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.
Related
I started a new class library project and I want to use Dependency Injection for services and DbContext, etc.
However there is no Program.cs file.
Where should I configure the DI interfaces and classes? Do I need to add an empty Program.cs?
for example, if you have a class library as a business access layer. you can add a class in the root with the name DependencyInjection as the following
public static class DependencyInjection
{
public static void AddApplication(this IServiceCollection service)
{
service.AddScoped<IOrgSettingsService, OrgSettingsService>();
service.AddScoped<IIdentity, IdentityService>();
service.AddScoped<ILdapAuthenticationService, LdapAuthenticationService>();
service.AddScoped<IOrgAuthenticationService, OrgAuthenticationService>();
service.AddScoped<IVacanciesService, VacancyService>();
// assemblers
service.AddScoped<IVacancyAssembler, VacancyAssembler>();
}
}
and register it in startup class as the following
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddApplication();
}
dependency injection used for whole application.Main application injects services to all assemblies. for example, dbcontext inject from main application to your assembly.You should not define dependency instance for each assembly separately and locally
In my Asp.net Core 5 API Project
I have a serviceLayer that the controller uses, to get data from a third layer called dataLayer.
I want to use the service layer as a DLL in different projects.
This ServiceLayer Contain dependency Injections like that :
namespace ServiceLayer
{
public class UserService : IUserService
{
IUserRepository userRepository; // (From DataLayer)
public UserService(IUserRepository repository) : base(repository)
{
this.userRepository = repository;
}
public Users GetAllPersonsById(int id)
{
return userRepository.GetById(id);
}
}
public interface IUserService : IService<Users>
{
Users GetAllPersonsById(int id);
}
How can I use the method GetAllPersonsById with the DLL ServiceLayer
can I use it because the dependency Injections
As soon as you reference the DLL / project you can use all classes the same ways as if they were in the project.
To use a class as a service:
Provide the service
Inject the service
There's a lot of documentation available, so I'll keep this short:
// provide in startup.cs
services.AddTransient<IUserService, UserService>();
// Inject where you need it
MyConstructor(IUserService userService) {}
See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0
Provide Extension Method
If we take a look at other libs, most of them provide a method to setup the services.
Example: Entity framework core
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDbContext>(options => options.UseSqlServer(...));
}
So you could:
In your lib, create an extension method for IServicesCollection that adds all services of your lib.
In the consuming project, call services.AddMyLibServices().
This could look like so:
public static class ServicesConfiguration
{
public static void AddDataLayer(this IServiceCollection services)
{
services.AddTransient<IUserService, UserService>();
// ... same for all services of your lib
}
}
Here's a tutorial with more details:
https://dotnetcoretutorials.com/2017/01/24/servicecollection-extension-pattern/
Lamar service registries
An optional and alternative approach are service registries. It's very similar to the extension methods but uses a class to do the setup. See https://jasperfx.github.io/lamar/documentation/ioc/registration/registry-dsl/
Composition Root
You may want to read about the composition root pattern, e.g. What is a composition root in the context of dependency injection?
In a simple app, your startup.cs is your composition root. In more complex apps, you could create a separate project to have a single place to configure your apps services.
Create the DLL
There are two ways to create the DLL:
As a project in your solution (so your solution has multiple projects, each will result in a separate DLL)
As a separate solution and as nuget package
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!!!
I have a solution that has the following projects
Acme.Core
Acme.Domain
Acme.Repositories
Acme.Services
Acme.Web
In the past I've used Unity for DI in full framework projects. I was able to register concrete objects to interface mappings in executable projects (web apps, console app, test apps).
I'm trying to implement the same approach with .NET Core. I wanted to first try using the Microsoft.Extensions.DependencyInjection library. Within the ASP.NET Core application it works great. Unfortunately I've run into an issue when I try to share/reference that instance with the registions to other projects, such as a .NET Standard library.
My idea was to inject the ServiceProvider into the constructor of the service:
public class AddressService : BaseService, IAddressService
{
private readonly IServiceProvider _serviceProvider;
public AddressService(IServiceProvider serviceProvider, string userOrProcessName)
{
_serviceProvider = serviceProvider;
}
public IReadOnlyList<IState> GetAllStates()
{
_serviceProvider.GetService<IAddressRepository>();
// other logic removed
}
}
I tried the following inside the Startup.ConfigureServices():
services.AddTransient<IAddressService>(s => new AddressService(HttpContext.RequestServices, Environment.UserName));
The issue I ran into is that I cannot reference HttpContext.RequestServices outside of a Controller. I haven't been able to figure another way of passing the ServiceProvider instance.
My questions:
How do pass a reference for the current ServiceProvider?
Is there a better design to accomplish my goal sharing the configuration of Microsoft.Extensions.DependencyInjection in multiple libraries?
Prevent injecting IServiceProvider into your application components; that leads to the Service Locator anti-pattern.
Instead, you should build up application components solely using Constructor Injection. This means that your AddressService should require IAddressRepository as constructor argument, not IServiceProvider. For instance:
public class AddressService : IAddressService
{
private readonly IAddressRepository repo;
public AddressService(IAddressRepository repo, IUserContext userContext)
{
this.repo = repo;
}
public IReadOnlyList<IState> GetAllStates()
{
// other logic removed
}
}
Also try to prevent injecting primites into your constructors. It's not a bad practice per se, but it does complicate object graph construction. Instead, either wrap the value into a class, in case its a configuration value, or hide it behind an abstraction (as shown above) in case it's a runtime value.
Both practices simplify both your application code and the Composition Root.
For instance, this will be the result of the previous AddressService redesign:
services.AddTransient<IAddressRepository, SqlAddressRepository>();
services.AddTransient<IAddressService, AddressService>();
services.AddScoped<IUserContext, UserContext>();
services.AddHttpContextAccessor();
Here, UserContext could be defined as follows:
public class UserContext : IUserContext
{
private readonly IHttpContextAccessor accessor;
public UserContext(IHttpContextAccessor accessor) => this.accessor = accessor;
public string UserName => this.accessor.HttpContext.User.Identity.Name;
}
In order to share configuration across multiple projects, you can put the configuration into a shared assembly, and register (not resolve) them in there. Many dependency injection libraries offer that functionality. e.g.
in Autofac you create a module (https://autofaccn.readthedocs.io/en/latest/configuration/modules.html) that takes a container builder to configure:
protected override void Load(ContainerBuilder builder) { ... }
SimpleInjector provides packages: https://simpleinjector.readthedocs.io/en/latest/howto.html#package-registrations
Unity can support something similar: Can I register my types in modules in Unity like I can in Autofac?
Ninject has a similar module feature: What is the intention of Ninject modules?
A similar feature has be created for Microsoft.Extensions.DependencyInjection: https://github.com/aruss/DotNetCore_ModularApplication
At a high level, you create a method that receives the DI container and adds your registrations to that container. If your DI framework doesn't provide hooks you need to manually call the method yourself, but the general concept doesn't change.
Splitting registrations into modules allows you to easily group similar sets of functionality while maintaining the flexibility of incorporating different sets of functionality into different projects. You could of course create a single shared assembly that registered the union of all dependencies for all projects, but that would carry around unnecessary baggage and result in a less reusable implementation.
The key point as Steven points out is that you configure the container and let it inject the dependencies rather than looking from the inside out for the dependencies.
Say I've a MVC Core Controller like this:
public class SomeController
{
public SomeController(IConfiguration appConfig, Func<string> someDelegate)
{
}
}
Also, I'm using AutoFac to resolve injections. Object injections are working flawlessly while adding a delegate injection produces an ASP.NET Core exception which tells that Func<string> can't be injected because there's no component to inject with such type.
When I try to manually resolve SomeController using AutoFac I get the desired behavior.
Is there any way to support this scenario without using AutoFac to resolve controllers?
Controllers are not resolved via DI by default, they are constructed in the DefaultControllerFactory or so.
Update
Microsoft.Extensions.DependencyInjection doesn't support named components, discovery, auto registrations, decorators etc.
It's meant to be simple out of the box IoC and provide the base for DI for basic applications and offer easy way for 3rd party IoC containers (with advanced features such as auto discovery, decorators etc.) to be integrated (basically all they need is process the information in IServiceCollection and return their own implementation of IServiceProvider from Configure method).
Tag helpers, controllers and view components are different in this aspect as they have their own activators (the default one use activation utilities, which at some point further down the pipeline use the service provider). For that reasons AddControllersAsServices exists, because it replaces DefaultControllerActivator (which uses ActivationUtilities, see DefaultControllerActivator.cs) with ServiceBasedActivator (which uses IServiceProvider, see ServiceBasedControllerActivator).
Also see this related answer for details on how to resolve controllers, tag helpers and view components via DI.
var builder = services
.AddMvc()
.AddControllersAsServices() // this one for your case
.AddViewComponentsAsServices()
.AddTagHelpersAsServices();
I was just run into this issue myself so I thought I would share for future reference as I had one case where I wanted to resolve a delegate but including an additional library seemed like overkill.
Given the following defintions:
public interface ISomething { /*...*/ };
public interface ISomeService { /*...*/ }
public class SomeService : ISomeService { /*...*/ }
public class Something
{
public Something(ISomeService service, string key) { /*...*/ }
}
// I prefer using a delegate for readability but you
// don't have to use one
public delegate ISomething CreateSomething(string key);
The delegate can be registered like this:
var builder = services
.AddSingleton<ISomeService, SomeService>()
.AddTrasient<CreateSomething>(provider => key => new Something(provider.GetRequiredService<ISomeService>(), key));