First, the problem of wonderful flowers
Before I built the wheel, encountered a very strange problem, although the demand is very wonderful, but still try to solve the
When a submitted form contains multiple fields with duplicate names, for example
<form action="/test/save"Method="Post"> <!--omit other fields-<input type="text"Name="value"/> <input type="text"Name="value"/> <input type="text"Name="value"/> <!--There may be more input--> <input with name value type="Submit"Value="Submit"/></form>
Html
If a model needs to be received in action, the usual solution is to use a ienumerable<t> type or its derived type to receive data to ensure the completion of the data, such as a model
Public class Test { // omit other fields Public string Get Set ; } }
Model
Generally speaking, there's nothing wrong with this, but the problem is.
If I need to split the result with a comma (,) and output it, then I need to write a line of code string. Join (",", model. Test); , no matter where it is.
If you do not do string concatenation on the model field, it will also cause the model to not be reused. And the code looks very elegant.
Second, the question of thinking
I sent the question to Bo . The. Net MVC model receives parameter issues
The general answer is the solution I said above, which seems to be not what I want.
Try to think for a moment.
The standard HTTP request is received when, for MVC, he is just a form or a querystring (if you understand the error, please correct), then how does the MVC framework do to bind a form to a model?
Why did the corresponding field in HttpContext.Request.Form complete the string concatenation?
Why is the assignment of the form and the model different? Can I use the values in the form?
With the problem, poked a degree Niang, found a surprise thing, model Binder (Modelbinder)
Concept I will not post, see this great God's blog ASP. MVC5 Modelbinder
This is a core, ASP. NET core MVC Model Binding:custom binders
Third, the solution
1. Build a model binder of your own
Framework:
Public class Testmodelbinder:defaultmodelbinder, Imodelbinder { publicoverrideobject Bindmodel (ControllerContext controllercontext, Modelbindingcontext BindingContext) { varbase. Bindmodel (ControllerContext, BindingContext); // Do something for model to format from Form or Other place return model; } }
Core:
Public class Testmodelbinder:imodelbinder { public Task bindmodelasync (modelbindingcontext bindingcontext) { var model = Bindingcontext.model; // Do something for model to format from Form or other place = modelbindingresult.success (model); return task.completedtask; } }
As long as the annotation is in place, the model needs to be assigned a field to operate on it.
PS: The specific operation of the benevolent see, simply say my own practice, reflection traversal of the model type string field, if the Model field value is inconsistent with the name of the form, the form is assigned a value from the new field.
The efficiency of this approach has yet to be improved, but this is the first solution.
Okay, the model binder is there, but it's not available yet.
2. Define the provider of the model binder
This method is written in the blog of the Great God above.
Framework:
Public class testmodelbinderprovider:imodelbinderprovider{ public imodelbinder getbinder (Type Modeltype) {iftypeof(Test)) { returnNew Testmodelbinder (); } return NULL ; }}
The type passed in here is the type of the model itself and is used to filter for some models to take effect, typically using the default binder Defaultmodelbinder .
Core:
Public class Testmodelbinderprovider:imodelbinderprovider { public imodelbinder getbinder (modelbinderprovidercontext context) { if typeof(DateTime)) { returnnew Testmodelbinder () ; } return NULL ; } }
In addition to the same parameters, the two versions are basically a bit of a hair.
3. Global Registration
A model binder that is defined as a global can be started when all models are bound. There is no need to add anything else, but at the same time the problem is that using a native binder requires a separate declaration on the parameters.
The framework is inside the global.asax.
Public class mvcapplication:system.web.httpapplication{ protectedvoid Application_Start () { ModelBinderProviders.BinderProviders.Insert (0New Testmodelbinderprovider ()); // or you can do the following, two options // ModelBinders.Binders.Add (typeof (Test), New Testmodelbinder ()); }}
The core is in the Startup.cs.
Public void configureservices (iservicecollection services) { = = { option. Modelbinderproviders.insert (0new Testmodelbinderprovider ()); })
4. Defining Model Binding Properties
In the case of a special binder, we can choose to define the binder as a property
Framework:
false false )] publicclass formformatattribute:custommodelbinderattribute { publicoverride imodelbinder getbinder () { return New Testmodelbinder (); } }
Core:
false false )] publicclass testmodelbinderattribute:modelbinderattribute { Public Base (typeof(testmodelbinder)) { } }
It's almost like a hair.
The invocation method of the property is identical, and the parameter is preceded by [Testmodelbinder] .
Summarize:
After a toss-up, the model binder is done, and the variable can be more elegantly bound. There's no need for a bunch of stitching strings ah, extra attributes ah, that sort of thing.
However, it is important to note that the core binder does not have a default base class (or maybe I did not find, if found, if there is trouble to find the Welcome to share), so you can not like the framework first let the default processing, processing and processing. Instead, it needs to be handled manually by the developer.
[MVC] Custom model binder, assigning a value from a form to a model