Reading directory:
1. Introduction
2. ASP. NETMVC IControllerFactory controller factory Interface
3. ASP. NETMVC DefaultControllerFactory default controller Factory
4. ASP. NETMVC ControllerBuilder controller creation portal settings
5. ASP. NETMVC custom IControllerFactory
1. Introduction
The previous article ". NET/ASP. net mvc Controller 1: in-depth analysis of Controller operating principles) "describes in detail the basic process logic inside the MvcHandler object. This basic process logic paves the way for us to learn later, when we can understand the internal execution process correctly, we can explore the detailed logic in each logical link;
Based on the introduction in the previous two articles, we can basically figure out how a Url request usesUrlRoutingModuleThe module passes through ASP smoothly. NET basic framework arrives at the application framework. After UrlRoutingModule completes processing, the RouteData object is encapsulated in the RequestContext request context and passed to the MvcHandler object, then the MvcHandler object uses the IControllerFactory interface to create a specific IController object instance based on the controllername controller name string obtained from RouteData;
We are clear about the basic process, but we are not very clear about what is happening behind IControllerFactory. Who is implemented as IControllerFactory by default, it also has an extension portal for us to expand the creation process, which is worth exploring;
In this article, let's analyze what happened behind IControllerFactory and whether we can learn any design ideas;
2] ASP. NETMVC IControllerFactory controller factory Interface
Since the ControllerFactory can be extracted from the interface, the IController creation will be a very loose process; simply imagine that if the Factory is not proposed to the interface, therefore, the creation of IController is a very intuitive process, but ASP. NETMVC does not simply use a ControllerFactory to create IController, but rather loose the design of the creation process to facilitate scalability, in other words, we can define a Factroy to replace the creation process, or extend it based on the Factroy in the system;
MvcHandler uses IControllerFactroy to create the corresponding IController object. First, we need to figure out how MvcHandler gets the IControllerFactory interface;
In fact, MvcHandler does not directly use the implementation of IControllerFactroy, but usesControllerBuilderThe implementation of a singleton mode. MvcHanlder obtains an instance through the ControllerBuilder object, and then creates an IControllerFactory implementation through ControllerBuilder;
internal ControllerBuilder ControllerBuilder { get { if (_controllerBuilder == null) { _controllerBuilder = ControllerBuilder.Current; } return _controllerBuilder; } set { _controllerBuilder = value; }}factory = ControllerBuilder.GetControllerFactory();
It can be simply understood that ControllerBuilder manages the IControllerFactory creation process. MvcHanlder obtains the global instance of ControllerBuilder and calls its method GetControllerFactory to obtain the IControllerFactory implementation that can be used;
Figure 1:
650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131229/12405SP5-0.jpg "title =" 1.jpg" alt = "203435933.jpg"/>
ControllerBuilder's design is clever. It opens the door to implementation of IControllerFactory. We can do many things through this portal;
Let's take a look at the definition of the IControllerFactroy interface:
public interface IControllerFactory { IController CreateController(RequestContext requestContext, string controllerName); SessionStateBehavior GetControllerSessionRequestContext requestContext, string controllerName); void ReleaseController(IController controller);}
The interface defines three methods. The first method, CreateController, is easy to understand. The Controller instance is created based on the second parameter controllerName of the method; the second method, GetControllerSessionBehavior, is used to obtain the Session behavior of the Controller represented by controllerName. This behavior is represented by the SessionStateAttribute feature. The third method, ReleaseController, is used to release the Controller at last:
public virtual void ReleaseController(IController controller) { IDisposable disposable = controller as IDisposable; if (disposable != null) { disposable.Dispose(); }}
Since the Controller inherits the IDisposable interface, the Dispose method is called directly inside the method to release resources. Note that the Controller implements the IDisposable interface with the virtual modifier:
protected virtual void Dispose(bool disposing) {}
This makes it easy for us to release some other resources by rewriting this method;
3] ASP. NETMVC DefaultControllerFactory default controller Factory
In ASP. NETMVC, there is a default factroydefacontrocontrollerfactroy). DefaultControllerFactroy implements the core IController code creation, which provides a good interface for our extension;
Call the CreateController (RequestContext requestContext, string controllerName) method of the IControllerFactory interface to go to The DefaultControllerFactory implementation. The first task is to find the corresponding ContorllerType according to the controllerName, then you can create a specific instance;
object routeNamespacesObj;Type match;if (requestContext != null && requestContext.RouteData.DataTokens.TryGetValue("Namespaces", out routeNamespacesObj)) { IEnumerable<string> routeNamespaces = routeNamespacesObj as IEnumerable<string>; if (routeNamespaces != null && routeNamespaces.Any()) { HashSet<string> nsHash = new HashSet<string>(routeNamespaces, StringComparer.OrdinalIgnoreCase); match = GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, nsHash); // the UseNamespaceFallback key might not exist, in which case its value is implicitly "true" if (match != null || false.Equals(requestContext.RouteData.DataTokens["UseNamespaceFallback"])) { // got a match or the route requested we stop looking return match; } }}
First, find the configured namespace set based on the requested route data RouteData, and then use the namespace and controller name to obtain the Type! = Null. If the namespace is not enabled, Type is directly returned;
3.1] AreaRegistration namespace in Controller
Two groups of namespaces are used internally in defacontrocontrollerfactroy to find the Controller NameSpace. The first one is set when we configure the Route data:
context.MapRoute(name: "api.order.default", url: "api/order/{controller}/{action}/{orderid}", defaults: new { controller = "OrderController", action = "GetOrderOperationDatetime", orderid = "1001" }, namespaces: new string[] { "Api.Order" });
The second one is generally not used. It exists as an AreaRegistration backup namespace and is set in ControllerBuilder:
ControllerBuilder.Current.DefaultNamespaces.Add("MvcApplication4.ApiOrder");
The reserved namespace is assigned in the MapRoute (string name, string url, object ults, object constraints, string [] namespaces) method of AreaRegistrationContext:
if (namespaces == null && Namespaces != null) { namespaces = Namespaces.ToArray();}Route route = Routes.MapRoute(name, url, defaults, constraints, namespaces);route.DataTokens["area"] = AreaName;// disabling the namespace lookup fallback mechanism keeps this areas from accidentally picking up// controllers belonging to other areasbool useNamespaceFallback = (namespaces == null || namespaces.Length == 0);route.DataTokens["UseNamespaceFallback"] = useNamespaceFallback;return route;
Because AreaRegistration can make our Controller design not limited to ASP. NETMVCWeb programs, but can implement modular design independently of the Controller, we need to provide a special namespace Search Method for the Area;
4] ASP. NETMVC ControllerBuilder controller creation portal settings
ControllerBuilder serves as the entry to the settings created by the Controller. It can be used to set ControllerFactory to replace the default DefaultControllerFactory. ControllerBuilder is the entry to the Framework extension of the Controller creation process. You can use ControllerBuilder to easily complete many settings;
internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver) { _serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>( () => _factoryThunk(), new DefaultControllerFactory { ControllerBuilder = this }, "ControllerBuilder.GetControllerFactory" );}
In the constructor of ControllerBuilder, a Resolver of the SingleServiceResolver <IControllerFactory> type is initialized to obtain the IOC mode of the Factory. In the code, an instance of the DefaultControllerFactory type is instantiated as the default Factory. It is important to set ControllerBuilder as a parameter to the ControllerBuilder attribute so that it can be used later when parsing the Controller namespace;
public HashSet<string> DefaultNamespaces { get { return _namespaces; }}
Here we can set a uniform namespace, because we need to set namesapce fields when setting the Route, but it is very troublesome if there are many such Route fields, we can use this method for unified settings;
public void SetControllerFactory(IControllerFactory controllerFactory) { if (controllerFactory == null) { throw new ArgumentNullException("controllerFactory"); } _factoryThunk = () => controllerFactory;}
Another important thing is to set the custom ControllerFactory. In the SetControllerFactory method, we can set an IControllerFactory object to take over the default DefaultControllerFactory object, including all the subsequent IController cache policies;
Figure 2:
650) this. length = 650; "src =" http://www.bkjia.com/uploads/allimg/131229/12405W493-1.jpg "title =" 2.jpg" width = "600" height = "229" border = "0" hspace = "0" vspace = "0" style = "width: 600px; height: 229px; "alt =" 203726859.jpg"/>
Basically, we can use ControllerBuilder to go to the process of creating ControllerFactroy, and use the SetControllerFactory method to directly pass in our custom IControllerFactroy;
5] ASP. NETMVC custom IControllerFactory
Now that we know that ContollerBulder allows us to change the default controller factory of the system, how can we use the current Factroy? In general, we only need to inherit from DefaultControllerFactory and then perform corresponding extension;
public class CustomControllerFactory : DefaultControllerFactory{ protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) { Console.WriteLine(string.Format("{0}is create.", controllerType.Name)); return base.GetControllerInstance(requestContext, controllerType); }}
Now let's assume that we need to record the created record information when the system creates all controllers, which is convenient. We only need to set it at the place where the system is initialized:
ControllerBuilder.Current.SetControllerFactory(new Api.Order.CustomControllerFactory());
In this way, some functions of ControllerFactory are taken over;
Author:Wang qingpei
Source:Http://wangqingpei557.blog.51cto.com/
The copyright of this article is shared by the author and BKJIA. You are welcome to repost this article. However, you must retain this statement without the author's consent and provide the original article connection clearly on the article page. Otherwise, you will be entitled to pursue legal liability.