Asp.net mvc-Controllerl ControllerDescriptor

Source: Internet
Author: User

Now let's take a look at the definition of the ActionInvoker attribute: Copy codeThe Code is as follows: public IActionInvoker ActionInvoker {
Get {
If (_ actionInvoker = null ){
_ ActionInvoker = CreateActionInvoker ();
}
Return _ actionInvoker;
}
Set {
_ ActionInvoker = value;
}
}
Protected virtual IActionInvoker CreateActionInvoker (){
Return new ControllerActionInvoker ();
}

Like the TempDataProvider attribute definition, you must get used to this code.
The definition of ControllerActionInvoker is also very simple, but this class is not simple.
Let's take a look at your InvokeAction definition:Copy codeThe Code is as follows: public virtual bool InvokeAction (ControllerContext controllerContext, string actionName ){
If (controllerContext = null ){
Throw new ArgumentNullException ("controllerContext ");
}
If (String. IsNullOrEmpty (actionName )){
Throw new ArgumentException (MvcResources. Common_NullOrEmpty, "actionName ");
}

ControllerDescriptor controllerDescriptor = GetControllerDescriptor (controllerContext );
ActionDescriptor actionDescriptor = FindAction (controllerContext, controllerDescriptor, actionName );
If (actionDescriptor! = Null ){
FilterInfo filterInfo = GetFilters (controllerContext, actionDescriptor );

Try {
AuthorizationContext authContext = InvokeAuthorizationFilters (controllerContext, filterInfo. AuthorizationFilters, actionDescriptor );
If (authContext. Result! = Null ){
// The auth filter signaled that we shocould let it short-circuit the request
InvokeActionResult (controllerContext, authContext. Result );
}
Else {
If (controllerContext. Controller. ValidateRequest ){
ValidateRequest (controllerContext );
}

IDictionary <string, object> parameters = GetParameterValues (controllerContext, actionDescriptor );
ActionExecutedContext postActionContext = InvokeActionMethodWithFilters (controllerContext, filterInfo. ActionFilters, actionDescriptor, parameters );
InvokeActionResultWithFilters (controllerContext, filterInfo. ResultFilters, postActionContext. Result );
}
}
Catch (ThreadAbortException ){
// This type of exception occurs as a result of Response. Redirect (), but we special-case so that
// The filters don't see this as an error.
Throw;
}
Catch (Exception ex ){
// Something blew up, so execute the exception filters
ExceptionContext exceptionContext = InvokeExceptionFilters (controllerContext, filterInfo. ExceptionFilters, ex );
If (! ExceptionContext. ExceptionHandled ){
Throw;
}
InvokeActionResult (controllerContext, exceptionContext. Result );
}

Return true;
}

// Policy controller that no method matched
Return false;
}

The content in this method cannot be completed at one time. Let's take a look at ControllerDescriptor controllerDescriptor = GetControllerDescriptor (controllerContext );
Obviously, ControllerDescriptor is a packaging class of the Controller instance.Copy codeThe Code is as follows: protected virtual ControllerDescriptor GetControllerDescriptor (ControllerContext controllerContext ){
Type controllerType = controllerContext. Controller. GetType ();
ControllerDescriptor controllerDescriptor = DescriptorCache. GetDescriptor (controllerType, () => new ReflectedControllerDescriptor (controllerType ));
Return controllerDescriptor;
}

From this method, we can know that the actual returned is a ReflectedControllerDescriptor instance, which is a subclass of ControllerDescriptor and DescriptorCache. getDescriptor (...) it seems to have been obtained from the cache. Let's verify it. Let's take a look at the GetDescriptor method of ControllerDescriptorCache:Copy codeThe Code is as follows: internal sealed class ControllerDescriptorCache: ReaderWriterCache <Type, ControllerDescriptor> {
Public ControllerDescriptor GetDescriptor (Type controllerType, Func <ControllerDescriptor> creator ){
Return FetchOrCreateItem (controllerType, creator );
}
}

The FetchOrCreateItem method is very simple. The ControllerDescriptor is obtained from the cache. If no ControllerDescriptor exists, it is created and added to the cache and then returned. The cache implementation method is actually a Dictionary <TKey, TValue>.
Now let's see if the ReflectedControllerDescriptor is special:
_ ControllerType = controllerType;
_ Selector = new ActionMethodSelector (_ controllerType );
Why does ActionMethodSelector exist? Its constructor is as follows:Copy codeThe Code is as follows: public ActionMethodSelector (Type controllerType ){
ControllerType = controllerType;
PopulateLookupTables ();
}
Private void PopulateLookupTables (){
MethodInfo [] allMethods = ControllerType. GetMethods (BindingFlags. InvokeMethod | BindingFlags. Instance | BindingFlags. Public );
MethodInfo [] actionMethods = Array. FindAll (allMethods, IsValidActionMethod );
AliasedMethods = Array. FindAll (actionMethods, IsMethodDecoratedWithAliasingAttribute );
NonAliasedMethods = actionMethods. Methods T (AliasedMethods). ToLookup (method => method. Name, StringComparer. OrdinalIgnoreCase );
}

