问题
I started using MVC recently and I'm getting little disappointed. Instead of helping me, the framework is getting in my way.
I'm trying to write a controller action like this (pseudo code)
ActionResult Save(long id, string whichForm)
{
if (whichForm == "A")
{
var vm = CreateModel(Request.Form);
if (!TryValidate(vm))
return View(vm);
else
return RedirectToRoute("Success");
}
else ....
}
Basically I'd like to have control over when my view-model is constructed and when it is validated. Is this possible? How can I implement CreateModel method? Consider I may want to create several different view-models within this controller action.
*Rant: I don't really understand why view-model binding and validation are mixed together in DefaultModelBinder. Seems like code smell. Specially when it's hard to override this behaviour.
回答1:
You can create and bind to an existing model at your discretion:
public ActionResult Save(long id, string whichForm)
{
if (whichForm == "A")
{
var vm = new FormAViewModel();
if (!TryUpdateModel(vm))
return View(vm);
else
return RedirectToRoute("Success");
}
// else ....
}
You also have the option of creating your own IModelBinder, if you want complete control over the binding process. You can replace the default model binder, or you can register specific IModelBinder
implementations for specific types. I would suggest, however, that unless your binding logic is simple, you will probably want to derive your custom model binder from DefaultModelBinder
and just override the parts you don't like.
I hate to leave a troll-ish comment, but 9 times out of 10 the reason someone feels a framework is getting in their way is because they don't yet understand how to properly use it. Here is an article with general tips on model binding.
As to your rant: Validation and Binding are separate, however, the default model binder does trigger validation. The reason for this is to allow your application to gracefully handle problems binding to missing/invalid/incomplete values, rather than allowing binding to fail silently or throwing exceptions.
回答2:
You can leverage IModelBinder interface and write a complete custom model binder. Here it is explained well. Essentially, this interface exposes a method "BindModel", where you can control model binding behavior along with validation.
http://www.dotnetcurry.com/ShowArticle.aspx?ID=584
However, this might complicate the matter and you might get in spaghetti code. I would suggest a simple "Action per model", if it suites you. So you can write something like this :
ActionResult SaveA(long id, AViewModel)
{
//.... Action to be conducted in case it is form A.
}
ActionResult SaveB(...., BViewModel)
{
//... Action to be conducted in case it is form B.
}
// Your view models can be structured for code reuse as well.
class AViewModel { ... }
class BViewModel : AViewModel { ... }
来源:https://stackoverflow.com/questions/10825951/how-to-gain-control-over-model-binding