When ASP. net mvc submits arrays through JQuery Ajax, the model binder Mechanism of MVC becomes invalid. We have to write custom code in the Controller to convert the data submitted by the Request to the required data type. This process is often boring. The following uses a project as an example to demonstrate how to solve this problem and provide a general solution.
Requirement Description
When the user changes the configuration, Ajax must be submitted to the server.
Front-end code:
- var items = [];
- $("input:checked").each(function () {
- items.push($(this).val());
- });
- $.ajax({
- type: 'post',
- url: 'Configure/Status',
- data: { answers: items }
- });
Backend code:
- public enum AnswerStatus
- {
- Correct = 1,
- Incorrect = 2,
- Unanswered = 3
- }
- [HttpPost]
- public ActionResult Status(IList<AnswerStatus> answers)
- {
- ….
- }
Here, answers is always null. The fiddler is used. It is found that the Array data is submitted using JQuery. Ajax, and "[]" is always added after the name during submission. The problem lies here.
Modify the code based on the discovered results:
- [HttpPost]
- public ActionResult Status(IList<AnswerStatus> answers)
- {
- answers = Request.Form.GetValues(“answers[]”).Select(d => d.ToEnum<AnswerStatus>(AnswerStatus.Unanswered).ToList();
- }
Although this can solve my problem, every time I submit an Array, I need to manually parse the request, and it will take a night to return to the stone age. In fact, we will immediately think of the MVC Mode Binder.
Try to perform the first refactoring:
- public class AnswerModelBinder : IModelBinder
- {
- public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
- {
- return controllerContext.RequestContext.HttpContext.Request.Form.GetValues(“answers[]”).Select(d => d.ToEnum<AnswerStatus>(AnswerStatus.Unanswered).ToList();
- }
- }
Hard coding tastes too heavy. You have to change the type and rewrite it. The workload is much higher than before, but the Controller becomes more elegant. This kind of waste of youth and power consumption still does not meet the requirements.
Perform the second reconstruction: ultmodelbinder appears
The omnipotent defamodelmodelbinder can be bound to any type. Unfortunately, "[]" is added after the name passed by the client, which makes the defamodelmodelbinder unable to be accurately parsed. Can we cheat defamodelmodelbinder?
You can view ModelBindingContext and find that there is a ModelName attribute, which is a bit like the name of the parameter to be bound. The debug trail finds that ModelName is indeed the name of the parameter, then we modify the ModelName so that it is consistent with the name passed by the client to make full use of defamodelmodelbinder. Create a JQAjaxModelBinder
And inherit from defamodelmodelbinder:
- Public override object BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext)
- {
- If (bindingContext. ModelType. IsEnumerable ())
- {
- Var key = bindingContext. ModelName + "[]";
- Var valueResult = bindingContext. ValueProvider. GetValue (key );
- If (valueResult! = Null &&! String. IsNullOrEmpty (valueResult. AttemptedValue ))
- {
- BindingContext. ModelName = key;
- }
- }
- Return base. BindModel (controllerContext, bindingContext );
- } // How to use custom ModelBinder. This method is the Action in the Controller.
- Public ActionResult Status ([ModelBinder (typeof (ModelBinder. JQAjaxModelBinder)] IList <AnswerStatus> answers)
- {
- ...
- }
At this time, the Status Action Method in the Controller can correctly obtain the data sent from the front-end. It is also strongly typed. Of course, many programmers are lazy, and I am also a part of it. I don't even want to write the Parameter [ModelBinder (typeof (ModelBinder. JQAjaxModelBinder)]) before Parameter. Let's register it directly in ModelBinders. In fact, it is a little troublesome during registration. You must set the Type. I can know the types in advance. Simply set JQAjaxModelBinder to the default ModerBinder. Once and for all, there will be no worries.
ModelBinder different registration methods
Add the ModelBinder label before the parameter of the Action method. The preceding method is used.
Add the ModelBinder label to the data type.
- [ModelBinder(typeof(ModelBinder.JQAjaxModelBinder))]
- Public class User
- {
- }
Register through ModelBinders
- ModelBinders.Binders.Add(typeof(User), new ModelBinder.JQAjaxModelBinder());
Set the default ModerBinder
- ModelBinders.Binders.DefaultBinder = new ModelBinder.JQAjaxModelBinder();
Note: When we are developing, we often repeat things. When one thing is repeated multiple times, we need to stop and think carefully. Can we abstract these things, what about a general solution? Solve these problems once and for all.
Link: http://www.cnblogs.com/coolite/archive/2012/12/24/JQModelBinder.html
Edit recommendations]