autofac resolve issue for keyed values - c#

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.

Related

Difference between Setting Dependency Resolver and Extending Dependency Lifescope

I am reading the Autofac documentation related to its integration with OWIN, and I get confused by the example they put on their website:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// STANDARD WEB API SETUP:
// Get your HttpConfiguration. In OWIN, you'll create one
// rather than using GlobalConfiguration.
var config = new HttpConfiguration();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Run other optional steps, like registering filters,
// per-controller-type services, etc., then set the dependency resolver
// to be Autofac.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// OWIN WEB API SETUP:
// Register the Autofac middleware FIRST, then the Autofac Web API middleware,
// and finally the standard Web API middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
}
Where I am stuck now is on line config.DependencyResolver = new AutofacWebApiDependencyResolver(container); the webapi dependency resolver is set to autofac, and what is the reason that app.UseAutofacWebApi(config); must be called?
The extension method is to "Extends the Autofac lifetime scope added from the OWIN pipeline through to the Web API dependency scope", but the autofac lifetime scope is shared by setting dependency resolver, is this call still necessary?
It would also be very helpful if you can provide me the use cases of UseAutofacWebApi. Thanks!
The short answer is, yes, it's needed.
Usually a way to test this sort of thing is to see if you can get everything you need without it. I mean, if your app works and things are injected right, that's enough, right?
The longer answer involves you needing to understand that Web API is not natively part of OWIN. OWIN is kind of a bolt-on. The way Web API integrates is, very basically, that the Web API pipeline is jammed into the OWIN pipeline as a middleware step. You can do other stuff with OWIN, too, like adding your own middleware and so on. It's a little beyond the scope of the question here to go through all the details of the ASP.NET pipeline, OWIN, how the middleware interacts, etc. A quick Google search for how does web api work with owin brings up a ton of documentation, blog articles, and explanations.
The important aspect there, though, is that there are basically two parts - the OWIN part, with its pipeline, and the Web API part, with its "sub pipeline."
Since the OWIN pipeline starts before the Web API pipeline, in order to make the two work together and have a request lifetime for the whole of the OWIN pipeline, you have to use the Autofac middleware to do that initialization. Then that same scope from the OWIN pipeline needs to make it into Web API. That also means when the Web API request is done, the OWIN pipeline needs to be able to handle the disposal of things rather than letting Web API handle it.
Hence the documentation: "Extends the Autofac lifetime scope added from the OWIN pipeline through to the Web API dependency scope." It's taking the scope created at the start of the OWIN pipeline and making sure it's the same scope that goes into the Web API pipeline.
Some applications not only have Web API but also ASP.NET MVC, all of which is trying to be coordinated through that OWIN pipeline and needing everything to work together. All of the stuff Autofac has in place to get Web API, MVC, and OWIN wired up is there for a reason - to make sure it all plays nicely together.
Generally if something is optional, the docs will explicitly say so. For example in the Autofac Web API documentation it's noted that it's optional to register filter and model binder provider handling. In this case, it's not really optional.

AutofacInstanceContext.Current is null and I don't get why

