When an asp.net application is notified of a URL, it routes it to the appropriate controller and specifically to the appropriate method.
Are those controllers placed upon the stack once? Or do they get instantiated again for each request?
For example, say I have a controller with a linq-to-sql class that gets instantiated in the declaration of the class. If I have n requests that route into that controller, have I spawned n different linq-to-sql class objects, each in their own instance of controller or just 1?
My gut tells me controllers are spawned one per request for thread safety reasons but I can't seem to dig up a better guide than my own gastrointestinal oracle.
They get instantiated each time by DefaultControllerFactory by default. Specifically, in GetControllerInstance,
(IController)Activator.CreateInstance(controllerType);
CreateController is first called which calls GetControllerType to get the controller type based on the controller name and the Namespaces passed in the route data tokens. Then it calls GetControllerInstance which creates an instance of the controller.
There's no better guide than the MVC framework source code itself.
You can define your own ControllerFactory by implementing IControllerFactory and then control how and when controllers are instantiated.
Related
So I want to do some profiling on a bunch of controllers which inherit from System.Web.Http.ApiController. In the project that's doing the profiling, we're registering them with
builder.RegisterApiControllers(typeof(Web.Modules.AutofacModule).Assembly)
.As(type => new Autofac.Core.KeyedService("api", type));
Later on, I'm trying to register a decorator for each with
builder.RegisterDecorator<ApiController>(original => Decorate(original, profiler),
fromKey: "api");
where Decorate injects some profiling code via a DelegatingHandler and returns the original.
I can resolve the controllers just fine:
scope.ResolveKeyed<RegistrationController>("api");
but the profiling code is never invoked, nor is Decorate.
My first thought was that maybe I need to register the controller components as ApiController's, but dropping an .As<ApiController>() just below first snippet wasn't successful.
Any help would be super. This probably just boils down to my lack of Autofac-fu.
So I want to do some profiling on a bunch of controllers which inherit from System.Web.Http.ApiController.
This is impossible. This has nothing to do with Autofac, but with the way ASP.NET Web API is designed.
Even though Web API Controllers derive from a common base class, ASP.NET Web API requires the original controller type to be used. In other words, when it requests a HomeController from the IHttpControllerActivator, it expects that exact type (or a sub type), but not a sibling type (another ApiController derivative).
I think this limitation exists because Web API uses reflection to find the actual action methods. But when you return a decorator, those methods are gone, because a decorator applies composition instead of inheritance. This is very different from how ASP.NET MVC is designed. MVC actually does allow controllers to be decorated, as it always invokes the IController.Execute method. Implementation IController is therefore MVC's only requirement for controllers.
So even if you configure Autofac to wrap any ApiController derivatives in a Decorator, Web API simply won't let you.
The way to apply Cross-Cutting Concerns around the invocation of action methods in Web API is through the use of delegating handlers.
I have this situation where the fact that the user is not logged in is preventing the construction of my controller's dependencies.
[Authorize]
class MyController : Controller
{
public MyController(MyService service)
{
}
}
class MyService
{
public MyService()
{
// requires information which only
// becomes known after the user logs in
}
}
My question is: can I do something to cause the MVC framework to first look at the Authorize attribute and then resolve the controller instance?
The above would be much more preferable to me than either of the following:
Changing MyService to be able to handle being created before user log in
Injecting Func
Switching to service location
Ideally, I'd like to flip a switch in the MVC framework that says, "before you resolve the controller, check that you're actually going to use it and not toss it out due to lack of authorization and direct anyway..."
I have this situation where the fact that the user is not logged in is preventing the construction of my controller's dependencies.
That's the root of your problem.
// requires information which only becomes known after the user logs in
This means that the constructor of that service does too much. Constructors should not do more than store the incoming dependencies. This way you can compose object graphs with confidence.
The building of object graphs should in general be static. This means that the resolved object graph should not change based on runtime conditions (there are exceptions, but this is a good rule of thumb). It shouldn't matter whether or not a user is authorized or not, the service class should still be composed and injected. This means that authorization and loading of data is done at a later point in time; the moment that the request is actually executed (which is directly after the object graph is composed).
Your problem is that you don't really understand how the MVC Request pipeline works.
The first thing you have to realize is that Attributes are, in essence, designed to match up with identical events in the controller base class. There is an OnAuthorization method in Controller, and this is called either just before or just after the attributes OnAuthorization method is called.
So, in order for it to call both methods at roughly the same time, that means the Controller class must have been constructed to do so. What's more, a lot of other stuff goes on before Authorization filters, such as model binding, because your authorization filter may need information from the model to make its decision.
I suggest you check out this pipline chart.
https://www.simple-talk.com/dotnet/.net-framework/an-introduction-to-asp.net-mvc-extensibility/
I have a Web API project where I intend on using an attribute that inherits from ActionFilterAttribute to do logging in a standardized fashion. As part of that logging, I want to extract some values from HttpActionContext in the OnActionExecuting method. I would then want to refer to these as part of OnActionExecuted. I have specified [AttributeUsage(AttributeTargets.Class)] for this attribute. My assumption is that my custom attribute would be instantiated in concert with the class it is applied to, and have the same lifetime as the class to which the attribute is applied. I can't find anything to concretely back this up. I've done some testing and that seems to be how it works but I worry that my test is too limited. I'm assuming that multiple calls to the same controller will generate new instances of that controller and thus new instances of the attribute. I'm basically worried about the thread safety of the data I retrieve as part of OnActionExcecuting.
Anyone know any resources or links that can confirm or deny my assumptions?
It depends on what you are going to use.
Attributes (filters) in Web API are cached (filter pipeline is private readonly Lazy<Collection<FilterInfo>> _filterPipeline; and initialized only once). see here
Therefore if you initialize something in the attribute's constructor, it will remain the same on subsequent executions.
However, the HttpActionContext is created created for every request from HttpControllerContext and HttpActionDescriptor and then passed on to each of the cached filters in the pipeline. see here
As a result, even though the instances of the filters are reused, the value of the context in the methods is specific to the specific request.
I have a RouteCollection and a string with an URL.
Has anybody an idea how can I get the name of the route that would be executed?
Some method like RouteCollection.PredictRoute(url) that will return the route name or the physical file that would be executed.
I want to create some statistics from web server log files. It would be very nice to reuse the used RouteCollection for that statistic.
Many thanks!
Here is a snippet of code I used to test that URLs were being mapped to their correct controller and action. You should be able to inspect the route name as well.
RouteConfig.RegisterRoutes(routes);
RouteData routeData = routes.GetRouteData(context);
string controller = routeData.Values["controller"];
string action = routeData.Values["action"];
The variable routes is a RouteCollection object and context is a HttpContextBase object.
I assume you want to do this outside of your MVC application, where requests and contexts are not available (only the log files, as you mentioned).
Unfortunately, that is not very easy to do. In order to write such a matching method you need to reuse (or worse, rewrite) the MVC framework code for URL parsing found in various classes in namespace System.Web.Http.Routing. The source code is available on CodePlex, under Apache 2.0 license.
Instead, I think there's an easier way you can include the route names in the log files and use them later in statistics. Have a look below.
What you could to do is extend the default MvcHandler class and override its ProcessRequest method. In there, you can call the base class implementation and right after it do your stuff by using RequestContext.RouteData.
The class RouteData contains, besides other things, also the current route (which you defined in your route collection. That is accessible through the RouteData.Route property.
This works because MvcHandler is always delegated (unless you've created your own MVC infrastructure) by the MvcRouteHandler, to handle the processing for each request. It is the one that gets the controller data from the existing route data, instantiates an IController implementation, and ultimately executes it.
Just a quick question, when you create a new controller for a new MVC ASP.Net app how does it know which controller to use. More specifically, given you create a new controller and you call it SockController in order to use said controller I would navigate to http://mywebapp/sock. How did the web app know that /Sock/ is linked to SockController? Is there a mapping somewhere ? Or if not what happens when if you call omit controller from the name when creating it, ie call it SockCont.
Note: I am not a Web Dev im just curious so please don't post links to page with tons of text, im looking for a short simple answer.
ASP.NET Routing extracts the name of the controller from the URL by getting the Route Value and then appending "Controller" to the end. So "/home/" returns "HomeController".
ASP.NET then uses reflection to go through every class in the project's assembly (or referenced assemblies) to find a class that inherits from System.Web.Mvc.Controller and is called "HomeController". It then uses the default, parameterless constructor to create an instance of it.
It then matches the Route action to a method of the controller.
This process is called "Dispatch" and similar patterns are seen in PHP, Ruby-on-Rails, etc, except that dynamic languages like those have different ways of resolving class names to actual objects (CakePHP uses Class auto-loading bindings to locate the class definition, for example).