ASP.NET Core - Using IServiceProvider within controllers - c#

I was reading on Constructor injection behavior (ms docs)
I currently have a Transient EmailSenderService that is registered in the DI container.
I have a controller that invokes several business-layer services. One of those business services is dependent on the EmailSenderService, where an email is sent after several business operations are successful.
ControllerA - Controller that calls business services
BusinessServiceA - Has a dependency of EmailSenderService
EmailSenderService - Registered in ASP.NET Core DI container
I am trying to figure out the best approach here... should my controller require IServiceProvider as a dependency so I can directly instantiate my BusinessServiceA (with its EmailSenderService dependency) using something like ActivatorUtilities?
If not using the IServiceProvider in something like GetServiceOrCreateInstance(IServiceProvider) (which is technically a service locator pattern), then what are the other options?
Recap:
I have an email provider that are not injected to my controllers, but business services that are called by my controllers use that email provider which is registered with the DI container, so instead of specifying my email provider as a dependency in my controller and passing it to data services, would just using the IServiceProvider be the correct approach here?

Related

How to manage db context in n-tier asp.net application with dependecy injection?

I have 3-layers architecture - asp.net web api, BLL and DAL. I use Ninject as dependency injector for injecting db context and objects between layers. As ORM i use Entity Framework . Injection of db context is processed in DAL. So every time some repository in BLL is instancied, new instance of db context is also created. Im doing it like this:
public class UserRepository : IUserRepository
{
private IChatDbModel _chatDbModel;
public UserRepository(IChatDbModel chatDbModel)
{
this._chatDbModel = chatDbModel;
}
It´s neccesary to say that PerWebRequest, which would solve my problem is not availible in lower layers than web api. Only web api layer has info about http request lifetime, so can use Ninject.Web.Common library.
My question is, is there a way how to share db context for whole request like using of PerWebRequest in this architecture? Or is really neccesary to create new instance of db context for every new instance of repository?
Edit
I forgot to mention that in each layer I´m referencing Ninject library and I´m registering mapping for the specific layer. The method in DAL looks like this:
public static void Register(IKernel kernel)
{
kernel.Bind<IChatDbModel>().To<ChatDbModel>();
}
in BLL it looks like this:
public static void Register(IKernel kernel)
{
kernel.Bind<IUserRepository>().To<UserRepository>();
NinjectDataAccess.Register(kernel);
}
in API it looks like this, it´s located in NinjectWebCommon.cs:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUserLogic>().To<UserLogic>();
NinjectLogic.Register(kernel);
}
so in each layer, I´m not only mapping it´s own objects but also calling register method of the layer lying below if any and with mechanism like this, I can register dependency mapping of each layer without referencing all layers in API, where I should not reference any other layer than BLL, so in my case DAL. If I reference the DAL in API layer, then it would be possible to define the mapping and call PerWebRequest, because I would have the objects, but I´m not and I think this should be avoided by the architecture, or am I wrong?
You can achieve per request instance by registering OnePerRequestHttpModule http module, which internally uses HttpContext lifecycle to track registered types and dispose them at the end of the request/response lifecycle.
After installing Ninject.Web.Common package, in NinjectWebCommon.cs you have to do (it will be added automatically once nuget package is installed)
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule))
And for your type registrations, you can do the following
//register IChatDbModel with per request scope
kernel.Bind<IChatDbModel>().To<ChatDbModel>().InRequestScope();
//register repositories with default transient scope
kernel.Bind<IUserRepository>().To<UserRepository>();
All your repositories will be transient, so everywhere they are injected , a separate instance will be supplied, but your DBContext instance will created and disposed per request.
I am assuming you have added both BAL and DAL reference to web api project, so that web api project has access to IChatDbModel to perform type registration in Ninject kernel.

Dependency Injection in the ASP.NET 5 and Object Dispose

Can anybody help me to understand following in context to Dependency Injection in Asp.Net 5 and object dispose.
I need to understand if my Service implements IDispose interface ,who will call dispose method.
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IService, Service>();
services.AddScoped<IService, Service>();
services.AddSingleton<IService, Service>();
services.AddInstance<IService, Service>();
}
IServiceCollection contains the set of services available in your application. You defines the services you want to use and their lifetime, and the application will instantiate and dispose them for you.
There are 4 different lifetimes :
Transient
Transient lifetime services are created each time they are requested. This lifetime works best for lightweight, stateless service.
Scoped
Scoped lifetime services are created once per request.
Singleton
Singleton lifetime services are created the first time they are requested, and then every subsequent request will use the same instance. If your application requires singleton behavior, allowing the services container to manage the service’s lifetime is recommended instead of implementing the singleton design pattern and managing your object’s lifetime in the class yourself.
Instance
You can choose to add an instance directly to the services container. If you do so, this instance will be used for all subsequent requests (this technique will create a Singleton-scoped instance). One key difference between Instance services and Singleton services is that the Instance service is created in ConfigureServices, while the Singleton service is lazy-loaded the first time it is requested.
The asp.net 5 official documentation is great, take time to read it : http://docs.asp.net/en/latest/fundamentals/dependency-injection.html
The documentation doesn't mention how exactly the dependencies lifetimes are handled by the dependency injection service but if you search in the code, you will find the ServiceProvider class, who manages the lifetimes : ServiceManager class
To be a little more specific, when a scope is created, the service scope factory returns a new service scope, who is instanciated with a service provider. When the dependency injection service have to dispose a service, he calls the service scope's dispose method, who calls the service provider's dispose method.
How the service provider works ? He has all the service scopes in a property, named _resolvedServices, and all the transiant disposables in a property named _transientDisposables. When the dispose() method of the service provider is called, he loops on all the items he has in this two properties, and for each object calls his dispose method.
You have all the source code here : Dependency Injection source code

