These days old feel wrong, always feel less what, today only found, in front 3 inside, in get action parameter information, less parse. There is a more important thing in it. The same is true for today's watch.
In the Invokeaction () method, there is a code:
idictionary<stringobjectthis. Getparametervalues (ControllerContext, actiondescriptor);
This is used to get the parameters. So is the parameter freely available? In MVC, when the page to the action, there is no attempt to pass an array, and then receive the time, also directly parse the group? Or to receive more complex types?
The answer is in this article. First look at the source code.
protected Virtualidictionary<string,Object>getparametervalues (ControllerContext controllercontext,
Actiondescriptor actiondescriptor) {Dictionary<string,Object> dictionary =Newdictionary<string,Object>(stringcomparer.ordinalignorecase); foreach(Parameterdescriptor DescriptorinchActiondescriptor. GetParameters ()) {Dictionary[descriptor. ParameterName]= This. Getparametervalue (ControllerContext, descriptor); } returndictionary;}
First, source code analysis
1. Actiondescriptor.getparameters ()
// System.Web.Mvc.ReflectedActionDescriptor Public Override parameterdescriptor[] GetParameters () { return actiondescriptorhelper.getparameters ( This isrefthis. _parameterscache);}
This should be to get all the parameters and their descriptive information.
2. This. Getparametervalue ()--Main method
protected Virtual ObjectGetparametervalue (ControllerContext ControllerContext,
Parameterdescriptor parameterdescriptor) {Type parametertype=Parameterdescriptor.parametertype;
//Parameter description to get the processing interface of the parameter Imodelbinder Modelbinder= This. Getmodelbinder (Parameterdescriptor); Ivalueprovider Valueprovider=ControllerContext.Controller.ValueProvider; stringstr = ParameterDescriptor.BindingInfo.Prefix??Parameterdescriptor.parametername;
//Get the filter above the parameter and put it in the parameter parsing context below (Modelbindingcontext) predicate<string> propertyfilter = getpropertyfilter(parameterdescriptor); Modelbindingcontext BindingContext=NewModelbindingcontext {fallbacktoemptyprefix= ParameterDescriptor.BindingInfo.Prefix = =NULL, Modelmetadata= ModelMetadataProviders.Current.GetMetadataForType (NULL, ParameterType), ModelName=str, modelstate=controllerContext.Controller.ViewData.ModelState, propertyfilter = propertyfilter, valueprovider=Valueprovider};
//handler for execution parameters return(Modelbinder.Bindmodel(ControllerContext, BindingContext)??parameterdescriptor.defaultvalue);}
2.1 Getmodelbinder () method
Private imodelbinder Getmodelbinder (parameterdescriptor parameterdescriptor) { return
This . Binders.getbinder (Parameterdescriptor.parametertype));}
Here is the processing interface to get the parameters according to the parameter description
Public Interface imodelbinder{ // Methods object Bindmodel (ControllerContext controllercontext, Modelbindingcontext bindingcontext);}
2.2 Bindmodel () method-Here you see Defaultmodelbinder, which will customize a
Public Virtual ObjectBindmodel (ControllerContext controllercontext, Modelbindingcontext BindingContext) { Ensurestackhelper.ensurestack (); if(BindingContext = =NULL) { Throw NewArgumentNullException ("BindingContext"); } BOOLFlag =false; if(!string. IsNullOrEmpty (Bindingcontext.modelname)
&&!BindingContext.ValueProvider.ContainsPrefix (Bindingcontext.modelname)) { if(!bindingcontext.fallbacktoemptyprefix) {return NULL; } Modelbindingcontext Context=NewModelbindingcontext {modelmetadata=Bindingcontext.modelmetadata, Modelstate=bindingcontext.modelstate, PropertyFilter=Bindingcontext.propertyfilter, Valueprovider=Bindingcontext.valueprovider}; BindingContext=context; Flag=true; } if(!flag) { BOOLFlag2 =shouldperformrequestvalidation (ControllerContext, BindingContext); BOOLSkipvalidation =!Flag2; Valueproviderresult Valueproviderresult=Bindingcontext.unvalidatedvalueprovider
. GetValue (Bindingcontext.modelname, skipvalidation); if(Valueproviderresult! =NULL) {
//Return parameter values for simple objects return This. Bindsimplemodel (ControllerContext, BindingContext, Valueproviderresult); } } if(!bindingContext.ModelMetadata.IsComplexType) {return NULL; } return This. Bindcomplexmodel (ControllerContext, BindingContext);}
This is a bit more content, but also a bit complex, in fact, the resolution here, almost already get what I want.
Second, custom Modelbinder
1. Imodelbinder-for relatively simple types, you can use this method
Start by creating a slightly more complex class.
Public enumgenderenum{Female, Male, unknow} Public classextinfo{ Public stringQQ {Get;Set; } Public stringPhone {Get;Set; }} Public classuser{
//The constructor here, I created a extinfo instance, otherwise, this Extinfo object is empty, affecting my demo PublicUser () {Extension=NewExtinfo (); }
Public intId {Get;Set; } Public stringName {Get;Set; } PublicGenderenum Gender {Get;Set; } PublicExtinfo Extension {Get;Set; }}
Next, take a look at the controller code
Public class modelcontroller:controller{ public actionresult Get (user user) { return View (user); Public ActionResult Index ([modelbinder(typeof(modelindexbinder))]user User) { return View (user);} }
The part of the controller that needs attention, I'm already marked red. Next look at my custom modelbinder.
Public class modelindexbinder : imodelbinder{ Public ObjectBindmodel (ControllerContext controllercontext, Modelbindingcontext bindingcontext) {varRequest =controllerContext.HttpContext.Request; User User=NewUser {Id= Convert.ToInt32 (Request. params["Id"]), Name= Request. params["Name"]. ToString (), Gender= (genderenum) convert.toint32 (request. params["Gender"]), Extension=NewExtinfo {QQ= Request. params["QQ"]. ToString (), Phone= Request. params["Phone"]. ToString ()}}; returnuser; }}
Let's take a look at the effect of two methods.
Note: Here is a different way to achieve the purpose, only need to modify the URL can be:
http://localhost:11620/model/get?id=1&name=haha&gender=0&extension.qq= 123123123&extension.phone=12312341234
Here is to give an example, only to do so.
For relatively simple, with Imodelbinder is very convenient, but for a little more complex, you can achieve defaultmodelbinder to achieve.
But this part of the implementation is not resolved, I temporarily useless.
Generally for URL get requests, it is not very complex, only when you use the POST request, you will encounter more complex processing methods. But for this kind of complex processing, there is a more common way, is to use the way of deserialization, I commonly used is newtonsoft.
Reference:
MVC extension
Dive into ASP. NET MVC
Directory is synchronized
MVC Source Analysis-Modelbinder binding/Custom data binding