Optimal way of declaring DI objects - c#

I've got a .net API and my Program.cs has started to become quite bloated with the following:
.
.
.
//core mappers
builder.Services.AddSingleton<IAppData_Mapper, AppData_Mapper>();
builder.Services.AddSingleton<IUserData_Mapper, UserData_Mapper>();
//pylon export services
builder.Services.AddTransient<IPylonItemExportService, PylonItemExportService>();
builder.Services.AddTransient<IPylonContactExportService, PylonContactExportService>();
//pylon repositories
builder.Services.AddSingleton<IPylonContactRepository, PylonContactRepository>();
builder.Services.AddSingleton<IPylonConnectionRepository, PylonConnectionRepository>();
builder.Services.AddSingleton<IPylonItemRepository, PylonItemRepository>();
builder.Services.AddSingleton<IPylonContactExportRepository, PylonContactExportRepository>();
builder.Services.AddSingleton<IPylonItemExportRepository, PylonItemExportRepository>();
builder.Services.AddSingleton<IPylonDocumentRepository, PylonDocumentRepository>();
builder.Services.AddSingleton<IPylonCentLineRepository, PylonCentLineRepository>();
builder.Services.AddSingleton<IPylonComEntryRepository, PylonComEntryRepository>();
builder.Services.AddSingleton<IPylonSupplierRepository, PylonSupplierRepository>();
builder.Services.AddSingleton<IPylonCustomerRepository, PylonCustomerRepository>();
//pylon sync services
builder.Services.AddTransient<IPylonItemSyncService, PylonItemSyncService>();
builder.Services.AddTransient<IPylonContactSyncService, PylonContactSyncService>();
builder.Services.AddTransient<IPylonMeasurementunitSyncService, PylonMeasurementunitSyncService>();
builder.Services.AddTransient<IPylonDocEntrySyncService, PylonDocEntrySyncService>();
builder.Services.AddTransient<IPylonCentLineSyncService, PylonCentLineSyncService>();
builder.Services.AddTransient<IPylonCommEntrySyncService, PylonCommEntrySyncService>();
builder.Services.AddTransient<IPylonCustomerSyncService, PylonCustomerSyncService>();
builder.Services.AddTransient<IPylonSupplierSyncService, PylonSupplierSyncService>();
.
.
.
What would be the optimal way to move these outside of my program.cs? Ideally i'd like for them to be in a seperate class that will be called via the Program.cs
Can I pass the builder to a static method that will add the services?
Can I create the array of services and do something like Services.AddRange?
I'm fairly new to the DI architecture on .net and any guidelines would be grately appreciated!

To answer your first question you can move the service registration to another class by creating a new class and having the method take in the builder and register services then return or create an extension method. Creating an extension method is slightly "neater" and you can do it like so.
public static class MyServiceExtension
{
public static IServiceCollection AddMyServices(this IServiceCollection services)
{
// add your services
return services;
}
}
Now in your Program.cs all you'll do is.
builder.Services.AddMyServices();

Related

How to Register Multiple Services, Multiple implementation in separate class and call it in ConfigureServices method?

