MVC Web API AutoFac Dependency Injection - c#

In my setup class I have the following code (using Autofac and the MVC Web API Template in Visual Studio)
builder.RegisterType<CRMUserStore<IdentityUser>>().As<IUserLoginStore<IdentityUser>>()
.InstancePerRequest();
Then in the Startup.Auth class I have the following
UserManagerFactory = () => new UserManager<IdentityUser>(
DependencyResolver.Current.GetService<IUserLoginStore<IdentityUser>>());
This returns null. Then when I try instead of the above
UserManagerFactory = () => new UserManager<IdentityUser>(
_container.Resolve<IUserLoginStore<IdentityUser>>()); //_container is IContainer
I get an error saying
An exception of type 'Autofac.Core.DependencyResolutionException' occurred in Autofac.dll but was not handled in user code
Additional information: 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.
How do I fix this?

Your IUserLoginStore service is being registered as InstancePerRequest which means it can only be resolved from within the context of a request. I.e. a lifetime scope tagged as 'AutofacWebRequest'.
AutoFac automatically creates a new lifetime scope tagged as 'AutofacWebRequest' for each request, and hence services resolved within the request can access this tagged scope.
I would imagine that the Startup.Auth class is running at the scope of the MVC application and outside of any specific request. Therefore it doesn't have access to the tagged scope and hence the exception No scope with a Tag matching 'AutofacWebRequest'.
If this is the case then changing the IUserLoginStore registration to InstancePerLifetimeScope will allow it to resolve correctly within the Startup.Auth class.
However, this would also change the behaviour when resolving within a request to always getting the application scoped service as well. Without seeing more of your code I can't tell if this would be an issue.
Here's a related question with a nice writeup: Autofac - InstancePerHttpRequest vs InstancePerLifetimeScope
Note - Ensure you have configured Asp.Net MVC to use AutoFac for dependency resolution as described in the AutoFac documentation ( https://code.google.com/p/autofac/wiki/MvcIntegration ).
protected void Application_Start() {
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// Other MVC setup...

Related

autofac resolve issue for keyed values

I am currently working on a feature and added the builder code like this in the Autofac
builder.RegisterType<ILTLoPublisher<ScheduleUpdateEvent>>()
.AsImplementedInterfaces()
.InstancePerRequest()
.Keyed<IILTLoPublisher<ScheduleUpdateEvent>>(AuditType.Schedule);
builder.RegisterType<ILTLoPublisher<ScheduleUpdatePart>>()
.AsImplementedInterfaces()
.InstancePerRequest()
.Keyed<IILTLoPublisher<ScheduleUpdatePart>>(AuditType.Part);
builder.RegisterType<ILTLoPublisher<ScheduleUpdateTest>>()
.AsImplementedInterfaces()
.InstancePerRequest()
.Keyed<IILTLoPublisher<ScheduleUpdateTest>>(AuditType.Test);
This code is run as a console app service and the call to this is made from an api service.I want it to be called as below
AutoFacModule autofac = new AutoFacModule();
var builder = new ContainerBuilder();
autofac.LoadBuilder(builder);
Container = builder.Build();
using (var scope = Container.BeginLifetimeScope())
{
var _publisher1 = scope.ResolveKeyed<IILTLoPublisher<ScheduleUpdateEvent>>(AuditType.Schedule);
var _publisher2 = scope.ResolveKeyed<IILTLoPublisher<ScheduleUpdatePart>>(AuditType.Part);
var _publisher2 = scope.ResolveKeyed<IILTLoPublisher<ScheduleUpdateTest>>(AuditType.Test);
}
When i am trying to resolve it using the below code in my implementation class
var _publisher = scope.ResolveKeyed<IILTLoPublisher<ScheduleUpdateEvent>>(AuditType.Schedule);
I am getting the following error
Unable to resolve the type Apiconnector.Integrations.Vilt.Service.Providers.Custom.Publish.ILTLoPublisher`1[LMS.ILT.ScheduleUpdateEvent]' because the lifetime scope it belongs in can't be located
You can't use InstancePerRequest unless the object being resolved is part of a web request (as noted by the comments on the question). More specifically:
The executing application must be a web application.
The executing application needs to have the Autofac web integration in place.
The resolution must be happening in that web application as part of a response to an inbound web request - for example, as part of an MVC controller or ASP.NET Core middleware.
The "per request" semantics have nothing to do with the client making the request - it's about the server handling the request.
You might want to spend some time with the documentation on the topic. There is a section in there about how to implement custom per-request semantics for your app.
If what you are creating is a console app that takes in requests from clients (e.g., a self-hosted web application) then you need to:
Add the existing Autofac web integration for your app type (we do support ASP.NET Web API and ASP.NET Core self hosted scenarios); OR
Implement something custom if you're not using ASP.NET (see that doc I linked).
If what you are creating is a console app that issues requests as a client then you should ignore InstancePerRequest. Instead:
Create a new lifetime scope around each request (like you're doing) and treat that as a unit of work.
Register components as InstancePerLifetimeScope so there will be just one for the duration of that lifetime scope.
That said, without a minimal repro it's hard to see what you're doing beyond that to provide any sort of guidance.
Since you mentioned you're pretty new to all this, it would be very worth your time checking out the Autofac documentation to start understanding concepts like this as well as looking in the Examples repo where there are working examples of many different application types to show you how things work.

Integrate Autofac with mediatr ASP.NET Web API2

I develop an app on asp.net api2 with autofac and mediatR, currently facing some issue with the dependency injection.
// This is registered in the global.asax file and working properly in the controller level
//i'm trying to register the entity framework context as instance per request
builder.RegisterType<EFContext>().InstancePerRequest();
However when sending the command throught MediatR pipeline, i get an exception because MetdiatR service provider cannot read the http request scope.
Below code is also located in the global asax file.
builder.Register<ServiceFactory>(context =>
{
var componentContext = context.Resolve<IComponentContext>();
return t => { object o;
return componentContext.TryResolve(t, out o) ? o : null; };
});
as the delegate function for service locator is called it throw an error saying that No scope with a Tag matching
"AutofacWebRequest" is visible from the scope in....
is there any work around to make mediatr ServiceFactory aware of the autofact InstancePerRequest scope ?
Use InstancePerLifetimeScope instead for resolving entity framework context.
I haven't used mediatR but seems like it doesn't follow the request response pattern, due to which Autofac can't associate any Request Lifetime with it.
Note that the difference between Request Scope and Lifetime Scope in Autofac is only that Autofac will treat a request as a lifetime.
You can read further about scopes from here,
https://autofaccn.readthedocs.io/en/latest/lifetime/instance-scope.html

Simple Injector Usage with UseApplicationInsights/AddApplicationInsights in ASP.NET Core

I am building an ASP.NET Core 2.1 app. For app insight telemetry I have my custom class but I also want to use built-in ITelemetryInitializer's. Does Simple Injector automatically resolves these dependencies when Auto Cross wiring is enabled?
UPDATE
I tried below piece of code and got the error as shown below. I am not sure how else Auto Crosswiring is supposed to work.
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IControllerActivator>(
new SimpleInjectorControllerActivator(container));
services.EnableSimpleInjectorCrossWiring(container);
services.UseSimpleInjectorAspNetRequestScoping(container);
container.AutoCrossWireAspNetComponents(app);
services.AddApplicationInsightsTelemetry(
applicationInsightsLoggerConfig.InstrumentationKey);
var test = Container.GetInstance<TelemetryConfiguration>();
The registered delegate for type TelemetryConfiguration threw an
exception. The registered delegate for type IServiceScope threw an
exception. The IServiceScope is registered as 'Async Scoped'
lifestyle, but the instance is requested outside the context of an
active (Async Scoped) scope.'
Thanks
This issue is caused by a bug in version 4.3.0 of the ASP.NET Core integration package for Simple Injector.
Due to the bug, any auto cross-wired dependency can only be resolved within the context of an active Scope, even if the dependency is a Singleton. TelemetryConfiguration is a Singleton.
When explicitly cross-wiring that dependency (i.e., using container.CrossWire<TelemetryConfiguration>(app)) the problem would go away, since CrossWire does allow Singletons to be resolved outside an active scope.
The problem has been resolved in patch release 4.3.1 of the integration package. In this version, you can resolve TelemetryConfiguration outside the context of an active web request or Simple Injector Scope.
In case the cross-wired service, however, is Transient or Scoped, you still need to either have an active web request, or, in case running on a background thread, an active Simple Injector Scope.

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

Hybrid lifestyle in Autofac

I have an application in ASP.NET MVC that also have a WCF Service included in the same proyect.
Im using Autofac to manage dependency injection. The problem is that when the application is accessed throught web, I need the dependencies to be instanced per Http request. And when the application is accessed throught WCF, I need the dependencies to be instanced per dependency.
In Castle.Windsor, there is a proyect to manage hybrid lifestyles (in this link).
I need something similar, something like:
builder.Register<UnitOfMeasureService>(x => new UnitOfMeasureService())
.As<IUnitOfMeasureService>().HybridLifetimeInstance();
Are there a workaround to manage the instance lifetime depending on when the application has a HttpContext or not?
Autofac does not have support for custom lifestyle managers.
Autofac lifetimes revolve around scopes, which are nestable and can be optionally tagged with a known ID. That's how instance-per-HTTP-request works: A nested scope "tagged" with a known value ("AutofacWebRequest") is created when a web request comes in. The hierarchy looks like this:
Container (root lifetime scope)
Web Reqeust Scope (tagged "AutofacWebRequest")
Any child scopes you might create in your code
When using InstancePerHttpRequest it's basically the same as InstancePerMatchingLifetimeScope("AutofacWebRequest"). If you resolve the type, it falls back until it finds a scope with that name and then uses the same instance in that tagged scope.
In standard WCF hosting, Autofac resolves everything out of a child scope you can get from the instance context (AutofacInstanceContext.Current.OperationLifetime). You could create a child lifetime scope from that and manually tag it, then resolve your dependencies like this:
var opScope = AutofacInstanceContext.Current.OperationLifetime;
using(var requestScope = opScope.BeginLifetimeScope("AutofacWebRequest"))
{
// Resolve InstancePerHttpRequest items from requestScope
}
However, there's no way to do that automatically and the WCF hosting mechanism isn't currently architected in a way you can "plug in" and do this - if you needed the web request scope automatically created, you'd have to roll your own WCF hosting mechanism based on the Autofac source code.
The other option is to have two different containers - one for your web stuff and one for your WCF stuff - and register the component with a different lifetime in each container.
Beyond that... there's really no way to "switch" lifetimes based on context. A component gets one lifetime declared and has to live with it for that component registry.

Categories

Resources