Autofac WebAPI Common Service Locator

So reading Autofac documentation on using it with WebApi, it says:
A common error in OWIN integration is use of the GlobalConfiguration.Configuration
I have a BaseController which uses the IMediator and to get an instance from the container I use the GlobalConfiguration.Configuration.DependencyResolver.GetService().
If I don't use GlobalConfiguration what other options do I have to inject the IMediator.
It's nice not to use constructor injection because then other api controllers don't need to have a constructor, and because of IMediator rarely will.
I've looked at property injection but I couldn't understand how to integrate it in the web api scenario, I use the builder.RegisterApiControllers and it doesn't look as though integrating property injection on the base controller fits this approach.
builder.RegisterApiControllers() returns IRegistrationBuilder which means you can continue customizing Controller registration from there.
For instance if you need to apply property injection to your Controllers you could use the following code:
builder.RegisterApiControllers().PropertiesAutowired();

Retrieving the application-wide container in web api

I'm trying to solve a problem I have with asynchronous event-based rest services. I have services that generate events in the application, and those events are handled asynchronouly. The problem I have is my linq to sql data contexts are disposed by then, because of autofac's lifetime scopes.
I found a website that had a solution for it and it involved getting the application wide container. He got it like so :
var accessor = ((IContainerProviderAccessor) HttpContext.Current.ApplicationInstance);
return accessor.ContainerProvider.ApplicationContainer;
However, I can't import IContainerProviderAccessor, which seems to be in autofac's mvc integration assembly. How can I translate this code for web api.
IContainerProviderAccessor is no longer supported. Autofac now use the IDependencyResolver of ASP.net MVC
If you want to access the resolver you can use the DependencyResolver.Current property of ASP.net MVC.
YourDbContext yourDbContext = DependencyResolver.Current.GetService<YourDbContext>();
Another solution would be to inject Func<Owned<YourDbContext>>, it will act as a factory. Each time you need a DbContext inside an API method you will be able to invoke it Autofac will instanciate a new one.

WebApi, Autofac, System.Web.Http.Filters.ActionFilterAttribute Instance Per Request

We have been using Autofac in our application (MVC 4 now) for a long time, we have dozens of attributes on the base controller everything inherits from and it has all been working fine so when the request begins our service is created and then available through all the attributes and on the controller action.
We are now looking at WebApi and have created our WebApi controller and created an attribute on the base controller using the ActionFilterAttribute from the HTTP namespace. However the problem starts here where the service injected on the property on the attribute is not the same instance as that on the ApiController. Looking at the link below this seems to be known ASP.NET Web API and dependencies in request scope
However the solution here is not ideal as we don't want our controllers to know about the dependency injection, we just want to use the service we are injecting to the property and know it is one instance per request.
We are calling this:
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
And
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
Our classes are currently registered with Autofac as InstancePerLifetimeScope, what we want is to be able to have per request working for MvcControllers and ApiControllers.
Is that possible?
EDIT:
So basically this line returns the right service for the request (i.e. the same instance that is also on the ApiController)
var service = actionContext.Request.GetDependencyScope().GetService(typeof(IOurService);
But the property injection instance on the ActionFilterAttribute is not the same and if I change the Autofac registration to be InstancePerApiRequest I get the following error:
"No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself."
This is a known issue and a design problem in Web API. When filter instances are first created in Web API they are cached, so Autofac has to resolve the property injection using the root lifetime scope, not the request lifetime scope. There is no opportunity on a per-request basis for Autofac to do any property injection - the filters are effectively singletons within Web API and there's no hook to change that.
Thereafter, if you need per-request services in your filter, you have to use that GetDependencyScope() trick.
See these issues on Autofac for more details:
Issue #452: Property Injection in Web API ActionFilterAttribute does not use Http request scope
Issue #525: Filter not getting instance per http request

Categories

Resources