Separating ASP.NET Core 2.1 from class library of Entity Framework

545 Views Asked by At

When you read this question, you think it is a repeated question and that I did not do enough search for finding the solution of this issue. Unfortunately, I spent many hours searching for the solution for this issue. I am developing an ASP.NET Core 2.1 application, that consists mainly from ASP.NET Web APP and Entity Framework Core.

I am using the code first approach for adding migrations and updating database, and everything looks working fine, until I separated the asp.net core web app from the Entity Framework Core. Actually, I put the EntityFrameworkCore in separated class library. When I tried to add new migration using

dotnet ef migrations add InitialCreate

I had this error

An error occurred while accessing the IWebHost on class 'Program'. Continuing without the application service provider. Error: Could not load type 'EF.EFCore.ApplicationDbContext' from assembly 'ef, Version=2.1.4.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. System.TypeLoadException: Could not load type 'EF.EFCore.ApplicationDbContext' from assembly 'EF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. at System.Reflection.CustomAttribute._CreateCaObject(RuntimeModule pModule, IRuntimeMethodInfo pCtor, Byte** ppBlob, Byte* pEndBlob, Int32* pcNamedArgs) at System.Reflection.CustomAttribute.CreateCaObject(RuntimeModule module, IRuntimeMethodInfo ctor, IntPtr& blob, IntPtr blobEnd, Int32& namedArgs) at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType, Boolean mustBeInheritable, IList derivedAttributes) at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeType type, RuntimeType caType, Boolean inherit) at System.Attribute.GetCustomAttributes(MemberInfo element, Type type, Boolean inherit) at System.Attribute.GetCustomAttribute(MemberInfo element, Type attributeType, Boolean inherit) at System.Reflection.CustomAttributeExtensions.GetCustomAttribute[T](MemberInfo element) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c.b__12_5(TypeInfo t) at System.Linq.Enumerable.WhereSelectListIterator2.MoveNext() at System.Linq.Enumerable.WhereEnumerableIterator1.MoveNext() at System.Linq.Enumerable.ConcatIterator1.MoveNext() at System.Linq.Enumerable.DistinctIterator1.MoveNext() at System.Linq.Enumerable.WhereEnumerableIterator1.MoveNext() at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.FindContextTypes() at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.FindContextType(String name) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType) at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_1.<.ctor>b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_01.b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action) Could not load type 'EF.EFCore.ApplicationDbContext' from assembly 'EF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

I am sure the problem is related to separation of the project, into component form

services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(conString,builder => builder.MigrationsAssembly(typeof(Startup).Assembly.FullName)));

the above code is the code I am using for my ApplicationDBContext class that derived form IdentityContext, either add or remove MigrationAssembly this does not make a different. Also, adding IDbContextFactory does not make a big deal I changed the ApplicationDbContext, that is derived from IdentityContext to the following

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    // Entity
    string conString = "Server=(local); Database=OnlineStoreDB;User Id=sa;Password=123@asu;";

    optionsBuilder.UseSqlServer(conString, x => x.MigrationsAssembly("EF"));

    base.OnConfiguring(optionsBuilder);
    // base.OnConfiguring(optionsBuilder);
    //if (!optionsBuilder.IsConfigured)
    //{
    //    optionsBuilder.UseSqlServer(conString);
    //}
    //else
    //{
    //    optionsBuilder.UseSqlServer(conString);
    //}

}
1

There are 1 best solutions below

0
On

Our approach was to create a small helper-classlibrary with the following content:

public class ApiDbContextMigrationsFactory : IDesignTimeDbContextFactory<ApiDbContext>
{
    public ApiDbContext CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder<ApiDbContext>();
        optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Api.Local.Migration;Trusted_Connection=True;ConnectRetryCount=0",
            b => b.MigrationsAssembly(typeof(ApiDbContext).Assembly.FullName));

        return new ApiDbContext(optionsBuilder.Options);

    }
}

And then we create the migration from inside the HelperForMigrations-Library-Folder with the following command:

dotnet ef migrations add nameofMigration --startup-project ./ --project ../ApiDbContextProject --context ApiDbContext