Traditionally, we register multiple services, multiple interfaces under ConfigureServices method in the Startup class. This is feasible if we have five or ten registrations. But what if we have fifty or more such registrations?
public void ConfigureServices(IServiceCollection services) {
service.AddTransient<ISQLDB, SQLDB>();
service.AddTransient<IEmployeeBusiness, EmployeeBusiness>();
service.AddTransient<IEmployeeRepository, EmployeeRepository>();
service.AddTransient<IEmployeeValidation, EmployeeValidation>();
service.AddTransient<IDepartmentBusiness, DepartmentBusiness>();
service.AddTransient<IDepartmentRepository, EmployeeRepository>();
service.AddTransient<IDepartmentValidation, EmployeeValidation>();
...
...
...
// some 50 or more
}
I want to move the registering part to another custom InjectDependency class and call this in ConfigureServices method like:
public class InjectDependency{
public InjectDependency(IServiceCollection service)
{
service.AddTransient<ISQLDB, SQLDB>();
service.AddTransient<IEmployeeBusiness, EmployeeBusiness>();
service.AddTransient<IEmployeeRepository, EmployeeRepository>();
service.AddTransient<IEmployeeValidation, EmployeeValidation>();
service.AddTransient<IDepartmentBusiness, DepartmentBusiness>();
service.AddTransient<IDepartmentRepository, EmployeeRepository>();
service.AddTransient<IDepartmentValidation, EmployeeValidation>();
...
...
...
...
}
}
Is there any way to achieve this?
Your code should work fine as is, though there are a couple of improvements you could make.
First, your InjectDependency() constructor is essentially stateless, so it would make more sense as a static method rather than a constructor. Second, to take that one step further, you could set it up as an extension method off of the IServiceCollection interface, which is a really common approach to this scenario:
public class ServiceCollectionExtensions {
public static IServiceCollection AddBusinessLogic(this IServiceCollection services) {
services.AddTransient<ISQLDB, SQLDB>();
services.AddTransient<IEmployeeBusiness, EmployeeBusiness>();
services.AddTransient<IEmployeeRepository, EmployeeRepository>();
…
return services;
}
}
Then, in your Startup class, you'd simply call this like:
public void ConfigureServices(IServiceCollection services) {
services.AddBusinessLogic();
}
If you have that many implementations, however, you might also try to determine if there's a common pattern or convention you can use to dynamically register them. For example, in your sample data, a lot of your implementations share the same base identifier as the interface. If that pattern holds, it might be easier to write code that automates that. There's a good example of this on the question Built-in dependency injection with conventions.

automatically inject services net core

I am doing a project in .net core
and always adding Interfaces and Services implement that Interfaces
public interface IDBContainer{
...
}
public class DBContainer : IDBContainer{
...
}
and i inject them in the startup
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IDBContainer, DBContainer>();
}
or using extension method adding them
public static IServiceCollection AddInfrastructure(this IServiceCollection services)
{
services.AddTransient<IDBContainer, DBContainer>();
return services;
}
and in startup
[..]
services.AddInfrastructure();
but that is the problem i has to inject each one myself as interface and service
in the extension method or in the startup class
is there away to add the interface and implementation for it automatically. and there is another thing the interfaces and class is in another project assembly in the same solution???
and there is no problem to use other library if it can do it like AutoFac or something
Have you tried https://github.com/khellang/Scrutor ?
As far as I know AutoFac can also be used with some extra work documented here https://autofaccn.readthedocs.io/en/latest/integration/aspnetcore.html
While I personally prefer EXPLICIT IoC registrations.
Here is a "autoscan" library.
NetCore.AutoRegisterDi
https://www.nuget.org/packages/NetCore.AutoRegisterDi/
https://www.thereformedprogrammer.net/asp-net-core-fast-and-automatic-dependency-injection-setup/
How to NetCore.AutoRegisterDi works The NetCore.AutoRegisterDi library
is very simple – it will scan an assembly, or a collection of
assemblies to find classes that a) are simple classes (not generic,
not abstract, not nested) that have interfaces and b) have an
interface(s). It will then register each class with its interfaces
with the NET Core DI provider.

Is there a robust way to register dependencies in ASP.NET Core 3.1 beside adding everything into Startup class?

