Learning the secrets of ASP. NET MVC5 framework-How ASP. net mvc runs (III)

Source: Internet
Author: User

Learning the secrets of ASP. NET MVC5 framework-How ASP. net mvc runs (III)
Controller Activation

ASP. net mvc routing system implements route resolution for the current HTTP request through the registered route table to obtain a RouteData object used to encapsulate route data, this process is implemented by registering the PostResolveRequestCache event of HttpApplication using the custom UrlRoutingModule. Because the RouteData object contains the name of the target Controller, we need to activate the corresponding Controller object based on the name.

1. MvcRouteHandler

Based on the previous introduction, we know that the Route type inherited from RouteBase has an attribute RouteHandler of the IRouteHandler type. Its main purpose is to use it according to the specified request context (RequestContext) to obtain an HttpHandler object. When the GetRouteData method is executed, the RouteHandler attribute value of Route is reflected in the Same Name attribute of RouteData. By default, the RouteHandler attribute of Route is an MvcRouteHandler object.

For our "mini version" ASP. net mvc Framework, MvcRouteHandler is a type with the following definitions. In the implemented GetHttpHandler method, it will directly return an MvcHandler object.

 

public class MvcRouteHandler : IRouteHandler    {        public IHttpHandler GetHttpHandler(RequestContext requestContext)        {            return new MvcHandler(requestContext);        }    }

 

2. MvcHandler

The entire ASP. net mvc framework is implemented by using custom HttpModule and HttpHandler to access ASP.. NET extension. The custom HttpModule type is UrlRouteModule, And the custom HttpHandler type is the MvcHandler that needs to be highlighted.

After using the route table to parse the current request and obtain the RouteData object that encapsulates the route data, the UrlRouteModule calls its RouteHandler's GetHttpHandler method to obtain an HttpHandler object, then map it to the current HTTP context. Because the RouteHandler of RouteData comes from the RouteHandler of the corresponding Route object, and the latter is an MvcRouteHandler object by default, it is such an MvcHandler object that is used to process HTTP requests by default. MvcHandler activates the Controller object and executes the target Action method.

As shown in the following code snippet, MvcHandler has an attribute of the RequestContext type, which indicates the current request context, which is specified in the constructor. MvcHandler activates and executes the Controller object in the ProcessRequest method.

 

public class MvcHandler : IHttpHandler    {        public bool IsReusable        {            get { return false; }        }        public RequestContext RequestContext { get; private set; }         public MvcHandler(RequestContext requestContext)        {            this.RequestContext = requestContext;        }         public void ProcessRequest(HttpContext context)        {            string controllerName = this.RequestContext.RouteData.Controller;            IControllerFactory controllerFactory = ControllerBuilder.Current.GetControllerFactory();            IController controller = controllerFactory.CreateController(this.RequestContext, controllerName);            controller.Execute(this.RequestContext);        }    }


 

3. Controller and ControllerFactory

We have defined an IController interface for the Controller. As shown in the following figure, this interface has a unique method: Execute indicates the execution of the current Controller object. This method is called in the ProcessRequest method of MvcHandler, and the parameter passed in this method is the RequestContext object of the current request context.

 

public interface IController    {        void Execute(RequestContext requestContext);    }

 

From the definition of MvcHandler, we can see that the Controller object is activated through the factory mode, and we have defined the IControllerFactory interface for the factory that activates the Controller. This interface has a unique method CreateController, which activates the corresponding Controller object based on the current request context and the name of the target Controller obtained through route resolution.

 

 public interface IControllerFactory    {        IController CreateController(RequestContext requestContext, string controllerName);    }

 

In the ProcessRequest method of MvcHandler, he obtains the Current ControllerBuilder object through the static attribute Current of ControllerBuilder, and calls its GetControllerFactory method to obtain the Current ControllerFactory. MvcHandler obtains the name of the target Controller by extracting the RequestData object from RequestContext, and calls the CreateController method of ControllerFactory as a parameter together with RequestContext to create the target Controller object.

The entire definition of ControllerBuilder is as follows, indicating that the Current static read-only attribute of ControllerBuilder is created in the static constructor. Its SetControllerFactory and GetControllerFactory methods are used to register and obtain ControllerFactory.

 

public class ControllerBuilder    {        private Func
 
   factoryThunk;        public static ControllerBuilder Current { get; private set; }         static ControllerBuilder()        {            Current = new ControllerBuilder();        }         public IControllerFactory GetControllerFactory()        {            return factoryThunk();        }         public void SetControllerFactory(IControllerFactory controllerFactory)        {            factoryThunk = () => controllerFactory;        }    }
 

 

Previously we established a Web application in the Custom ASP. net mvc framework. We registered ControllerFactory through the current ControllerBuilder. The registered ControllerFactory type is DefaultControllerFactory.

 

public class Global : System.Web.HttpApplication    {        protected void Application_Start(object sender, EventArgs e)        {            ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory());        }    }


 

The DefaultControllerFactory type used as the default ControllerFactory is defined as follows. Because the premise of activating the Controller object is that the true type of the Controller can be correctly parsed, The controllerName as the input parameter of the CreateController method only indicates the name of the Controller, therefore, we need to add the Controller character suffix as the type name. When the DefaultControllerFactory type is loaded (the static constructor is called), he loads all referenced assembly through BuilderMessage, obtains all IController types that implement the interface, and caches it. In the CreateController method, DefaultControllerFactory obtains the corresponding Controller type from the list of saved Controller types based on the Controller name, and creates it through reflection.

 

public class DefaultControllerFactory : IControllerFactory    {        private static List
 
   controllerTypes = new List
  
   ();         static DefaultControllerFactory()        {            foreach (Assembly assembly in BuildManager.GetReferencedAssemblies())            {                foreach (Type type in assembly.GetTypes().Where(type => typeof(IController).IsAssignableFrom(type)))                {                    controllerTypes.Add(type);                }            }        }         public IController CreateController(RequestContext requestContext,string controllerName)        {            string typeName = controllerName + Controller;            Type controllerType = controllerTypes.FirstOrDefault(c => string.Compare(typeName, c.Name, true) == 0);            if (null == controllerType)            {                return null;            }            return (IController)Activator.CreateInstance(controllerType);        }    }
  
 

The above describes in detail the activation principle of the Controller, and now the focus is returned to the Controller itself. By implementing the IController interface, we define a ControllerBase abstract base class with the following definitions for all controllers, it can be seen that in the implemented Execute method, ControllerBase executes the Action method through an object that implements the interface IActionInvoker.

 

 

public abstract class ControllerBase : IController    {        protected IActionInvoker ActionInvoker { get; set; }         public ControllerBase()        {            this.ActionInvoker = new ControllerActionInvoker();        }         public void Execute(RequestContext requestContext)        {            ControllerContext context = new ControllerContext            {                RequestContext = requestContext,                Controller = this            };            string actionName = requestContext.RouteData.ActionName;            this.ActionInvoker.InvokeAction(context, actionName);        }    }
 

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.