https://blog.econduct.de/dotnet-core-dependency-injection-with-configuration-file/
.NET Core 2.0 has a build in dependency injection and it works well, but if you want to do it via configuration you have to hack around. So, my idea was to introduce a concept of modules that can be managed via configuration logic.
This idea is not new, I am big fan of Autofac and Autofac has the concept of modules.
A module is a small class that can be used to bundle up a set of related components behind a ‘facade’ to simplify configuration and deployment. The module exposes a deliberate, restricted set of configuration parameters that can vary independently of the components used to implement the module.
I could use Autofac with all its goodies, but I decided to extend the built in DI mechanism with module feature.
There are four files to enable this feature.
usingMicrosoft.AspNetCore.Builder;usingMicrosoft.Extensions.Configuration;usingMicrosoft.Extensions.DependencyInjection;publicinterfaceIModule{voidConfigureServices(IServiceCollectionservices,IConfigurationconfiguration);voidConfigure(IApplicationBuilderapp);}usingSystem.Collections.Generic;publicclassModulesOptions{publicList<ModuleOptions>Modules{get;set;}}publicclassModuleOptions{publicstringType{get;set;}}usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingMicrosoft.AspNetCore.Builder;usingMicrosoft.Extensions.Configuration;usingMicrosoft.Extensions.DependencyInjection;publicclassModulesStartup{privatereadonlyIEnumerable<IModule>_modules;privatereadonlyIConfiguration_configuration;publicModulesStartup(IConfigurationconfiguration){this._configuration=configuration??thrownewArgumentNullException(nameof(configuration));ModulesOptionsoptions=configuration.Get<ModulesOptions>();this._modules=options.Modules.Select(s =>{Typetype=Type.GetType(s.Type);if(type==null){thrownewTypeLoadException($"Cannot load type \"{s.Type}\"");}IModulemodule=(IModule)Activator.CreateInstance(type);returnmodule;});}publicvoidConfigureServices(IServiceCollectionservices){foreach(IModulemoduleinthis._modules){module.ConfigureServices(services,this._configuration);}}publicvoidConfigure(IApplicationBuilderapp){foreach(IModulemoduleinthis._modules){module.Configure(app);}}With this four classes you are ready to go.
Lets say you want to load the IEmailSender, that is a part of default .NET Core template, from a module. You will need to create a IEmailSender implementation, something like this.
usingSystem.Threading.Tasks;usingMicrosoft.Extensions.Logging;publicclassSomeFancyEmailSender:IEmailSender{privatereadonlyILogger<SomeFancyEmailSender>_logger;publicSomeFancyEmailSender(ILogger<SomeFancyEmailSender>logger){this._logger=logger;}publicasyncTaskSendEmailAsync(stringemail,stringsubject,stringmessage){// Call some fancy API here this._logger.LogInformation("SomeFancyEmailSender.SendEmailAsync...");}}And you will need a module class.
usingMicrosoft.AspNetCore.Builder;usingMicrosoft.Extensions.Configuration;usingMicrosoft.Extensions.DependencyInjection;publicclassSomeFancyEmailSenderModule:IModule{publicvoidConfigureServices(IServiceCollectionservices,IConfigurationconfiguration){services.AddScoped<IEmailSender,SomeFancyEmailSender>();}publicvoidConfigure(IApplicationBuilderapp){// Configure services }}To make it whole thing work you we need to integrate it in Startup.cs and appsettings.json files.
usingMicrosoft.AspNetCore.Builder;usingMicrosoft.AspNetCore.Hosting;usingMicrosoft.Extensions.Configuration;usingMicrosoft.Extensions.DependencyInjection;publicclassStartup{privatereadonlyModulesStartup_modules;publicStartup(IConfigurationconfiguration){this._modules=newModulesStartup(configuration);}publicvoidConfigureServices(IServiceCollectionservices){services.AddMvc();this._modules.ConfigureServices(services);}publicvoidConfigure(IApplicationBuilderapp,IHostingEnvironmentenv){app.UseMvcWithDefaultRoute();this._modules.Configure(app);}}{
"Modules": [
{ "Type": "SomeFancyModules.SomeFancyEmailSenderModule, SomeFancyModules" }
]
}You can find the code used in this post on GitHub