0

So I'm trying to seperate concerns of my project and properly isolate layers. Therefore the layers I have are:

Web, Domain and Data

I've noticed from several answers on S/O that the best designs are especially when the data access is not known and is self contained in the data layer. Since with this approach I need to DI the DbContext in my Web project, however this exposes that the Data layer is using EntityFrameworkCore to the Web project like so:

Startup:

 public void ConfigureServices(IServiceCollection services)
 {
     services.AddDbContext<ApplicationDbContext>(option =>
         option.UseSqlServer(_configuration.GetConnectionString("Data")));
 }

Is there any way to just DI this in the Data project thus hiding what the Data layer is using from the Web project?

Dimitris Maragkos
  • 8,932
  • 2
  • 8
  • 26
KTOV
  • 559
  • 3
  • 14
  • 39
  • I believe your question has been answered before, [here](https://stackoverflow.com/questions/9501604/ioc-di-why-do-i-have-to-reference-all-layers-assemblies-in-applications-entry). If that q&a doesn't answer your question, please let me know. – Steven Sep 17 '22 at 11:38
  • @Steven This doesn't answer my question. The answers don't explore how to DI a DbContext outside of the `Startup` and only DI in the relevant layer, in this case the `Data` layer – KTOV Sep 17 '22 at 11:55
  • Those answers don't explore that, because you shouldn't do that. Registration and composition of components should be centralized in a single place in the application; a.k.a. the [Composition Root](https://freecontent.manning.com/dependency-injection-in-net-2nd-edition-understanding-the-composition-root/). As one of the answers explains your `ConfigureServices` method (and `Startup` class) is not part of the UI layer, but part of the Composition Root 'layer'. I urge you to re-read those answers again. – Steven Sep 17 '22 at 13:20
  • The solution, therefore, is to register your `DbContext` inside the `ConfigureServices` method (as all Microsoft-provided examples suggest). Yes, this causes a reference from your startup project to the data-access project, but this doesn't mean that your UI *layer* (that currently resided inside the same *assembly*) depend on the data-access layer. – Steven Sep 17 '22 at 13:22
  • So in short: Q: DI DbContext in data layer? A: Don't do it. Keep all registrations inside your Composition Root. – Steven Sep 17 '22 at 13:23
  • Create a Class Project for the dbContext to separate from the webcode. – jdweng Sep 17 '22 at 14:27

2 Answers2

1

I recommend you to add such Extension Method to the Data Layer

public static class ServiceExtensions
{
    public static void AddDataLayer(this IServiceCollection services,  IConfiguration configuration)
    {
        services.AddDbContext<ApplicationDbContext>(option =>
             option.UseSqlServer(configuration.GetConnectionString("Data")));
    }
}

and then call it in the Web Layer as follows

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataLayer(_configuration);
}

So you can hide EntityFrameworkCore existence from Web Layer.
The Web Layer already knows about the existence of the Data Layer. So you won't break anything.

giorgi02
  • 683
  • 6
  • 13
0

I believe you choose wrong approach and you cant DI in data layer. but for your final sentence (DI out side of main layer), we use db context in unit test project like this:

lock (_lock)
        {
            if (!_databaseInitialized)
            {
                using (var context = CreateContext())
                {
                    context.Database.EnsureDeleted();
                    context.Database.EnsureCreated();

                    context.AddRange(
                        new Blog { Name = "Blog1", Url = "http://blog1.com" },
                        new Blog { Name = "Blog2", Url = "http://blog2.com" });
                    context.SaveChanges();
                }

                _databaseInitialized = true;
            }
        }

again, this is wrong approach and its completely wrong. DI supply lots of feature that you should use them. plus i think you can use other lib for injecting services (not db context)

Amir
  • 26
  • 1
  • 4