Autofac scope in ASP.NET Core appears to differ between middleware - asp.net-core

When registering an object with Autofac and resolving in middleware and again in the MVC middleware via a controller, the instance is different. Instances are registered per lifetime scope.
I've popped a repro project here https://github.com/jakkaj/AutofacResolveIssue.
The app sets a value to the IUserService in the middleware, then try to read that value in the ValuesController later.
This same technique worked in older versions of ASP.NET with autofac. Any ideas what's going on?

Okay, so I made the mistake of injecting my dependency in to the constructor of the middleware.
You should inject dependencies into the Invoke.
The entire middleware object is singleton across all app instances!

Change builder registration to use SingleInstance() insted of InstancePerLifetimeScope(), So that every dependent component or call to Resolve() gets the same, shared instance.
builder.RegisterAssemblyTypes(typeof(UserService).GetTypeInfo().Assembly)
.Where(t => t.Name.EndsWith("Service") || t.Name.EndsWith("Repo"))
.AsImplementedInterfaces()
.SingleInstance();
Single Instance This is also known as ‘singleton.’ Using single instance scope, one instance is returned from all requests in
the root and all nested scopes. When you resolve a single
instance component, you always get the same instance no matter where
you request it.
Check the link for more details
http://docs.autofac.org/en/latest/lifetime/instance-scope.html#single-instance

Related

User scoped dependencies in a custom ASP.NET Core Action Filter?

According to the official documentation here:
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters#authorization-filters
To implement a custom ActionFilter in ASP.NET Core I have three choices:
SeviceFilterAttribute
TypeFilterAttribute
IFilterFactory
But for all three it is stated that:
Shouldn't be used with a filter that depends on services with a lifetime other than singleton.
So how can I inject scoped services in my custom ActionFilter? I can easily get a scoped service from the current HttpContext like this:
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
ISubscriptionHelper subscriptionHelper =
actionContext.HttpContext.RequestServices
.GetRequiredService<ISubscriptionHelper>();
}
But then I am wondering if I am doing something wrong? What is the correct way to depend on scoped services in a custom ActionFilterAttribute?
Resolving services from the HttpContext.RequestServices will correctly resolve scoped and transient instances without causing any problems such as Captive Dependencies. In case resolved components implement IDisposable, they will be disposed of when the request ends. ASP.NET Core passes on the current HttpContext object to filter's OnActionExecuting method and that HttpContext gives access to the DI Container.
This is completely different from injecting those services into the constructor, because the action filter will be cached for the lifetime of the application. Any dependencies stored in private fields will, therefore, live as long as that filter. This leads to the so called Captive Dependency problem.
Code that accesses the DI Container (the HttpContext.RequestServices is your gateway into the DI Container) should be centralized in the infrastructure code of the startup path of the application—the so called Composition Root. Accessing your DI Container outside the Composition Root inevitably leads to the Service Locator anti-pattern—this should not be taken lightly.
To prevent this, it is advised to keep the amount of code inside the action filter as small as possible and implement the filter as a Humble Object. This means that preferably, the only line of code inside the filter is the following:
actionContext.HttpContext.RequestServices
.GetRequiredService<ISomeService>() // resolve service
.DoSomeOperation(); // delegate work to service
This means all (application) logic is moved to the ISomeService implementation, allowing the action filter to become a Humble Object.

Can I create an object from the DI container/Lamar in .NET 6.0 minimal hosting, preserving singletons?

