B Z*_*B Z 50 asp.net-mvc model-binding asp.net-mvc-3
假设我有一个Product模型,Product模型具有ProductSubType(abstract)的属性,我们有两个具体的实现Shirt和Pants.
这是来源:
public class Product
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public decimal? Price { get; set; }
[Required]
public int? ProductType { get; set; }
public ProductTypeBase SubProduct { get; set; }
}
public abstract class ProductTypeBase { }
public class Shirt : ProductTypeBase
{
[Required]
public string Color { get; set; }
public bool HasSleeves { get; set; }
}
public class Pants : ProductTypeBase
{
[Required]
public string Color { get; set; }
[Required]
public string Size { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在我的用户界面中,用户有一个下拉列表,他们可以选择产品类型,并根据正确的产品类型显示输入元素.我已经弄明白了(使用ajax get on dropdown change,返回部分/编辑器模板并相应地重新设置jquery验证).
接下来,我为ProductTypeBase创建了一个自定义模型绑定器.
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ProductTypeBase subType = null;
var productType = (int)bindingContext.ValueProvider.GetValue("ProductType").ConvertTo(typeof(int));
if (productType == 1)
{
var shirt = new Shirt();
shirt.Color = (string)bindingContext.ValueProvider.GetValue("SubProduct.Color").ConvertTo(typeof(string));
shirt.HasSleeves = (bool)bindingContext.ValueProvider.GetValue("SubProduct.HasSleeves").ConvertTo(typeof(bool));
subType = shirt;
}
else if (productType == 2)
{
var pants = new Pants();
pants.Size = (string)bindingContext.ValueProvider.GetValue("SubProduct.Size").ConvertTo(typeof(string));
pants.Color = (string)bindingContext.ValueProvider.GetValue("SubProduct.Color").ConvertTo(typeof(string));
subType = pants;
}
return subType;
}
}
Run Code Online (Sandbox Code Playgroud)
这会正确地绑定值并且大部分都可以工作,除了我丢失了服务器端验证.所以,在预感到我这样做不正确的时候,我做了一些搜索,并且遇到了Darin Dimitrov的回答:
所以我将模型绑定器切换为仅覆盖CreateModel,但现在它不绑定值.
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
ProductTypeBase subType = null;
var productType = (int)bindingContext.ValueProvider.GetValue("ProductType").ConvertTo(typeof(int));
if (productType == 1)
{
subType = new Shirt();
}
else if (productType == 2)
{
subType = new Pants();
}
return subType;
}
Run Code Online (Sandbox Code Playgroud)
通过MVC 3 src,似乎在BindProperties中,GetFilteredModelProperties返回一个空结果,我认为是因为bindingcontext模型设置为ProductTypeBase,它没有任何属性.
谁能发现我做错了什么?这似乎不应该是这么困难.我相信,我失去了一些东西简单...我有另一种选择考虑的,而不是在产品型号,只是有上衣和裤子分开的性质有一个子产品属性.这些只是视图/表单模型,所以我认为这样可行,但是如果有什么需要了解正在发生的事情,我希望当前的方法有效...
谢谢你的帮助!
我没说清楚,但我添加的自定义模型绑定器继承自DefaultModelBinder
设置ModelMetadata和Model是缺失的部分.谢谢玛纳斯!
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
if (modelType.Equals(typeof(ProductTypeBase))) {
Type instantiationType = null;
var productType = (int)bindingContext.ValueProvider.GetValue("ProductType").ConvertTo(typeof(int));
if (productType == 1) {
instantiationType = typeof(Shirt);
}
else if (productType == 2) {
instantiationType = typeof(Pants);
}
var obj = Activator.CreateInstance(instantiationType);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, instantiationType);
bindingContext.ModelMetadata.Model = obj;
return obj;
}
return base.CreateModel(controllerContext, bindingContext, modelType);
}
Run Code Online (Sandbox Code Playgroud)
Man*_*nas 58
这可以通过重写CreateModel(...)来实现.我将以一个例子来证明这一点.
1.让我们创建一个模型和一些基础和子类.
public class MyModel
{
public MyBaseClass BaseClass { get; set; }
}
public abstract class MyBaseClass
{
public virtual string MyName
{
get
{
return "MyBaseClass";
}
}
}
public class MyDerievedClass : MyBaseClass
{
public int MyProperty { get; set; }
public override string MyName
{
get
{
return "MyDerievedClass";
}
}
}
Run Code Online (Sandbox Code Playgroud)
2.现在创建一个modelbinder并覆盖CreateModel
public class MyModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
/// MyBaseClass and MyDerievedClass are hardcoded.
/// We can use reflection to read the assembly and get concrete types of any base type
if (modelType.Equals(typeof(MyBaseClass)))
{
Type instantiationType = typeof(MyDerievedClass);
var obj=Activator.CreateInstance(instantiationType);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, instantiationType);
bindingContext.ModelMetadata.Model = obj;
return obj;
}
return base.CreateModel(controllerContext, bindingContext, modelType);
}
}
Run Code Online (Sandbox Code Playgroud)
3.现在在控制器中创建get和post动作.
[HttpGet]
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
MyModel model = new MyModel();
model.BaseClass = new MyDerievedClass();
return View(model);
}
[HttpPost]
public ActionResult Index(MyModel model)
{
return View(model);
}
Run Code Online (Sandbox Code Playgroud)
4.现在将MyModelBinder设置为global.asax中的默认模型绑定器这样做是为了为所有操作设置默认模型绑定器,对于单个操作,我们可以在操作参数中使用ModelBinder属性)
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ModelBinders.Binders.DefaultBinder = new MyModelBinder();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
Run Code Online (Sandbox Code Playgroud)
5.现在我们可以创建MyModel类型的视图和MyDerievedClass类型的局部视图
Index.cshtml
@model MvcApplication2.Models.MyModel
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>MyModel</legend>
@Html.EditorFor(m=>m.BaseClass,"DerievedView")
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Run Code Online (Sandbox Code Playgroud)
DerievedView.cshtml
@model MvcApplication2.Models.MyDerievedClass
@Html.ValidationSummary(true)
<fieldset>
<legend>MyDerievedClass</legend>
<div class="editor-label">
@Html.LabelFor(model => model.MyProperty)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.MyProperty)
@Html.ValidationMessageFor(model => model.MyProperty)
</div>
</fieldset>
Run Code Online (Sandbox Code Playgroud)
现在它将按预期工作,Controller将收到"MyDerievedClass"类型的对象.验证将按预期进行.

| 归档时间: |
|
| 查看次数: |
22768 次 |
| 最近记录: |