I have an ASP.NET Core 3.1 project. Typically, I register any dependency using the ConfigureServices() method in the Startup.cs class.
But, I find myself having to register lots of dependencies and the ConfigureServices() looks huge! I know I can probably create an extension method of a static method and call it from the ConfigureService()` class, but wondering if there is a better way.
If there a way to register dependencies in the IoC container without having to define them one at a time like this
services.AddScoped<Interface, Class>();
.... 200 lines later
services.AddScoped<ISettings, Settings>()
Grouping related dependencies into custom extension methods is a very common way to do this. ASP.NET Core already does this for many of the internal services, and you can easily expand on top of that and set them up the way you need for your application. For example to set up authentication and authorization:
public IServiceCollection AddSecurity(this IServiceCollection services)
{
services.AddAuthentication()
.AddCookie();
service.AddAuthorization(options =>
{
options.DefaultPolicy = …;
});
return services;
}
You can do the same for your application-specific services and group them logically in separate extension methods.
If you have a lot of service registrations that are very similar, you can also employ a convention-based registration e.g. using Scrutor. For example, this registers all services within a certain namespace as transient for their respective interface:
services.Scan(scan => scan
.FromAssemblyOf<Startup>()
.AddClasses(c => c.InNamespaces("MyApp.Services"))
.AsImplementedInterfaces()
.WithTransientLifetime()
);
Scrutor allows for very complex rules to scan for services, so if your services do follow some pattern, you will likely be able to come up with a rule for that.
Create a custom attribute (called AutoBindAttribute)
public class AutoBindAttribute : Attribute
{
}
Use it like bellow (Decorate all the implementations that you want to automatically bind with [AutroBind])
public interface IMyClass {}
[AutoBind]
public class MyClass : IMyClass {}
Now create an extention method for IServiceCollection
public static class ServiceCollectionExtensions
{
public static void AutoBind(this IServiceCollection source, params Assembly[] assemblies)
{
source.Scan(scan => scan.FromAssemblies(assemblies)
.AddClasses(classes => classes.WithAttribute<AutoBindAttribute>())
.AsImplementedInterfaces()
.WithTransientLifetime();
}
}
Now call it in Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AutoBind(typeof(Startup).Assembly);
}
}
Note: You can improve the ServiceCollectionExtentions class to support all scopes such as singleton, etc. This example shows only for Transient lifetime.
Enjoy!!!

.NET Core 2.0 Modular Dependency Injection

I am trying to build a library that has core and extensions packages like Entity Framework and its database providers.
What I am trying to do is when I register that library with dependency injection, I want to give specific implementation as a parameter.
Think EF. In order to use sql provider on EF we need to register it with SQL provider passed as option parameter like the following.
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration["ConnectionString"]);
});
I would like to build similar structure. Lets say my framework will provide film producer. It will have producer.core package for framework related classes and two extensions package called Producer.Extensions.Hollywood and Producer.Extensions.Bollywood.
If I want to use Hollywood provider, I need to install core package and Hollywood extension package. On registration it should look like
services.AddFilmProducer(options =>
{
options.UseHollywoodProducer();
});
I could not find even a keyword that will point me a direction. I tried to read entity framework's source code but it is too complicated for my case.
Is there anyone who could point me a direction?
Thanks in advance.
I'm not sure if I completely understand your requirements, but DI and extensions are an easy thing in .net core.
Let's say you want this in your Startup.cs
services.AddFilmProducer(options =>
{
options.UseHollywoodProducer();
});
To implements this, create your library and add a static extension class
public static class FilmProducerServiceExtensions
{
public static IServiceCollection AddFilmProducer(this IServiceCollection services, Action<ProducerOptions> options)
{
// Create your delegate
var producerOptions = new ProducerOptions();
options(producerOptions);
// Do additional service initialization
return services;
}
}
where your ProducerOptions implementation might look like
public class ProducerOptions
{
public void UseHollywoodProducer()
{
// Initialize hollywood
}
public void UseBollywoodProducer()
{
// Initialize bollywood
}
}
If you wish to use the passed ProducerOptions in your service, there are two ways to do it. Either use dependency injection again, or directly access the service by using service provider in your extension method
var serviceProvider = services.BuildServiceProvider()
IYourService service = sp.GetService<IYourService>();
And now you have the original Use piece of initialization working.
Hope it helps.
Edit:
To clarify. To inject your options in the service, you can use
services.Configure(ProducerOptions);
in your extension method, and pass to your service constructor via
public YourService(IOptions<ProducerOptions>)
You can then simplify or complicate your options as much as you want.
A useful link for this kind of extensions might be the CORS repository for .net core: https://github.com/aspnet/CORS
Edit after comments:
I think I've got it now. You want packages to extend and implement specific options, kind of like what serilog does with different sinks. Piece of cake.
Scrap the ProducerOptions implementation.
Lets say you have a base package with initial empty structures (BaseProducer library) and an interface
public interface IProducerOptions
{
// base method signatures
}
Your service extension now becomes
public static class FilmProducerServiceExtensions
{
public static IServiceCollection AddFilmProducer(this IServiceCollection services, Action<IProducerOptions> options)
{
// Do additional service initialization
return services;
}
}
Now you create a new package with specific "Hollywood producer" options and you want to extend the base option set
public static class HollyWoodExtensions
{
public static void UseHollywoodProducer(this IProducerOptions options)
{
// Add implementation
}
}
Create as many packages and IProducerOptions extensions as you like, and the added methods will start appearing in your Startup.cs
services.AddFilmProducer(options =>
{
options.UseHollywoodProducer();
});

Application startup code in ASP.NET Core

Reading over the documentation for ASP.NET Core, there are two methods singled out for Startup: Configure and ConfigureServices.
Neither of these seemed like a good place to put custom code that I would like to run at startup. Perhaps I want to add a custom field to my DB if it doesn't exist, check for a specific file, seed some data into my database, etc. Code that I want to run once, just at app start.
Is there a preferred/recommended approach for going about doing this?
I agree with the OP.
My scenario is that I want to register a microservice with a service registry but have no way of knowing what the endpoint is until the microservice is running.
I feel that both the Configure and ConfigureServices methods are not ideal because neither were designed to carry out this kind of processing.
Another scenario would be wanting to warm up the caches, which again is something we might want to do.
There are several alternatives to the accepted answer:
Create another application which carries out the updates outside of your website, such as a deployment tool, which applies the database updates programmatically before starting the website
In your Startup class, use a static constructor to ensure the website is ready to be started
Update
The best thing to do in my opinion is to use the IApplicationLifetime interface like so:
public class Startup
{
public void Configure(IApplicationLifetime lifetime)
{
lifetime.ApplicationStarted.Register(OnApplicationStarted);
}
public void OnApplicationStarted()
{
// Carry out your initialisation.
}
}
This can be done by creating an IHostedService implementation and registering it using IServiceCollection.AddHostedService<>() in ConfigureServices() in your startup class.
Example
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
public class MyInitializer : IHostedService
{
public Task StartAsync(CancellationToken cancellationToken)
{
// Do your startup work here
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
// We have to implement this method too, because it is in the interface
return Task.CompletedTask;
}
}
using Microsoft.Extensions.DependencyInjection;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHostedService<MyInitializer>();
}
}
Notes
The main application will not be started until after your code has finished executing.
Constructor dependency injection is available to the IHostedService implementation.
I can recommend this blog post for more info, and an example of how to use async: https://andrewlock.net/running-async-tasks-on-app-startup-in-asp-net-core-3/
For more background reading, see this discussion: https://github.com/dotnet/aspnetcore/issues/10137
Basically there are two entry points for such custom code at startup time.
1.) Main method
As a ASP.NET Core application has got the good old Main method as entry point you could place code before the ASP.NET Core startup stuff, like
public class Program
{
public static void Main(string[] args)
{
// call custom startup logic here
AppInitializer.Startup();
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
2.) Use your Startup class
As you already stated in your question is the Configure and ConfigureServices a good place for your custom code.
I would prefer the Startup class. From the runtime perspective it does not matter, if the call is called in startup or somewhere else before the host.Run() call. But from a programmer's point of view who is accustomed to the ASP.NET framework then his first look for such logic would be the Startup.cs file. All samples and templates put there the logic for Identity, Entity Framework initialization and so on. So as a convention I recommend to place the initialization stuff there.

Categories