We have migrated from a windows Framework 4.7 application to .NET 6.0. Lamar is added for Dependency Injection. We are trying to finalize a refactor to the latest "one-file" program.cs but are getting unexpected System.ObjectDisposedException: 'Cannot access a disposed object'. In all cases, the error is against a Func<T> during object creation.
All our tests are running correctly using the same environment, except to start the tests we (a) create the DI container and (b) use the container to create an object that loads the singletons (from MongoDB):
Container = new Container(registry);
var start = Container.GetInstance<HomeService>();
In the program.cs, we configure the container, but do not get to see it created, or access it inside program.cs. Instead we create HomeService from IServiceProvider during the first use of a controller. Here we were trying to limit the lifecyle scope during creation:
using (var scope = _container.CreateScope())
{
scope.ServiceProvider.GetService<INewHomeService>();
}
For test, we use the same loading steps, except for adding controllers/mvc, of course (i.e. NOT using builder.Services.AddControllers(); and builder.Services.AddMvc() for (integration) testing).
We have tried a lot of different things, like creating our object independently to the startup, but that did not align the singletons. We can get functionality by using static instead, but then we lose dynamic change access.
Some great tips like Resolving instances with ASP.NET Core DI from within ConfigureServices and https://andrewlock.net/exploring-dotnet-6-part-10-new-dependency-injection-features-in-dotnet-6/ but I can't see the specific example to get the live container just after initial creation.
Is it possible that the issue is just the difference between the lifecycle management of the new .NET DI implementation? As this is configuration at the composition root, if we can configure as per our testing approach, it should solve our problem. Other solutions welcome!
The problem 'Cannot access a disposed object' was being caused by a lifecycle mismatch between retained context and the controller access. The code retained a handle on the state object, that had a handle on the factory using FUNC. As we did not configure the Func as anything, it was transient during the controller graph creation, and so was disposed when the controller request ended.
To solve, we tried registering ALL of the FUNC, per How to use Func<T> in built-in dependency injection which was a large task as we had a few factories throughout an old codebase.
The better solution was to create a factory in the composition root, and use an injected IserviceProvider (or with Lamar an IContainer). This is a simple workaround.
With our creation concern, the creation of our object after the completion of the startup process is working correctly as a lazy validation of the first controller access.

Correct way to clean up a "Pre" instance of ServiceCollection and ServiceProvider?

I am implementing a Custom Configuration Provider in my application.
In that provider, I have to make a REST API call. That call needs a valid OAuth 2 Token to succeed. To get that token I need a semi complicated tree of class dependencies.
For the rest of my application, I just use dependency injection to get the needed instance. But a custom configuration provider is called well before dependency injection is setup.
I have thought about making a "Pre" instance of dependency injection. Like this:
IServiceCollection services = new ServiceCollection();
// Setup the DI here
IServiceProvider serviceProvider = services.BuildServiceProvider();
var myTokenGenerator = serviceProvider.GetService<IMyTokenGenerator>();
But I have read that when you make another ServiceCollection, it can cause problems. I would like to know the way to avoid those problems.
How do I correctly cleanup a "pre-DI" instance of ServiceCollection and ServiceProvider?
(Note: Neither one seems to implement IDisposable.)
Hm, I don't get the point why you want to do it that way.
I'd probably get the Serviceprovider fully build.
To avoid that retrieved services affect each other I'd would use nested containers/scopes which means that if you retrieve retrieve the same service you get different instances per container/scope.
Hopefully I understood what you want to achieve.
See
.NET Core IServiceScopeFactory.CreateScope() vs IServiceProvider.CreateScope() extension

Configuring options for middleware

