Autofac WebAPI Common Service Locator - c#

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();

Related

ASP.NET Core - Using IServiceProvider within controllers

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?

ASP.Net Core dependency injection | How to access user or route data upon creation

Scenario
I am working to follow the IoC pattern and use the Microsoft DI Framework, but I'm hitting a wall and can't decide if it's my mindset, my approach, or I'm just doing it wrong.
I have a multi-tenant application that utilizes a Utility class to handle isolation and accessing the data of the tenant based on their unique configuration. The tenant is identified during authentication, but the tenant data has to be accessible and handled based on the request. This Utility class is registered under ConfigureServices in the Startup.cs and the constructor requires two parameters - a TenantDbContext and a Tenant.
public class TenantUtility{
public TenantUtility(TenantDbContext context, Tenant tenant){/*...*/}
}
Problem
Realizing that I'm probably pushing the limits of the DI Framework, I'm trying to build an implementationFactory in the Startup.cs. I've tried two approaches for accessing the tenant Id to build the Tenant object: one is using a User Claim, the second is a Route parameter.
services.AddTransient<TenantUtility>((svc)=> {
var tenantContext = svc.GetService<TenantDbContext>();
var accessor = svc.GetService<IHttpContextAccessor>();
var httpContext = accessor.HttpContext;
//httpContext is NULL...
//How do I get access to the tenant?
Common.Tenant t = new Common.Tenant();
//Set Tenant Identifier in t (once I get it)
return new StudentDataManager(tenantContext, t);
});
In both situations, when I setup the ImplementationFactory inside the Startup.cs, I don't have access to the user and I don't have access to the RouteData (or can't figure out how to get it) -- I even tried using IHttpContextAccessor, but the HttpContext property is null.
Am I approaching the pattern incorrectly? Should I be able to use DI for this level of detail be injected into the Utility before the Utility class is passed into the Controller?
You shouldn't pass in non-DI-managed types into services you want the container to provide for you (in this case, your Tenant parameter). Only request services that the container can provide. If you need a tenant, perhaps another service like an ITenantAccessor could be injected and would be able to get one.
I suspect your implementation could be done in middleware (if not using MVC) or as a filter (if using MVC). In either case, you can use DI from the filter or middleware class to inject your tenant service. In the class's invoke method, you will have access to the current context and request and should be able to do the things you need to. Remember that ConfigureServices runs before the app has started, so there is no context and no request is yet being made.
If you want to see some examples of filters, and especially how to do DI into filters, check out:
https://github.com/ardalis/GettingStartedWithFilters
and
http://ardalis.com/real-world-aspnet-core-mvc-filters
If you want to do it in middleware, then these might help:
https://github.com/ardalis/NotFoundMiddlewareSample
and
http://ardalis.com/using-custom-middleware-to-record-and-fix-404s-in-aspnet-core-apps
It seems to me that what you are injecting in the TenantUtility as a frist parameter is a valid abstraction (though it's probably better to use some interface), but the other one is a value-object. You don't generally inject value objects as they are not abstraction of some operations that you need to perform, but data. So I would pass the Tenant as a parameter to an operation on the TenantUtility class.
Another thing that I can suggest is to use a full-blown DI container like SimpleInjector (there are many others like Ninject, CastlWindsor, etc.). They are much more advanced as far as I know and can easily be integrated. Many of them have .Net Core integration already.

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

How to inject different dependencies into WebApi Controller using StructureMap

Currently I have an MVC application which also contains WebApi controllers.
I've set-up StructureMap to initialize using default conventions which handles service dependencies for both MVC and WebApi. This all works perfectly.
However, I have one Authentication service dependency which should be injected for WebApi and a different implementation for MVC. Since StructureMap has the same initialization bootstrap code, how do I switch depending on whether the request coming in is a WebApi endpoint or and Mvc controller endpoint?
Don't know if this is the best way of achieving this but I use the ObjectFactory.Configure method to override the initialization registries on boot-up but do this inside each SetResolver on Mvc's DependencyResolver.SetResolver and on WebApi's GlobalConfiguration.Configuration.ServiceResolver.SetResolver.
e.g.
ObjectFactory.Configure(x => x.For<IAuthenticationService>()
.Use(s => s.GetInstance<IMvcAuthenticationService>()));
and
ObjectFactory.Configure(x => x.For<IAuthenticationService>()
.Use(s => s.GetInstance<IWebApiAuthenticationService>()));

Categories

Resources