Autofac lifetime scope issue with asp.net webforms - asp.net

I'm having an issue with the lifetime scope of autofac lasting across a request in an asp.net webforms site.
I'm register a factory in auto fac thus:
builder.RegisterType<DoSomethingFactory>().As<IDoSomethingFactory>().InstancePerLifetimeScope();
This occurs in the app_start of course.
then I have a simple user control that calls a method of this factory
IDoSomethingFactory doSomethingFactory = Resolver.Resolve<IDoSomethingFactory>();
Number.Text = doSomethingFactory.DoSomething().ToString();
I have two instances of this control on a page, so that the DoSomething method should be called twice and the factory should be resolved twice also.
The first time I run the site, the contstructor for the DoSomethingFactory is fired, and there are 2 subsequent calls to the DoSomething method. The second request, results in 2 calls to the DoSomething method without a fresh new-ing up of the factory.
If I take out the InstancePerLifetimeScope on the registering then the factory is instantiated on each resolve. Most answers I have seen for this talk about an MVC site. I also have an MVC site and am using it in the same manner and it is working as requested, hence the need to question for asp.net webforms
To be clear I would like the factory to be instantiated once every request. Any help or ideas would be welcome.
Many thanks
Will

If you want to have one instance of your DoSomethingFactory per request you need to use the InstancePerHttpRequest extension method.
From the Autofac wiki: WebFormsIntegration
ASP.NET integration adds a special component lifetime that allows a component instance to live for the life of a single HTTP request. You can register components using the InstancePerHttpRequest() extension method in the Autofac.Integration.Web namespace.
So change your registration to:
builder.RegisterType<DoSomethingFactory>()
.As<IDoSomethingFactory>()
.InstancePerHttpRequest();

Related

Does a call to MapRazorPages() constitute a call to UseEndpoints()?