I'm working on a WCF project in which I'm using Autofac as IoC container and MediatR as a mediator to execute my requests & commands.
The "base" implementation of the WCF contract takes an instance of IMediator as a dependency to delegate the work associated with each request to the associated handler. I also have several decorators I stack up the base implementation for things like authorization and error handling.
As specified in this page of Autofac documentation, the use of a MultitenantServiceImplementationDataProvider is necessary in order to satisfy WCF internals when you use decorators on the service implementation. Nothing more multitenant-related is needed, so it just consists of:
AutofacServiceHostFactory.ServiceImplementationDataProvider = new MultitenantServiceImplementationDataProvider();
Also, in the .svc I specified the qualified name of the interface since it's supported by Autofac and I have decorators on top on my base implementation.
Now, on to MediatR.
MediatR uses service location to instantiate the appropriate handlers when it is given a request. More specifically, it relies on CSL.
Not a problem, since Autofac provides a bridge to support CSL.
The "tricky" part relies in the fact that my handlers take DbContext as dependencies, and I want them disposed by Autofac after each WCF request.
So the AutofacServiceLocator has to be given the scope that is created for the specific request, since the root scope is not disposed and neither would be the DbContext instances.
Autofac got you covered with the AutofacInstanceContext.Current static property which is the equivalent of the AutofacDependencyResolver.RequestLifetimeScope in ASP.NET MVC.
So far so good, here's how I registered the ServiceLocatorProvider the Mediator class takes a depedency on:
builder
.Register(x => new ServiceLocatorProvider(() => new AutofacServiceLocator(AutofacInstanceContext.Current.OperationLifetime)))
.InstancePerLifetimeScope();
It works as expected on my development box but I get a NullReferenceException on the staging environment and I don't really know where to look for - GoogleBing didn't give relevant results.
Only things that differ from both environments:
HTTP on my box vs HTTPS on the staging env.
debugattribute on <system.web> element was set to false on staging env.
And that's about it...
.NET frameworks as the same, 4.5.2.
Anyone has an idea?
Thanks!
Fixed it by changing:
builder
.Register(x => new ServiceLocatorProvider(() => new AutofacServiceLocator(AutofacInstanceContext.Current.OperationLifetime)))
.InstancePerLifetimeScope();
with
builder
.Register(x =>
{
var serviceLocator = new AutofacServiceLocator(AutofacInstanceContext.Current.OperationLifetime);
return new ServiceLocatorProvider(() => serviceLocator);
}
.InstancePerLifetimeScope();
I wouldn't be able to tell you exactly why it didn't work, but I guess that by the time the lambda expression () => new AutofacServiceLocator(AutofacInstanceContext.Current.OperationLifetime) was executed internally by MediatR, it was too late and the current operation context was disposed of or released.
Any insight would still be greatly appreciated!

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.

Simple Injector / IoC - Windows Service and Request Cycles of a Queue Processor

I'm writing a queue processor in C# as a Windows Service. The backend queue mechanism is MongoDB. The purpose of the queue is to run out-of-band requests that originated from our main website (Angular w Web API). For each queued item, a serialized Command instance + the serialized Context info, I would like to
foreach request cycle:
1) New up a DbContext (EF) if it is needed for the current Command Handler
2) Deserialize the AppContext and get that info injected into the current Command Handler
Not sure how to handle these patterns in Simple Injector. Especially since this is the cycle of Timer not a Web Request that there are helpers/classes already written for. Thoughts? I have seen other IoC containers use lambda expressions to handle this kind of stuff in the past. Just not sure how to approach my #1 and #2 scenarios.
Each timer pulse can be considered a new request. Or if you are processing multiple commands in one single pulse, each command can be considered a new request.
Some frameworks such as ASP.NET and WCF have the notion of a request (web request, WCF operation, etc.) and this allows Simple Injector to plug into the framework's request model. Because of this, Simple Injector contains integration packages for MVC, Web API and WCF. Those integration packages hook into the request model of the framework and this allows you to register per-request instances without having to do anything special.
Windows Services, however, don't provide us with such request-based model. This means that you will have to define the request boundaries manually. This holds for all DI containers; not only Simple Injector.
Simple Injector contains two different Lifestyles that allow you to create an explicit scope. These are the ThreadScopedLifestyle and AsyncScopedLifestyle. The ThreadScopedLifestyle is thread-specific, while the AsyncScopedLifestyle can be used when processing asynchronous operations; it allows the scope to flow over asynchronous method calls.
TIP: Prefer the use of AsyncScopedLifestyle over ThreadScopedLifestyle, since it will work for both asynchronous as single-threaded operations. ThreadScopedLifestyle should typically only be used when you are running a .NET 4.0 application, since AsyncScopedLifestyle is only available for .NET 4.5, .NET Core and .NET Standard 1.3.
This means that you will have to start a new 'scope' in the container, before resolving a new service from the container that you use to process that command. For instance:
public void ProcessCommand(object command) {
using (AsyncScopedLifestyle.BeginScope(this.container)) {
Type handlerType =
typeof(ICommandHandler<>).MakeGenericType(command.GetType());
dynamic handler = container.GetInstance(handlerType);
handler.Handle((dynamic)command);
}
}
By wrapping the operation in a lifetime scope, we allow services to be reused. We can do this by registering them using the AsyncScopedLifestyle:
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
container.Register<IUnitOfWork, DbContextUnitOfWork>(Lifestyle.Scoped);
Services that are registered using the lifetime scope will live for the duration of that scope and will get disposed when the scope gets disposed (in the example at the end of the ProcessCommand method).

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