asp.net 5 dependency injection in multiple projects
K

4

10

I've got an ASP.NET 5 dnxcore solution with some projects to separate my logic:

  • API
  • Core (with services for business logic)
  • DAL (repository interfaces)
  • Entity Framework (the repositories implementations)

Now I use DI to call my services in the constructors of my API controllers:

private readonly IMyService _myService;
public Controller(IMyService myservice){ _myService = myService; }

The services in my core get the repository thru constructor injection too:

private readonly IMyRepository _myRepo;
public MyService(IMyRepository myRepo){ _myRepo = myRepo; }

Currently I need to define my DI container in the startup class of my API to make it work.

My question is, how can I put the 'building' of the DI container of the repositories in my services in my Core-project. This way, my API is loosely coupled of the fact that my services use Entity Framework, so I can change to, for example, mongodb without changing my API project.

Kurus answered 24/1, 2016 at 0:33 Comment(0)
B
8

My question is, how can I put the 'building' of the DI container of the repositories in my services in my Core-project. This way, my API is loosely coupled of the fact that my services use Entity Framework, so I can change to, for example, mongodb without changing my API project.

You could, but you shouldn't do that.

Dependency Injection is the practice of making loosely-coupled classes throughout the libraries that can be plugged together (often in many ways).

However, each application should have a composition root, which is the one place in the application where we put the coupling code. Our first instinct as developers is to try to farm the coupling code off into its own library, but that is an urge that you should resist. See composition root reuse.

Mark Seeman's illustration sums it up well. Avoiding transitive dependencies is what is desired when using DI in order to flatten the dependency graph. This ensures assemblies can be used/tested in isolation without dragging along unnecessary dependencies, which in turn makes maintenance easier.

That said, many DI containers have a way to organize the configuration of certain parts of the application by using modules. In Autofac, the documentation for modules is here.

Bolden answered 24/1, 2016 at 9:56 Comment(1)
Do you have any example for new aspnet 5 dependency injection? Thanks.Shrewsbury
S
8

You can easily add an extension method of IServiceCollection into your services layer and use it to register its own dependencies. Then in the startup you just call the method on the service layer without having any reference to EntityFramework in your web app.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace your.service.layer
{
    public static class MyServiceCollectionExtensions
    {
        public static IServiceCollection AddMyServiceDependencies(this IServiceCollection services)
        {
            services.AddScoped<My.Data.Tier.DbContext, My.Data.Tier.DbContext>();
        }
    }

}

Startup:

using your.service.layer;

public void ConfigureServices(IServiceCollection services)
{
    services.AddMyServiceDependencies();
}

Now your web app only needs a reference to your service layer and it is not directly dependent on EntityFramework.

Sherillsherilyn answered 24/1, 2016 at 12:59 Comment(3)
Is this the best practice?Shrewsbury
Please, refer to the question I recently asked. With this approach, you would end up having the same problem as before: your Web project will have a reference to your.service.layer, and as your.service.layer will have a reference to specific implementations, by transitivity your Web project will reference your.service.layer.Tritium
yes there would be transitive dependency. Myself I put most of my code in class library projects so to me the main web app/console app is just the composition root for wiring up dependencies and configuration. I don't see it as a problem.Sherillsherilyn
A
1

As NightOwl888 have said, you should have a CompositionRoot in your application, the place where all your dependencies are set. What I did is this: 1. Create a Core Class Library named CompositionRoot. 2. Add a class to handle your dependencies:

public class DependencyMapper
{
    public static void SetDependencies(IServiceCollection serviceCollection, IConfigurationRoot configuration)
    {
        serviceCollection.AddEntityFramework()
                         .AddDbContext<SonoPeopleContext>(options =>
                                                        options.UseSqlServer(configuration["Data:DefaultConnection:ConnectionString"])
                                                        );            

        MapperConfiguration mapperConfiguration = new MapperConfiguration(cfg =>
        {
            cfg.AddProfile(new AutoMapperProfileConfiguration());
        });
        serviceCollection.AddSingleton<IMapper>(sp => mapperConfiguration.CreateMapper());

        serviceCollection.AddScoped<IUserService, UserService>();

    }
}

Then you reference your CompositionRoot in your MVC project and in your Startup.cs you just do

DependencyMapper.SetDependencies(services, Configuration); 

That's all.

Alysiaalyson answered 11/8, 2016 at 13:44 Comment(0)
H
0

See this question, I have the same problem because my application is DB agnostic and base on the request will need to switch between a document oriented database (noSQL) and transaccional database (SQL).

Honolulu answered 27/1, 2016 at 13:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.