Looking on different libraries and even Microsoft code I've noticed two different ways of configuring options in code:
in ConfigureServices it can be done when registering DependencyInjection:
services.AddMvc(options => { });
or in Configure
app.UseStaticFiles(
new StaticFileOptions
{
ServeUnknownFileTypes = true
});
I tried to find out, which way use for which purpose and still don't know, assuming that creating your own middleware and registering both DI and usage.
Interesting issue you have found.
Looking into the source code i have found the following:
All the middleware registrations are an overload of this UseMiddleware function, which is an overload of IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);.
In these overloads you can specify hard your own parameters for the middle-ware. Say you have a few strings in the constructor, the DI container will not be able to resolve this.
If the parameters aren't set though, it does fallback to the IServiceProvider to resolve the specific type. see extension class: Microsoft.Extensions.Internal.ActivatorUtilities (inside: Microsoft.AspNetCore.Http.Abstractions.dll)
Tips
As for best practice think about the following (my opinion though):
Try to avoid using simple types in constructor but use an Options class.
for IOptions use services.Configure<>() as here you can specify options from a ConfigSection => appsettings.
As for Services: be aware that middleware is a singleton! so adding a transient Service, will only be resolved once for this middleware!
I think best practise is to: Register Middleware AND its dependencies as singletons in IOC on startup. then resolve it yourself and add it yourself with the method App.Use([yourDelegate]).
The advantage of this method is it is easilier understandable than use the hidden microsoft code + Microsoft recently published an upgrade to the DI container to check if the scopes of your registrations match properly (and warn you if not).
This tool basically does: it checks if a dependency of a service has a smaller scope then the service itself: say service is scope: Singleton and the dependency is scope Transient. this means that if Singleton is resolved Transient is also resolved for this singleton and thus not resolved again on next usage of this singleton. (so its a hidden singleton usage).

Autofac: Is it possible to pass a lifetime scope to another builder?

Problem:
I am building a four layer system with Ui, ServiceLayer, BizLayer and DataLayer. In line with good practice the ServiceLayer hides the BizLayer and DataLayer from the Ui, and of course the ServiceLayer doesn't know what the Ui Layer is.
My implementation is a single .NET application with each layer in its own assembly. I am using Autofac.MVC3 in my MVC3 Ui layer to do all the resolving classes used in a web request. I also include standard Autofac in my ServiceLayer so that it can handle the registration of all other layers in my application. At system startup I call a method to register all the types with Autofac. This does:
Register the lower levels by calling a module inside the ServiceLayer. That handles the registration of itself and all other assemblies using the standard NuGet Autofac package.
Then the Ui layer uses the NuGet Autofac.MVC package to register the various controllers and the IActionInvoker for Action Method injection.
My UnitOfWork class in my DataLayer is currently registered with InstancePerLifetimeScope because it is registered by the ServiceLayer which uses plain Autofac and knows nothing about InstancePerHttpRequest. However I read here that I should use InstancePerHttpRequest scope.
Question:
My question is, can I pass a lifetime scope around, i.e. could the MVC layer pass the InstancePerHttpRequest down to the service layer to use where needed? Alex Meyer-Gleaves seemed to suggest this was possible in his comment from this post below:
It is also possible to pass your own ILifetimeScopeProvider implementation to the AutofacDependencyResolver so that you can control the creation of lifetime scopes outside of the ASP.NET runtime
However the way he suggests seems to be MVC specific as ILifetimeScopeProvider is a MVC extension class. Can anyone suggest another way or is InstancePerLifetimeScope OK?
InstancePerHttpRequestScope is in fact a variant of InstantPerLifetimeScope. The first one only works in a request. If you want to execute some stuff on a background thread, it won't be available.
Like you I'm using autofac in as.net mvc and multiple app layers. I pass around the Container itself for the cases where I need to have a lifetime scope. I have a background queue which executes tasks. Each taks pretty much needs to have its own scope and to be exdecuted in a transaction. The Queue has an instance of IContainer (which is a singleton) and for every task, it begins a new scope and executes the task.
Db access and all are setup as INstancePerLifetimeScope in order to work in this case and I don't have aproblem when I use them in a controller.
With the help of MikeSW, Cecil Philips and Travis Illig (thanks guys) I have been put on the right track. My reading of the various posts, especially Alex Meyer-Gleaves post here, it seems that InstancePerLifetimeScope is treated as InstancePerHttpRequest when resolved by the Autofac.MVC package, within certain limitations (read Alex's post for what those limitations they). Alex's comment is:
Using InstancePerHttpRequest ensures that the service is resolved from the correct lifetime scope at runtime. In the case of MVC this is always the special HTTP request lifetime scope.
This means that I can safely register anything that needs a single instance for the whole htpp request as InstancePerLifetimeScope and it will work fine as long as I don't have child scoped items. That is fine and I can work with that.