Asp.net MVC source code analysis-action parameterdescriptor

Source: Internet
Author: User

Next I will discuss the source code analysis of Asp.net MVC-the filter in action Idictionary <string, Object> parameters = getparametervalues (controllercontext, actiondescriptor );First, the purpose of this method is to get the name and value of the current action to a dictionary.

Protected virtual idictionary <string, Object> getparametervalues (controllercontext, actiondescriptor ){
Dictionary <string, Object> parametersdict = new dictionary <string, Object> (stringcomparer. ordinalignorecase );
Parameterdescriptor [] parameterdescriptors = actiondescriptor. getparameters ();

Foreach (parameterdescriptor in parameterdescriptors ){
 Parametersdict [parameterdescriptor. parametername] = getparametervalue (controllercontext, parameterdescriptor );
}
Return parametersdict;
}

ThisCodeThe logic is simple.ArticleWe know thatActiondescriptor is a reflectedactiondescriptor instance. We guess parameterdescriptor is a packaging class of paramete., The specific return should be its subclass. The getparameters method of is as follows:

Public override parameterdescriptor [] getparameters (){
 Parameterdescriptor [] parameters = lazilyfetchparameterscollection ();

// Need to clone array so that user modifications aren't accidentally stored
Return (parameterdescriptor [])Parameters. Clone ();
}

Private parameterdescriptor [] lazilyfetchparameterscollection (){
Return descriptorutil.Lazilyfetchorcreatedescriptors<Parameterinfo, parameterdescriptor> (
Ref _ parameterscache/* cachelocation */,
Methodinfo. getparameters/* initializer */,
Parameterinfo => New reflectedparameterdescriptor (parameterinfo, this)/* converter */);
}

1.LazilyfetchorcreatedescriptorsThis name is obtained directly if it exists. If it does not exist, it is created.

Public static tdescriptor [] handler (ref tdescriptor [] cachelocation, func initializer, func converter) {
// did we already calculate this once?
tdescriptor [] existingcache = interlocked. compareexchange (ref cachelocation, null, null);
If (existingcache! = NULL) {
return existingcache;
}

Treflection [] memberinfos = initializer ();
Tdescriptor [] descriptors = memberinfos. Select (converter). Where (descriptor => descriptor! = NULL). toarray ();
Tdescriptor [] updatedcache = interlocked. compareexchange (ref cachelocation, descriptors, null );
Return updatedcache ?? Descriptors;
}

Here, memberinfos = methodinfo. getparameters () is used to obtain all the parameters of the resource. Converter = new reflectedparameterdescriptor (parameterinfo, this) and reflectedparameterdescriptor constructors are as follows:

Public reflectedparameterdescriptor (parameterinfo, actiondescriptor ){
Parameterinfo = parameterinfo;
_ Actiondescriptor = actiondescriptor;
_ Bindinginfo = new reflectedparameterbindinginfo (parameterinfo );
}

Please note that the reflectedparameterdescriptor has an attribute, that is, defaultvalue.

Public override object defaultvalue {
Get {
Object value;
If (parameterinfoutil. trygetdefadefavalue (parameterinfo, out value )){
Return value;
}
Else {
Return base. defaultvalue;
}
}
}

Internal static class parameterinfoutil {public static bool trygetdefadefavalue (parameterinfo, out object value) {// This will get the default value as seen by the VB/C # compilers // if no value was baked in, rawdefaultvalue returns dbnull. value Object defaultvalue = parameterinfo. defaultvalue; If (defaultvalue! = Dbnull. value) {value = defaultvalue; return true;} // If the compiler did not bake in a default value, check the [defaultvalue] attribute defavaluvalueattribute [] attrs = (defaultvalueattribute []) parameterinfo. getcustomattributes (typeof (defaultvalueattribute), false); If (attrs = NULL | attrs. length = 0) {value = default (object); Return false;} else {value = attrs [0]. value; return true ;}}}

This code mainly refers to finding the parameterinfo of the object first. defaultvalue. If it is not null, set value = parameterinfo. defaultvalue and return true. If no value is found, check whether the parameter has the defavaluvalueattribute attribute. If yes, return the value = attrs [0]. value and return true; otherwise, value = default (object) and return false. If false is returned, the defaultvalue of reflectedparameterdescriptor returns NULL. From this code, we need to note thatDeclare that the default parameter should be written as public actionresult index (string name = "majiang") instead of public actionresult index ([defaultvalue ("majiang")] string name)
Now let's take a look at the one in the constructor.ReflectedparameterbindinginfoIn the parameter binding process, not all parameters need to be bound to data, and write parameters do not need to be bound to Data.

The main code of reflectedparameterbindinginfo is as follows:

Public reflectedparameterbindinginfo (parameterinfo) {
_ parameterinfo = parameterinfo;
encrypt ();
}< br> private void readsettingsfrombindattribute () {
bindattribute ATTR = (bindattribute) attribute. getcustomattribute (_ parameterinfo, typeof (bindattribute);
If (ATTR = NULL) {
return;
}

_ Exclude = new readonlycollection <string> (authorizeattribute. splitstring (ATTR. Exclude ));
_ Include = new readonlycollection <string> (authorizeattribute. splitstring (ATTR. Include ));
_ Prefix = ATTR. prefix;
}

The readsettingsfrombindattribute method mainly obtains the bindattride of the parameter to initialize the exclude exclusion parameter. The include includes the parameter. This class also has a special attribute.
Public override imodelbinder BinderThis will be explained later.
By default, or in general cases (simple type), we do not consider any exclusion parameter. The bindattribute obtained is null.

Now we have a set of packaging objects for Parameters of action.Parameterdescriptor [].The same action indicates that you call multiple times so that they do not affect each other. Therefore, we need to clone this parameterdescriptor [] set.(Parameterdescriptor []) parameters. Clone ();

The next step is to obtain the real value based on parameterdescriptor. Call the getparametervalue method.

Protected virtual object getparametervalue (controllercontext, parameterdescriptor) {// collect all of the necessary binding properties type parametertype = parameterdescriptor. parametertype; imodelbinder binder = getmodelbinder (parameterdescriptor); ivalueprovider valueprovider = controllercontext. controller. valueprovider; string parametername = parameterdescr Iptor. bindinginfo. prefix ?? Parameterdescriptor. parametername; predicate <string> propertyfilter = getpropertyfilter (parameterdescriptor); // Finally, call into the binder modelbindingcontext bindingcontext = new modelbindingcontext () {fallbacktoemptyprefix = (parameterdescriptor. bindinginfo. prefix = NULL), // only fall back If prefix not specified modelmetadata = modelmetadataproviders. current. getmetadatafortype (null, para Metertype), modelname = parametername, modelstate = controllercontext. controller. viewdata. modelstate, propertyfilter = propertyfilter, valueprovider = valueprovider}; object result = binder. bindmodel (controllercontext, bindingcontext); return result ?? Parameterdescriptor. defaultvalue ;}

in this Code, the value is obtained through the binder. bindmodel method. If no value is found, parameterdescriptor. defaultvalue is returned. The binder. bindmodel method is very complex and requires imodelbinder, ivalueprovider, and modelmetadataprovider. So we will put them in the next sections to explain them in a unified way.

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.