'Dotnet organizing dependency injection registration and project seperation

Have a project structure where I have a couple of layers

Api
Bll
Dal
Utility

When say a order request is received by the Api there is a couple of steps that we need to take. Like:

  • Validate the input
  • Save the customer
  • Save the order
  • Validate payment
  • Save final order status

All of these require different classes from the Bll And the classes inside the Bll requires classes from Dal and maybe other Bll or from Utility.

So now inside the Api I need to register the whole chain of what might be needed like

Register<IValidateService,ValidateService>()
Register<ICustomerService,CustomerService>()
Register<ICustomerDatabaseService,CustomerDatabaseService>()
Register<IUtilityService,UtilityService>();

Maybe all of the above just to get the CustomerService working, and then we need to do this for a lot more services and I will have to reference the Dal layer inside the Api layer. And in the long run I feel that everything will become really bloated. Would be good if I could just Register the CustomerService and then that will register it's dependencies by itself or something.

Maybe it is fine to have the entry level to be aware of everything?

Any ideas on how to solve this or am I overthinking things?

Thank you



Solution 1:[1]

My suggested solution for auto-registration is the following:

  • Use Autofac.
  • Create a public DependencyModule class derived from Autofac.Module in your Api, Bll, Dal and Utility projects.
  • Override the Load method and register only types that are in that project.
  • In your startup project (Api) use my nuget package to automatically discover and register all your DependencyModule classes into the DI container.

At the end you will have something like this:

  • Utility
    • DependencyModule.cs - registers all the utility types that need to be injected.
  • Dal
    • DependencyModule.cs - registers all the DAL types (e.g. DbContext) that need to be injected.
  • Bll
    • DependencyModule.cs - registers all the BLL types that need to be injected.
  • Api
    • DependencyModule.cs - registers all the API types (if any) that need to be injected. E.g. filters, etc.
    • In Program.cs or Startup.cs you register only my Autofac module that will discover and register all your modules above.

See my example solution's description and implementation.

This way each injectable type registration is done in its own assembly and dependent services do not need to worry about it.

Alternative solution - uses Microsoft DI

Instead of Autofac modules you can create extensions methods for IServiceCollection type in each of your project and register the types that are in that project.

Then in your Program.cs or Startup.cs just call each extensions method.

At the end you will have something like this:

  • Utility
    • IServiceCollectionExtensions.cs - registers all the utility types that need to be injected.
  • Dal
    • IServiceCollectionExtensions.cs - registers all the DAL types (e.g. DbContext) that need to be injected.
  • Bll
    • IServiceCollectionExtensions.cs - registers all the BLL types that need to be injected.
  • Api
    • IServiceCollectionExtensions.cs - registers all the API types (if any) that need to be injected. E.g. filters, etc.
    • In Program.cs or Startup.cs call each of the extensions methods.

Note

Actually you can combine MS DI with Autofac so that you can enjoy the advanced features of Autofac and use specific extension methods for IServiceCollection at the same time.

In that case you should know that the order of registrations is this:

  1. MS DI registrations: ConfigureServices() method
  2. Autofac registrations: ConfigureContainer<T>() method

All the MS DI registrations will be populated into the Autofac container.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1