The Entity Framework provider type 'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer' registered in the application config file for the ADO.NET providerwith invariant name 'System.Data.SqlClient' could not be loaded. Make sure that the assembly-qualified name is used and that the assembly is available to the running application.See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.
As usual, the link provided minimal assistance. With a little prodding, I found a workaround for the issue.
The goal of this post is to make as few modifications to the code base as possible, to make the EF5 to EF6 upgrade. Sure, there are some differences between EF5 and EF6 implementation, but we're ignoring that for now. EF6 does not require data provider configurations in the App.config file. The new ProviderService types, embedded in the System.Data.Entity.(ProviderName) namespace does this for us. But, these are the objects giving us trouble. First things first...
Fixing the SqlProviderServices Issue
STEP 1: Comment out the existing Entity Framework element, and replace it with the new, EF6 version. You'll notice my project is also using the SQL Server Compact Edition (SQL CE or SqlCE) provider, and the default connection factory is configured. These may also be removed; the application programmatically updates the DefaultConnectionFactory and AppDomain default connection string, after dynamically generating the secure connection string (more on this, later):<entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework"> <parameters> <parameter value="System.Data.SqlServerCe.4.0" /> </parameters> </defaultConnectionFactory> <providers> <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> <provider invariantName="System.Data.SqlServerCe.4.0" type="System.Data.Entity.SqlServerCompact.SqlCeProviderServices, EntityFramework.SqlServerCompact" /> </providers> </entityFramework><section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
STEP 2: If you're reading this post, you've probably already done step 1 and things still aren't working. There's another step! Past experience with these types of issues taught me that sometimes things need a little priming, before they work properly. If you don't already have one, create a static constructor in your DBContext derivative class. The EF6 providers must be called, before instantiating a DBContext derivative class. The first constructor to be called is generally the static constructor.
static MyDbContext() { // EF 6.0.1 throws an exception, unless we first probe the provider types. var type1 = typeof(System.Data.Entity.SqlServer.SqlProviderServices); var type2 = typeof(System.Data.Entity.SqlServerCompact.SqlCeProviderServices); ... }
This immediately resolved the issue. However, I heard my inner software craftsman shouting me that ALL of the constructors should call these lines of code, and should adhere to the DRY Principle. So, how do we call a common initialization method from both the static and instance constructors?
Of course, if you already have redirected your initializer to a custom method, simply add the type probes to your initialize method.
public class LocalDbContext : DbContext, ILocalDbContext { private bool _isInitialized = false; // Be sure to call Initialize from the instance constructors! private LocalDbContext() : base() { Initialize(); } static MyDbContext() { // The following replaces the original "Database.SetInitializer<MyDbContext>(strategy);". var strategy = new MyDbContextInitializer(); var init = strategy as IDatabaseInitializer<MyDbContext>; Database.SetInitializer<MyDbContext>(strategy); } protected internal void Initialize() { if (!m_isInitialized) { _isInitialized = true; // EF 6.0.1 throws an exception, unless we first probe the provider types. var type1 = typeof(System.Data.Entity.SqlServer.SqlProviderServices); var type2 = typeof(System.Data.Entity.SqlServerCompact.SqlCeProviderServices); } }
Now, we have a workaround that functions from every constructor of the DbContext derivative, with minimal impact to existing code.
Actually the issue appears to be with the TestRunner. I found that any tests that used the [DeploymentItem] attribute would fail. This can be addressed by referencing System.Data.Entity.SqlServer.SqlProviderServices.Instance in the test assembly or by specifying the EntityFramework.SqlServer assembly as a deployment item. For more info see: http://entityframework.codeplex.com/workitem/1590
ReplyDeleteStep 1 Fixed my problem!
ReplyDeleteThanks Mike.
Neeraj
The type or namespace name 'SqlServerCompact' does not exist in the namespace 'System.Data.Entity' (are you missing an assembly reference?)
ReplyDeleteAll assemblies are referenced
Thanks! Step 1 fixed the problem for me as well!
ReplyDeleteThanks million
ReplyDeleteyour code (Step2) really solved my EF6 init error