This method is very simple. Find all the instances and common methods of ControllerType. Then, when filtering the call is not an Action, these Action methods are divided into two parts: one part has an alias, and the other part has no alias.
Now we have the ControllerDescriptor instance. Next we should look at the code of ActionDescriptor actionDescriptor = FindAction (controllerContext, controllerDescriptor, actionName). We can also confirm that ActionDescriptor is actually a packaging class of Action.
Protected virtual ActionDescriptor FindAction (ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) is actually called
The ControllerDescriptor class FindAction method. Let's take a look at your ReflectedControllerDescriptor's FindAction method. This method is very simple. The Group has to have two lines of code:Copy codeThe Code is as follows: MethodInfo matched = _ selector. FindActionMethod (controllerContext, actionName );
Return new ReflectedActionDescriptor (matched, actionName, this );

_ Selector. FindActionMethod (controllerContext, actionName); find the MethodInfo corresponding to the Action.Copy codeThe Code is as follows: public MethodInfo FindActionMethod (ControllerContext controllerContext, string actionName ){
List <MethodInfo> methodsMatchingName = GetMatchingAliasedMethods (controllerContext, actionName );
MethodsMatchingName. AddRange (NonAliasedMethods [actionName]);
List <MethodInfo> finalMethods = RunSelectionFilters (controllerContext, methodsMatchingName );

Switch (finalMethods. Count ){
Case 0:
Return null;

Case 1:
Return finalMethods [0];

Default:
Throw CreateAmbiguousMatchException (finalMethods, actionName );
}
}

Cycle each MethodInfo to find their custom ActionMethodSelectorAttribute. If any, only the features that pass verification are returned. The Code such as ReflectedAttributeCache. GetActionMethodSelectorAttributes (methodInfo) is determined by the cache,Copy codeThe Code is as follows: private static ReadOnlyCollection <TAttribute> GetAttributes <TMemberInfo, TAttribute> (ConcurrentDictionary <TMemberInfo, ReadOnlyCollection <TAttribute> lookup, TMemberInfo memberInfo)
Where TAttribute: Attribute
Where TMemberInfo: MemberInfo {
Return lookup. GetOrAdd (memberInfo, mi => new ReadOnlyCollection <TAttribute> (TAttribute []) memberInfo. GetCustomAttributes (typeof (TAttribute), inherit: true )));
}

The ReflectedAttributeCache class has several cache dictionaries:
ConcurrentDictionary <MethodInfo, ReadOnlyCollection <ActionMethodSelectorAttribute>
ConcurrentDictionary <MethodInfo, ReadOnlyCollection <ActionNameSelectorAttribute>
ConcurrentDictionary <MethodInfo, ReadOnlyCollection <FilterAttribute>
ConcurrentDictionary <Type, ReadOnlyCollection <FilterAttribute>
The default ActionMethodSelectorAttribute class includes the following:
AcceptVerbsAttribute
HttpDeleteAttribute
HttpGetAttribute
HttpPostAttribute
HttpPutAttribute
NonActionAttribute
AcceptVerbsAttribute
The rest is to directly instance a ReflectedActionDescriptor object. This is nothing special, but there is a verification method in it.Copy codeThe Code is as follows: if (validateMethod ){
String failedMessage = VerifyActionMethodIsCallable (methodInfo );
If (failedMessage! = Null ){
Throw new ArgumentException (failedMessage, "methodInfo ");
}
}

It is used to verify whether the method can be executed. In the following cases, it is not passed. (1) The method is a static method. (2) The instance type of the method is not ControllerBase (3) whether to include a generic parameter such as public ActionResult Index <T> () is invalid, but public ActionResult Index (List <string> aa) is legal (4) the parameter cannot contain Ref and out.
This article is very scattered. We need to note that Microsoft caches well in mvc. When the previous one gets ControllerTyper, it has a cache, read all controllertypes of the current Assembly at a time. Here we mention a DescriptorCache cache that caches the ControllerType-> ReflectedControllerDescriptor called each time, while the ReflectedControllerDescriptor instance reads all the Action methods of the Controller at a time; there is also a ReflectedAttributeCache, which caches all features of MethodInfo (ActionMethodSelectorAttribute, ActionNameSelectorAttribute, and FilterAttribute) each call. Of course, the FilterAttribute feature can also be in the class.

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.