Tomas
Tomas

Reputation: 18127

How to remove dependency from EntityFrameworkCore 3 in ASP.NET core 3.1

My EF-Core database access layer and ASP.NET Core application are in different projects. I am trying to wire-up Database access layer to Web application and come with code

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<DatabaseContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("Connection")));

    services.AddScoped<IMyDbContext, DatabaseContext>();
    services.AddScoped<IUserService, UserService>();
    services.AddScoped<IPlanService, PlanService>();

    services.AddControllersWithViews();
}

Unfortunately, this adds a dependency on the EntityFrameworkCore library. How to move DI wire-up outside Web application into the Database project?

I was using a similar approach in ASP.NET MVC(not Core) project with Unity DI, there was UnityContainerExtension class for that. My old example

DI wire-up in the database layer

 public class SharedUnityRegistry : UnityContainerExtension
    {
        private readonly Func<Type, LifetimeManager> _lifeTimeManager;

        public SharedUnityRegistry(Func<Type, LifetimeManager> lifetimeManager)
        {
            _lifeTimeManager = lifetimeManager;
        }

        protected override void Initialize()
        {
            Container.RegisterTypes(
                AllClasses.FromLoadedAssemblies().Where(type => typeof(DatabaseContext).IsAssignableFrom(type)),
                WithMappings.FromAllInterfaces,
                WithName.Default,
                _lifeTimeManager);            
        }
    }

DI Wire-up in ASP.NET web project, no dependency from EF

  UnityContainer.AddExtension(new SharedUnityRegistry(lifetimeManager => new HierarchicalLifetimeManager()));

Upvotes: 1

Views: 1538

Answers (2)

Philippe
Philippe

Reputation: 2029

In this project I've solved this issue like this:

  • Create interface IStartupRegistrator which is being called during application startup. This allows satellite assemblies to register their services, without having the need to decide in startup itself.
  • Implement EF data access layer which is NOT aware of the underlying DB
  • Create a dedicated data context (with migrations) for supported DBs. In my case MsSql, Sqlite and in memory (used for unit tests). The DB to use is being set in the app settings and each DB provider decides if it is him having to register himself; e.g. here

Note that only projects in the namespace Sppd.TeamTuner.Infrastructure.DataAccess reference EF core. For the record: I wasn't able to use asp.net identity, because of this.

Upvotes: 1

Maximilian Ast
Maximilian Ast

Reputation: 3499

You could use an extension method for this and place it in your database project. But you still need to have a reference to your database project.

Database project:

public static class Extensions
{
    public static IServiceCollection UseMyDatabase(this IServiceCollection services, string connectionString)
    {
        services.AddDbContext<DatabaseContext>(options => options.UseSqlServer(connectionString));
        return services;
    }
}

Startup.cs:

services.UseMyDatabase(Configuration.GetConnectionString("Connection"));

Upvotes: 2

Related Questions