asp.net mvc-controllerl article controllerdescriptor_ practical skills

Source: Internet
Author: User
Now let's look at the definition of the Actioninvoker attribute:
Copy Code code as follows:

Public Iactioninvoker Actioninvoker {
get {
if (_actioninvoker = = null) {
_actioninvoker = Createactioninvoker ();
}
return _actioninvoker;
}
set {
_actioninvoker = value;
}
}
Protected virtual Iactioninvoker Createactioninvoker () {
return new Controlleractioninvoker ();
}

As with the Tempdataprovider attribute definition, you must get used to the code.
And the definition of controlleractioninvoker is simple, but this class is not simple.
Let's take a look at your invokeaction definition:
Copy Code code 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 should 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-Response.Redirect (), but we special-case so
The Filters don ' t is as an error.
Throw
}
catch (Exception ex) {
Something blew up and so execute the exception filters
Exceptioncontext Exceptioncontext = Invokeexceptionfilters (ControllerContext, Filterinfo.exceptionfilters, ex);
if (!exceptioncontext.exceptionhandled) {
Throw
}
Invokeactionresult (ControllerContext, Exceptioncontext.result);
}

return true;
}

Notify controller that no method matched
return false;
}

The contents of this method can not be finished once, we look at controllerdescriptor controllerdescriptor = Getcontrollerdescriptor (ControllerContext);
Obviously Controllerdescriptor is a wrapper class for the controller instance.
Copy Code code 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 return is a Reflectedcontrollerdescriptor instance, which is a subclass of Controllerdescriptor, Descriptorcache.getdescriptor ( ... It seems to be getting from the cache ah, let's prove it, first look at the Controllerdescriptorcache GetDescriptor method:
Copy Code code as follows:

Internal sealed class Controllerdescriptorcache:readerwritercache<type, controllerdescriptor> {
Public Controllerdescriptor GetDescriptor (Type controllertype, func<controllerdescriptor> creator) {
Return Fetchorcreateitem (Controllertype, creator);
}
}

Fetchorcreateitem method is very simple, get controllerdescriptor from the cache, if not to create and add to the cache and then return, the cache implementation is actually a dictionary dictionary<tkey, TValue >.
Now look at the reflectedcontrollerdescriptor of the function is there anything special:
_controllertype = Controllertype;
_selector = new Actionmethodselector (_controllertype);
How come there is actionmethodselector this dongdong ah, its constructor is as follows
Copy Code code 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.except (aliasedmethods). ToLookup (method => method. Name, stringcomparer.ordinalignorecase);
}

This method is very simple, find all the instances of controllertype, common methods, and then the filter is not action, and finally the action methods are divided into two parts, some aliases, some have no alias.
Now that we've got the Controllerdescriptor instance, here's a look at actiondescriptor actiondescriptor = findaction (ControllerContext, Controllerdescriptor, ActionName); Again, we can confirm that Actiondescriptor is actually a wrapper class for the action.
Protected virtual Actiondescriptor findaction (ControllerContext controllercontext, Controllerdescriptor Controllerdescriptor, String ActionName) This method is actually called
Controllerdescriptor class Findaction method, let's take a look at your Reflectedcontrollerdescriptor Findaction method, which is very simple, the group should be 2 code:
Copy Code code as follows:

MethodInfo matched = _selector. Findactionmethod (ControllerContext, actionname);
Return to new Reflectedactiondescriptor (matched, actionname, this);

_selector. Findactionmethod (ControllerContext, actionname); This is to find the methodinfo that we need the action to correspond to.
Copy Code code 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);
}
}

Loop through each MethodInfo to find their custom actionmethodselectorattribute attributes if there is only one attribute that returns validation. See Reflectedattributecache.getactionmethodselectorattributes (MethodInfo) code like this because of caching-related,
Copy Code code 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));
}

Reflectedattributecache This class has several cached dictionaries:
Concurrentdictionary<methodinfo, readonlycollection<actionmethodselectorattribute>>
Concurrentdictionary<methodinfo, readonlycollection<actionnameselectorattribute>>
Concurrentdictionary<methodinfo, readonlycollection<filterattribute>>
Concurrentdictionary<type, readonlycollection<filterattribute>>
The default implementation of the Actionmethodselectorattribute class mainly has the following several
Acceptverbsattribute
Httpdeleteattribute
Httpgetattribute
Httppostattribute
Httpputattribute
Nonactionattribute
Acceptverbsattribute
The rest is a direct instance of a Reflectedactiondescriptor object, which is nothing special, except that there is a validation method
Copy Code code as follows:

if (Validatemethod) {
String failedmessage = Verifyactionmethodiscallable (MethodInfo);
if (failedmessage!= null) {
throw new ArgumentException (Failedmessage, "methodInfo");
}
}

Used to verify that the method can be executed, the following conditions are not passed, (1) The method is the instance type of the static method (2) method is not controllerbase (3) containing generic parameters such as public ActionResult index<t> () is illegal, but public actionresult Index (list<string> aa) is a valid (4) parameter cannot contain ref and out.
This article is very loose, we need to pay attention to a little bit Microsoft in MVC cache does well, in the previous will get Controllertyper it is cached, read the current assembly all Controllertype, Mentioned here is a descriptorcache cache each invocation of the Controllertype->reflectedcontrollerdescriptor, The Reflectedcontrollerdescriptor instance reads all the action methods of the controller at a time; here's another reflectedattributecache. Cache all attributes (Actionmethodselectorattribute, Actionnameselectorattribute, FilterAttribute) for each call to MethodInfo. Of course FilterAttribute properties can also be on the class.

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.