According to the documentation for UseRouting(), we must call UseEndpoints() afterward:
A call to UseRouting(IApplicationBuilder) must be followed by a call to UseEndpoints(IApplicationBuilder, Action) for the same IApplicationBuilder instance.
But in some code samples (e.g. here) I see UseRouting() calls with UseEndpoints() omitted and MapRazorPages() used instead. Is this safe?
I entered this query into ChatGPT:
What is the difference between App.MapRazorPages and App.UseEndpoints(Sub(Routes) Routes.MapRazorPages)?
...and it returned this helpful answer:
App.MapRazorPages is a method that configures the routing for Razor pages in an ASP.NET Core application. It adds a default route for all Razor pages, which is {page}/{handler?}, where page is the name of the Razor page and handler is the name of an optional handler method defined within the page.
App.UseEndpoints is a method that enables you to specify a pipeline of middleware that will be executed when a request is received by the application. Within the lambda expression provided to UseEndpoints, you can call MapRazorPages to add a route for Razor pages to the pipeline.
So, in short, App.MapRazorPages is a specific method that configures routing for razor pages, while App.UseEndpoints is a more general method that allows you to specify a pipeline of middleware and register various types of endpoints, including razor pages, in the application.
All well and good. Very nice. But what about the admonition from the documentation, that we must call UseEndpoints() at some point after we call UseRouting()? Is it safe to rely on only a call to MapRazorPages() to fulfill that requirement?
This answer seems to indicate so, but I'd like to make sure before I go stringing things together that I don't fully understand.
---EDIT---
Well, go figure.
I consulted the almighty ChatGPT on this one (should've done that at first, I guess) and he boomed down:
No, it is not safe to rely on a call to MapRazorPages() as a substitute for the required call to UseEndpoints().
UseRouting() is used to enable routing in an ASP.NET Core application. It sets up the routing system and prepares the app to handle incoming requests.
MapRazorPages() is an extension method that can be used to configure Razor pages in an ASP.NET Core application. It adds a Razor pages endpoint to the application's endpoint routing table, which allows the app to handle requests for Razor pages.
UseEndpoints() is used to define the endpoints for an ASP.NET Core application. It adds a route to the application's endpoint routing table for each endpoint defined within the lambda passed to it.
So, while MapRazorPages() can be used to configure razor pages and add a corresponding endpoint to the application's endpoint routing table, it cannot be used as a substitute for UseEndpoints(). UseEndpoints() is required to properly define the endpoints for an ASP.NET Core application and handle incoming requests.
So there we have it. But should we trust it? I'm a little bit wary, perhaps because I tend to prefer to live on the edge and not allow myself to be lulled into complacency by The Matrix.
Can someone corroborate?
It differs in different .NET versions.
For example, in .NET 5, you have to call app.UseEndpoints() to register routing. However, in .NET 6 you can register routes with a call to app.MapRazorPage() directly, leaving out both app.UseRouting() and app.UseEndpoints(). This is documented here.
Apps typically don't need to call UseRouting or UseEndpoints. WebApplicationBuilder configures a middleware pipeline that wraps middleware added in Program.cs with UseRouting and UseEndpoints. However, apps can change the order in which UseRouting and UseEndpoints run by calling these methods explicitly.

Get same instance of a component registered with Autofac as InstancePerLifetimeScope in Global.asax methods as is injected into a controllers?

I have a situation where I need to manually instantiate some objects in Application_BeginRequest that are dependent on some of the same components that I've registered with Autofac. I'd like to use the same instances of components that I've registered with Autofac with InstancePerLifetimeScope for injection into my MVC and WebAPI controllers. My config for both MVC and Web API works as expected, and an example of a component registration looks like so:
builder.Register(c => new MyDbContext()).AsSelf().InstancePerLifetimeScope();
Now I want to use that same instance in the class I'm instantiating in Application_BeginRequest. I've tried the following methods:
//Tried with MVC controllers
DependencyResolver.Current.GetService<MyDbContext>()));
AutofacDependencyResolver.Current.ApplicationContainer.Resolve<MyDbContext>()));
AutofacDependencyResolver.Current.RequestLifetimeScope.Resolve<MyDbContext>()));
//Tried with Web API controllers
GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(MyDbContext))
But none give me what I'm looking for, even at later points in the request lifecylce (ie, beyond BeginRequest). As an aside, I need this to work with the Web API configuration, but I tried the first 3 methods just to see if I could get any of the resolved instances to match up with what Autofac is injecting.
I have what I believe is a decent understanding of lifetime scopes in Autofac and my assumption is that the instances that are being resolved for my application's controllers are in a child scope that the none of the above 4 methods are pointed towards, but it's fuzzy to me what each of the above methods is trying to do in regard to which scope they are looking at and how they decide. What's even fuzzier is what lifetime scopes Autofac is automatically creating for the components that are ultimately injected into my controllers and when they're created.
Clarification on the points above would be a big bonus, but my primary question here is how do I get Autofac to hand me the same instances of registered components in Global.asax that it resolves for Web API and MVC controllers?
If you read up on this subject, you'll notice that folks mention that in most circumstances for a web application, InstancePerLifetimeScope and InstancePerRequest can be used interchangeably. What they don't mention are the exceptions where these two registrations behave differently. Gerrod has an excellent article on lifetime scopes inside of ASP.NET MVC/Web API applications and how they work in which he elaborates on this piece of info that most omit. Understanding this difference is crucial to this scenario, and his article cleared up any misunderstandings I had in regards to InstancePerLifetimeScope registration in relation to ASP.NET applications. It also made me realize that, because I need to share instances of resolved components across my MVC/Web API controllers and within the global.asax, InstancePerLifetimeScope is no longer a suitable means of registration for this application- I now need to use InstancePerRequest.
As per the docs, InstancePerRequest actually uses InstancePerMatchingLifetimeScope under the hood. What I need is a reference to the child scope that is tagged with "AutofacWebRequest" that lives under the root scope. This is the scope that both my MVC and Web API controllers resolve their dependencies from, since they both use the same tag. So how do I get a reference to that particular scope? This was my solution, and I'd love to know if there's a better way to do it.
First off, I need to change my registration from
builder.Register(c => new MyDbContext()).AsSelf().InstancePerLifetimeScope();
to
builder.Register(c => new MyDbContext()).AsSelf().InstancePerRequest();
Now, after I've built my container I have the following method:
private void SetDependencyResolversForMvcAndWebApi(ILifetimeScope container)
{
container.ChildLifetimeScopeBeginning += CaptureRequestLifetimeScope;
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
The only part that wasn't there before is the event subscription. Everytime my container creates a child scope, my event handler gets called. The event handler looks like this:
private void CaptureRequestLifetimeScope(object sender, LifetimeScopeBeginningEventArgs args)
{
if (args.LifetimeScope.Tag == MatchingScopeLifetimeTags.RequestLifetimeScopeTag)
{
//Get the ILifetimeScope created for components registered with InstancePerRequest
var requestScope = args.LifetimeScope;
//This is the same DbContext instance that will be injected into
//my WebAPI and MVC controllers
var context = requestScope.Resolve<MyDbContext>();
//do the rest of my stuff
}
}
I've tested this by holding onto a reference of the resolved DbContext that's resolved within the CaptureRequestLifetimeScope event handler and comparing it to the DbContext instances that are injected into my Web API and MVC controllers, and they are indeed pointing to the same object.
Well, I think you should try changing .InstancePerLifetimeScope() into .InstancePerRequest();
As Autofac says about InstancePerLifetimeScope:
When you resolve the instance per lifetime scope component, you get a single instance per nested scope (e.g., per unit of work).
So when you do Resolve<MyDbContext>() you are probably doing it in a different Lifetime scope than you controller (I guess it's because you're doing an explicit resolution); that's why you're getting a diffent instance.
InstancePerRequest instead:
Some application types naturally lend themselves to “request” type semantics, for example ASP.NET web forms and MVC applications. In these application types, it’s helpful to have the ability to have a sort of “singleton per request.”
The begin phase of your request is already in the request phase, so you shoud get the same instance there and inside your controllers.
Instance per request builds on top of instance per matching lifetime scope by providing a well-known lifetime scope tag, a registration convenience method, and integration for common application types.
Based on this, probably, you can also go for the .InstancePerMatchingLifetimeScope("myrequest"), but you will have to manually instanciate a Lifetime scope everywhere like this using(var scope1 = container.BeginLifetimeScope("myrequest")); I think is not so practical.
Obviously I suppose you will not use those elements outside of the request scope, or you will get an exception. In that case, you are forced to the MatchingLifetimeScope.
If you need more details, the Autofac guide is extremely clear.
DependencyResolver.Current.GetService<MyDbContext>()));
AutofacDependencyResolver.Current.RequestLifetimeScope.Resolve<MyDbContext>()));
are same. They get current request lifetime scope. If you resolve some instance here, it shares it with cotrollers. (In this stiuation, instance per request and instance per lifetime will be same. Because their lifetime is same).
AutofacDependencyResolver.Current.ApplicationContainer.Resolve<MyDbContext>()));
This wil be resolved from root container. That's why it will create another instance for request lifetime scope. This will not be shared. And this will live in root container. (If you have per request instance, this will give error).
I have tested first one. It shares instance resolved in Application_BeginRequest with mvc controllers but not with Api controllers.
Then I tried to get GlobalConfiguration.Configuration.DependencyResolver.GetRequestLifetimeScope() in Application_BeginRequest it returns null.
I think, if it's api request, Autofac doesn't start request lifetime yet in Application_BeginRequest (May be it's related .net).
So if it's api request and if we can't reach autofac request life time. I don't know how to share this instance with mvc and api controllers which is resolved in Application_BeginRequest.
May be Travis can make it clear.

Order of execution of the absolute earliest places to run code in ASP.NET

There are numerous places you can have initialization code be executed in ASP.NET:
web.config is processed
WebActivator PreApplicationStartMethod
WebActivator PostApplicationStartMethod
Global.asax Application_Start
What is the ordering of these occurences? Are there any other additional items that should be to this list?
Edit: Since it was mentioned that statics are relevant to first invocation location, I'm going to break this up for them
Foo class that is used in a WebActivator PreApplicationStartMethod
static constructor
static readonly field
Bar class that is used in a WebActivator PostApplicationStartMethod
static constructor
static readonly field
Baz class that is used in a Global.asax Application_Start
static constructor
static readonly field
For clarity purposes, suppose that in the above examples each of those depends on the Foo/Bar/Baz class being used in the location and that the class contains a static constructor and static readonly field.
Static constructors and static field initialization is determined by the runtime, not ASP.NET. Eric Lippert recently posted a great four-part blog series detailing how they work.
As for the rest of the items you mentioned, methods marked with the System.Web.PreApplicationStartMethodAttribute are executed first. According to the MSDN documentation for this attribute, there is no guarantee of the order in which these methods are called.
According to a blog post by Phil Haack, this attribute gives developers the opportunity to call two other methods during the application's startup: BuildProvider.RegisterBuildProvider and BuildManager.AddReferencedAssembly. The MSDN documentation for BuildManager.AddReferenceAssembly states that this method can only be executed during the Application_PreStartInit stage of the application, which suggests that's when all methods marked by the System.Web.PreApplicationStartMethodAttribute are executed.
WebActivator uses the framework's PreApplicationStartMethodAttribute to hook into the application's startup. Once called, it will search for and execute all methods marked by the WebActivator.PreApplicationStartMethodAttribute before it dynamically registers an HttpModule that will later invoke all methods marked by the PostApplicationStartMethodAttribute - after Application_Start has been called in the HttpApplication class.
So, to summarize, the order is:
Web.config is read into memory
Methods marked with a PreApplicationStartMethodAttribute
HttpApplication.Application_Start
Methods marked with WebActivator.PostApplicationStartMethodAttribute
The application life cycle looks like this:
A request is made for an application resource.
The unified pipeline receives the first request for the application.
Response objects are created for each request.
An HttpApplication object is assigned to the request
The request is processed by the HttpApplication pipeline.
Additionally, here are the events that occur in the request pipeline:
See ASP.NET Application Life Cycle Overview
Static constructors and static readonly fields (instantiated inline) are initialized the first time that type is used by your code. That could happen any point in the application lifetime.
Specifically answering your question
According to the WebActivator project page, this is the order of events:
web.config is processed
WebActivator PreApplicationStartMethod
Global.asax Application_Start
WebActivator PostApplicationStartMethod
As far as static initialization goes, see Eric Lipperts posts that Justin linked in his answer.
Your current list has some things that aren't necessarily related to ASP.NET only (static readonly fields, etc.), but this link describes the ASP.NET lifecycle. There are a ton of things that happen, many of them allow customization where you could inject some of your own code if you had good reason to.
Your question is pretty broad. Is there something you're trying to accomplish here that could hope hone in on what part of the process would be ideal for what you want to do?

MVC 3/4 HttpModule or ActionFilter

I need to check some stuff (Cookies) for each request coming to my application.
In ASP.NET we've used HttpModule for this task , the question what should be used in MVC ? Some Global Filter , or I can Use HttpModuler as well, is there Any difference in Request PipeLine between MVC and regular ASP.NET ?
MVC is an abstraction over ASP.NET and therefore their "hooks" really depend at which level you want to inject your logic. An action filter will allow you to hook into MVC specific events:
OnActionExecuting – This method is called before a controller action is executed.
OnActionExecuted – This method is called after a controller action is executed.
OnResultExecuting – This method is called before a controller action result is executed.
OnResultExecuted – This method is called after a controller action result is executed.
Whereas an HttpModule only allows you to hook into ASP.NET (upon which MVC is built) specific events:
BeginRequest - Request has been started. If you need to do something at the beginning of a request (for example, display advertisement banners at the top of each page), synchronize this event.
AuthenticateRequest - If you want to plug in your own custom authentication scheme (for example, look up a user against a database to validate the password), build a module that synchronizes this event and authenticates the user in a way that you want to.
AuthorizeRequest - This event is used internally to implement authorization mechanisms (for example, to store your access control lists (ACLs) in a database rather than in the file system). Although you can override this event, there are not many good reasons to do so.
PreRequestHandlerExecute - This event occurs before the HTTP handler is executed.
PostRequestHandlerExecute - This event occurs after the HTTP handler is executed.
EndRequest - Request has been completed. You may want to build a debugging module that gathers information throughout the request and then writes the information to the page.
So it really depends on when you need to hook in your event and which events you need.
If the HttpModule worked well for you before then it will continue to with Mvc.
The other parts of your question are quite broad in scope and think you'd be as well reading a good article on asp.net-mvc pipeline and extensibility.
I've done similar things using a global action filter. It works quite well, and keeps your code integrated within your application.
An HTTP module works as well, of course, but this will mean seperating the code from your main application and maintaining it seperately. Unless your code spans multiple sites or is used in multiple applications, or needs to work with web forms sites, then I would use a global filter.

Does the SessionState attribute in MVC 3 work properly?

I'm managing a rather large project, written in asp.net webforms + mvc3, with a large user base, and a pretty high daily visitor count. Basically, there are a lot of requests at any given moment.
One of my controllers in MVC that handles / resizes images on the fly has the following attribute applied to it:
[SessionState(SessionStateBehavior.Disabled)]
Now, if an action in the controller tries to access the session - it obviously throws an exception - so we're good so far.
The problem is: if I go to the IIS Worker Processes window (Win Server 2008 R2, IIS 7.5), and check the current requests for this site, I can sometimes see the requests to an action in this controller. Their current state is locked in State: RequestAcquireState, Module Name: Session. Sometimes these locks go over a second or two in this state.
Wasn't the whole point of the attribute in the first place to make the requests to the controller ignore the state, and not waste time (and possibly being locked) trying to acquire the state?
If this is so - am I doing something wrong here, or does the problem lie elsewhere?
[migrated from comments]
If you're using a custom controller factory or route handler, make sure that they're aware of the controller's session state behavior. Marking a controller as not requiring session state requires cooperation from both of these components. Out-of-box, the DefaultControllerFactory and MvcRouteHandler are designed to work with this. See DefaultControllerFactory.GetControllerSessionBehavior and MvcRouteHandler.GetHttpHandler for more information. If you're writing custom components, you can use those methods as inspiration.

Resources