I am using autofac in my web api to register log4net . It is working fine in controller but how can i use same log4net instance for common library project classes in same solution.
I have used below code for registering log4net using autofac in web api.
// IOC Container Setup uisng Autofac
var builder = new ContainerBuilder();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.Register(c => LogManager.GetLogger(typeof(Object))).As<ILog>();
builder.RegisterWebApiFilterProvider(config);
builder.RegisterModule<AMLWebApiModule>();
builder.RegisterFilterProvider();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
I am using logger as a property in common library project.
public ILog logger { get; set; }
when i tried to log message it is giving below exception.
Object reference not set to an instance of an object.
Please advise how can i use log4net in common library project.
So there are two approaches to make this work
1) Inject ILog in the class library project
2) Resolve the Ilog object in the class library project
I would go for option 1) and will register all my components in autofac to take full advantage of DI and keep each component independent.
Example Code,
Create a contract for the class library project example
public interface Ilibrary
{
string GetName();
}
public class Library : Ilibrary
{
private ILog _log;
public Library(ILog log)
{
_log = log;
}
public string GetName()
{
_log.Debug("log message");
return "test";
}
}
then either create a module in the class library project and register that module in your application start.
public class DomainModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterType<Library>()
.AsImplementedInterfaces()
.SingleInstance();
}
}
Or you can directly register too if you have access to the concert implementation just by doing this in your application start.
builder.RegisterType<Library>()
.AsImplementedInterfaces()
.SingleInstance();
Since you are using Logger as a property in your common library project, you can just decorate/annotate that property with [Dependency] attribute. This is called property injection. I am not sure if you have to have to do extra configuration for property injected dependencies in autofac but you can try if not you can search it.
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 .NET MVC 5 .NET Framework Application which I am converting to .NET Core 2.1
I have a custom action filter which in .NET Framework version was registered as a Global Filter in a Filterconfig class like below:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyCustomActionFilter());
}
}
Within the custom action filter in the .NET version I was using Service Locator pattern (I know it can be considered an anti pattern) as below:
var myService = DependencyResolver.Current.GetService<IMyService>();
I am using Simple Injector for DI and everything works fine in the .NET Version. With the .NET Core version I am trying to get the same functionality working but myService is always null
I am still using Simple Injector (as all the other projects in the solution use it and they are not getting move to .NET Core projects (only the web one is).
My Startup.cs class has this code:
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new MyCustomActionFilter());
});
SimpleInjectorConfig.IntegrateSimpleInjector(services, container);
At my service layer I have a SimpleInjector Registartion class that gets called from Web Layer - it then calls down to DAL Layer to do Registration
public class SimpleInjectorRegistration
{
public static void RegisterServices(Container container)
{
container.Register<IMyService, MyService>();
//further code removed for brevity
When I run the application with a breakpoint in the Custom Filter and a breakpoint in this RegisterServices method I can see the breakpoint in the RegisterServices method gets hit first and then the breakpoint in the Custom Filter - this made me think everything was wired up in the container correctly.
However I am trying to do the below again in the custom filter with .NET Core Service Locator pattern
var myService = filterContext.HttpContext.RequestServices.GetService<IMyService>();
but the result is always null?
Is there something I have missed in this setup?
------------ UPDATE -------------------
Based on Stevens comment I added a constructor to my action filter and passed in the Simple Injector container.
So My Startup class now is:
public class Startup
{
//Simple Injector container
private Container container = new Container();
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new MyCustomActionFilter(container));
My Custom filter now is like below with constructor added:
public class MyCustomActionFilter : ActionFilterAttribute
{
private readonly IMyService _myService;
public MyCustomActionFilter(Container container)
{
_myService = container.GetService<IMyService>();
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//actual code of custom filter removed - use of MyService
I set a breakpoint on the Constructor of MyCustomActionFilter and I can see it getting hit but I get an Error thrown:
SimpleInjector.ActivationException: 'The IDbContext is registered as 'Async Scoped' lifestyle, but the instance is requested outside the context of an active (Async Scoped) scope.'
MyService has a Dependency on the DbContext which is injected into it (it is doing work saving and retrieving data from DB.
For the DB Context I registered it as below:
public class SimpleInjectorRegistration
{
public static void RegisterServices(Container container, string connectionString)
{
container.Register<IDbContext>(() => new MyDbContext(connectionString),
Lifestyle.Scoped);
}
}
There are some significant changes between how to integrate Simple Injector in the old ASP.NET MVC and the new ASP.NET Core. In the old system, you would be able to replace the IDependencyResolver. ASP.NET Core, however, contains a completely different model, with its own internal DI Container. As it is impossible to replace that built-in container with Simple Injector, you will have the two containers run side-by-side. In that case the built-in container will resolve framework and third-party components, where Simple Injector will compose application components for you.
When you call HttpContext.RequestServices.GetService, you will be requesting the built-in container for a service, not Simple Injector. Adding the IMyService registration to the built-in container, as TanvirArjel's answer suggests, might seem to work at first, but that completely skips Simple Injector from the equation, which is obviously not an option, as you wish to use Simple Injector as your application container.
To mimic the Service Locator-like behavior you had before, you will have to inject the SimpleInjector.Container into your filter, as follows:
options.Filters.Add(new MyCustomActionFilter(container));
It would be an error, however, to call the container from within the constructor, as you are showing in your question:
public class MyCustomActionFilter : ActionFilterAttribute
{
private readonly IMyService _myService;
public MyCustomActionFilter(Container container)
{
_myService = container.GetService<IMyService>(); // NEVER DO THIS!!!
}
...
}
WARNING: You should never resolve from the container from the constructor. Or in more general: you should never use any injected dependency from inside the constructor. The constructor should only store the dependency.
As Mark Seemann explained, injection constructors should be simple. In this case, it even gets worse because:
During the time that the constructor of MyCustomActionFilter is invoked, there is no active scope, and IMyService can't be resolved
Even if IMyService could be resolved, MyCustomActionFilter is a Singleton and storing IMyService in a private field will cause a hidden Captive Dependency. This could lead to all sorts of trouble.
Instead of storing the resolved, IMyService dependency, you should store the Container dependency:
public class MyCustomActionFilter : ActionFilterAttribute
{
private readonly Container _container;
public MyCustomActionFilter(Container container)
{
_container = container;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
myService = container.GetService<IMyService>();
//actual code of custom filter removed - use of MyService
}
}
During the time that OnActionExecuting is called, there will be an active Simple Injector Scope, which will allows IMyService to be resolved. On top of that, as IMyService is not stored in a private field, it will not be cached and will not cause a Captive Dependency.
In your question you referred to the Service Locator anti-pattern. Whether or not the injection of the Container into your filter is in fact an implementation of the Service Locator anti-pattern depends on where the filter is located. As Mark Seemann puts it:
A DI container encapsulated in a Composition Root is not a Service Locator - it's an infrastructure component.
In other words, as long as the filter class is located inside your Composition Root, you are not applying the Service Locator anti-pattern. This does mean, however, that you must make sure that the filter itself contains as little interesting behavior as possible. That behavior should all be moved to the service that the filter resolves.
As #Steven points out, the built-in container will resolve framework and third-party components, where Simple Injector will compose application components for you. For built-in container, it could not resolve the service from simple injector. For simple injector, you could try EnableSimpleInjectorCrossWiring to resolve services from built-in container.
For options.Filters.Add, it also accepts MyCustomActionFilter instance, without resigering Container as depedence into MyCustomActionFilter, you could try register MyCustomActionFilter in sample injector, and then pass this instance to options.Filters.Add.
Register Services
private void InitializeContainer(IApplicationBuilder app)
{
// Add application presentation components:
container.RegisterMvcControllers(app);
container.RegisterMvcViewComponents(app);
// Add application services. For instance:
container.Register<IMyService, MyService>(Lifestyle.Scoped);
container.Register<MyCustomActionFilter>(Lifestyle.Scoped);
// Allow Simple Injector to resolve services from ASP.NET Core.
container.AutoCrossWireAspNetComponents(app);
}
add MyCustomActionFilter
services.Configure<MvcOptions>(options =>
{
using (AsyncScopedLifestyle.BeginScope(container))
{
options.Filters.Add(container.GetRequiredService<MyCustomActionFilter>());
}
});
#region SampleInjector
IntegrateSimpleInjector(services);
#endregion
Note If you specify container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();, you will need using (AsyncScopedLifestyle.BeginScope(container)) when you call container.GetRequiredService<MyCustomActionFilter>().
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.
How can I inject different implementation of object for a specific class?
For example, in Unity, I can define two implementations of IRepository
container.RegisterType<IRepository, TestSuiteRepositor("TestSuiteRepository");
container.RegisterType<IRepository, BaseRepository>();
and call the needed implementation
public BaselineManager([Dependency("TestSuiteRepository")]IRepository repository)
As #Tseng pointed, there is no built-in solution for named binding. However using factory method may be helpful for your case. Example should be something like below:
Create a repository resolver:
public interface IRepositoryResolver
{
IRepository GetRepositoryByName(string name);
}
public class RepositoryResolver : IRepositoryResolver
{
private readonly IServiceProvider _serviceProvider;
public RepositoryResolver(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IRepository GetRepositoryByName(string name)
{
if(name == "TestSuiteRepository")
return _serviceProvider.GetService<TestSuiteRepositor>();
//... other condition
else
return _serviceProvider.GetService<BaseRepositor>();
}
}
Register needed services in ConfigureServices.cs
services.AddSingleton<IRepositoryResolver, RepositoryResolver>();
services.AddTransient<TestSuiteRepository>();
services.AddTransient<BaseRepository>();
Finally use it in any class:
public class BaselineManager
{
private readonly IRepository _repository;
public BaselineManager(IRepositoryResolver repositoryResolver)
{
_repository = repositoryResolver.GetRepositoryByName("TestSuiteRepository");
}
}
In addition to #adem-caglin answer I'd like to post here some reusable code I've created for name-based registrations.
UPDATE Now it's available as nuget package.
In order to register your services you'll need to add following code to your Startup class:
services.AddTransient<ServiceA>();
services.AddTransient<ServiceB>();
services.AddTransient<ServiceC>();
services.AddByName<IService>()
.Add<ServiceA>("key1")
.Add<ServiceB>("key2")
.Add<ServiceC>("key3")
.Build();
Then you can use it via IServiceByNameFactory interface:
public AccountController(IServiceByNameFactory<IService> factory) {
_service = factory.GetByName("key2");
}
Or you can use factory registration to keep the client code clean (which I prefer)
_container.AddScoped<AccountController>(s => new AccountController(s.GetByName<IService>("key2")));
Full code of the extension is in github.
You can't with the built-in ASP.NET Core IoC container.
This is by design. The built-in container is intentionally kept simple and easily extensible, so you can plug third-party containers in if you need more features.
You have to use a third-party container to do this, like Autofac (see docs).
public BaselineManager([WithKey("TestSuiteRepository")]IRepository repository)
After having read the official documentation for dependency injection, I don't think you can do it in this way.
But the question I have is: do you need these two implementations at the same time? Because if you don't, you can create multiple environments through environment variables and have specific functionality in the Startup class based on the current environment, or even create multiple Startup{EnvironmentName} classes.
When an ASP.NET Core application starts, the Startup class is used to bootstrap the application, load its configuration settings, etc. (learn more about ASP.NET startup). However, if a class exists named Startup{EnvironmentName} (for example StartupDevelopment), and the ASPNETCORE_ENVIRONMENT environment variable matches that name, then that Startup class is used instead. Thus, you could configure Startup for development, but have a separate StartupProduction that would be used when the app is run in production. Or vice versa.
I also wrote an article about injecting dependencies from a JSON file so you don't have to recompile the entire application every time you want to switch between implementations. Basically, you keep a JSON array with services like this:
"services": [
{
"serviceType": "ITest",
"implementationType": "Test",
"lifetime": "Transient"
}
]
Then you can modify the desired implementation in this file and not have to recompile or change environment variables.
Hope this helps!
First up, this is probably still a bad idea. What you're trying to achieve is a separation between how the dependencies are used and how they are defined. But you want to work with the dependency injection framework, instead of against it. Avoiding the poor discover-ability of the service locator anti-pattern. Why not use generics in a similar way to ILogger<T> / IOptions<T>?
public BaselineManager(RepositoryMapping<BaselineManager> repository){
_repository = repository.Repository;
}
public class RepositoryMapping<T>{
private IServiceProvider _provider;
private Type _implementationType;
public RepositoryMapping(IServiceProvider provider, Type implementationType){
_provider = provider;
_implementationType = implementationType;
}
public IRepository Repository => (IRepository)_provider.GetService(_implementationType);
}
public static IServiceCollection MapRepository<T,R>(this IServiceCollection services) where R : IRepository =>
services.AddTransient(p => new RepositoryMapping<T>(p, typeof(R)));
services.AddScoped<BaselineManager>();
services.MapRepository<BaselineManager, BaseRepository>();
Since .net core 3, a validation error should be raised if you have failed to define a mapping.