Asp.net mvc 4 DefaultModelBinder返回子类MVC4
几天来,我一直在努力阅读关于这个DefaultModelBinder的文章,但我仍然很困惑。我使用的是MVC4和EF5表格结构 我的问题是我有一个资源基类:Asp.net mvc 4 DefaultModelBinder返回子类MVC4,asp.net-mvc-4,binding,subclass,defaultmodelbinder,Asp.net Mvc 4,Binding,Subclass,Defaultmodelbinder,几天来,我一直在努力阅读关于这个DefaultModelBinder的文章,但我仍然很困惑。我使用的是MVC4和EF5表格结构 我的问题是我有一个资源基类: public class Resource : PocoBaseModel { private int _resourceID; private string _title; private string _description; //public accessors } 有子类(DVD、电
public class Resource : PocoBaseModel
{
private int _resourceID;
private string _title;
private string _description;
//public accessors
}
有子类(DVD、电子书、书籍等)
我的控制器代码使用自定义ModelBinder
[HttpPost]
public ActionResult Create([ModelBinder(typeof(ResourceModelBinder))] Resource resource)
{
//controller code
}
public class ResourceModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
var type = controllerContext.HttpContext.Request.Form["DiscriminatorValue"];
bindingContext.ModelName = type;
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, resourceTypeMap[type]);
return base.BindModel(controllerContext, bindingContext);
}
static Dictionary<string, Type> resourceTypeMap = new Dictionary<string, Type>
{
{"Resource", typeof(Resource)},
{"Book", typeof(Book)},
{"DVD", typeof(DVD)},
{"EBook", typeof(EBook)},
{"Hardware", typeof(Hardware)},
{"Software", typeof(Software)}
};
}
[HttpPost]
公共操作结果创建([ModelBinder(typeof(ResourceModelBinder))]资源)
{
//控制器代码
}
公共类ResourceModelBinder:DefaultModelBinder
{
公共覆盖对象绑定模型(ControllerContext ControllerContext,
ModelBindingContext(绑定上下文)
{
var type=controllerContext.HttpContext.Request.Form[“DiscriminatorValue”];
bindingContext.ModelName=类型;
bindingContext.ModelMetadata=ModelMetadataProviders.Current.GetMetadataForType(null,resourceTypeMap[type]);
返回base.BindModel(controllerContext、bindingContext);
}
静态字典resourceTypeMap=新字典
{
{“资源”,类型(资源)},
{“书”,字体(书)},
{“DVD”,类型(DVD)},
{“电子书”,类型(电子书)},
{“硬件”,类型(硬件)},
{“软件”,类型(软件)}
};
}
这样我就可以将我的视图传递给一个资源(以DVD、书籍或任何其他类型的形式播放)
@model Models.Resource
@{
ViewBag.Title=“创建”;
}
创造
@使用(Html.BeginForm(“Create”、“Admin”、null、FormMethod.Post、null))
{
@Html.ValidationSummary(true)
资源
@Html.HiddenFor(model=>model.ResourceID)
@Html.HiddenFor(model=>model.ResourceTypeID)
@Html.HiddenFor(model=>model.Committed)
@Html.Partial(“_CreateOrEdit”,Model)
}
并根据其派生属性绑定它,该属性发生在partialview内部的开关中
@using Models.ViewModels;
@using Models.ResourceTypes;
@using Helper;
@model Models.Resource
@Html.HiddenFor(model => Model.DiscriminatorValue);
<table cellspacing="2" cellpadding="2" border="0">
@{
string type = Model.DiscriminatorValue;
switch (type)
{
case "Book":
Book book = (Book)Model;
<tr>
<td colspan="2">
<div class="editor-label" style="padding-top: 15px;">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.Title, new { style = "width: 750px; height: 65px;" })
@Html.ValidationMessageFor(model => model.Title)
</div>
</td>
</tr>
<tr>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.Edition)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => book.Edition, new { style = "width: 150px;" })
@Html.ValidationMessageFor(model => book.Edition)
</div>
</td>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.Author)
</div>
<div class="editor-field">
@Html.EditorFor(model => book.Author)
@Html.ValidationMessageFor(model => book.Author)
</div>
</td>
</tr>
<tr>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.Pages)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => book.Pages, new { style = "width: 75px;" })
@Html.ValidationMessageFor(model => book.Pages)
</div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="editor-label">
@Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.Description, new { style = "width: 750px; height: 105px;" })
@Html.ValidationMessageFor(model => model.Description)
</div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="editor-label">
@Html.LabelFor(model => model.AdminNote)
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.AdminNote, new { style = "width: 750px; height: 105px;" })
@Html.ValidationMessageFor(model => model.AdminNote)
</div>
</td>
</tr>
<tr>
<td>
<div class="editor-label">
@{ int copies = Model == null ? 1 : Model.Copies; }
@Html.LabelFor(model => model.Copies)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.Copies, new { style = "width: 75px;", @Value = copies.ToString() })
@Html.ValidationMessageFor(model => model.Copies)
</div>
</td>
</tr>
<tr>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.ISBN10)
</div>
<div class="editor-field">
@Html.EditorFor(model => book.ISBN10)
@Html.ValidationMessageFor(model => book.ISBN10)
</div>
</td>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.ISBN13)
</div>
<div class="editor-field">
@Html.EditorFor(model => book.ISBN13)
@Html.ValidationMessageFor(model => book.ISBN13)
</div>
</td>
</tr>
break;
@使用Models.ViewModels;
@使用模型。资源类型;
@使用助手;
@模型。资源
@Html.HiddenFor(model=>model.DiscriminatorValue);
@{
字符串类型=Model.DiscriminatorValue;
开关(类型)
{
案例“书”:
Book=(Book)模型;
@LabelFor(model=>model.Title)
@Html.TextAreaFor(model=>model.Title,新{style=“宽度:750px;高度:65px;”})
@Html.ValidationMessageFor(model=>model.Title)
@LabelFor(model=>book.Edition)
@Html.TextBoxFor(model=>book.Edition,新{style=“width:150px;”})
@Html.ValidationMessageFor(model=>book.Edition)
@LabelFor(model=>book.Author)
@EditorFor(model=>book.Author)
@Html.ValidationMessageFor(model=>book.Author)
@LabelFor(model=>book.Pages)
@Html.TextBoxFor(model=>book.Pages,新{style=“width:75px;”})
@Html.ValidationMessageFor(model=>book.Pages)
@LabelFor(model=>model.Description)
@Html.TextAreaFor(model=>model.Description,新{style=“宽度:750px;高度:105px;”})
@Html.ValidationMessageFor(model=>model.Description)
@LabelFor(model=>model.AdminNote)
@Html.TextAreaFor(model=>model.AdminNote,新{style=“宽度:750px;高度:105px;”})
@Html.ValidationMessageFor(model=>model.AdminNote)
@{int copies=Model==null?1:Model.copies;}
@LabelFor(model=>model.Copies)
@Html.TextBoxFor(model=>model.Copies,新的{style=“width:75px;”,@Value=Copies.ToString()})
@Html.ValidationMessageFor(model=>model.Copies)
@LabelFor(model=>book.ISBN10)
@EditorFor(model=>book.ISBN10)
@Html.ValidationMessageFor(model=>book.ISBN10)
@LabelFor(model=>book.ISBN13)
@EditorFor(model=>book.ISBN13)
@Html.ValidationMessageFor(model=>book.ISBN13)
打破
我的第一个问题是,当我将表单发回时,它作为一个资源返回,而不是作为强制类型返回(因此我丢失了所有派生类型属性)这就是我创建ResourceModelBinder的原因。现在它正确地绑定了/postsback铸造类型,但没有绑定资源的基类属性,如Title、ResourceID、ResourceTypeID
有人能帮我理解我缺少什么,这样它就可以绑定基本资源类属性和派生类型属性。所以我所要做的就是在自定义ModelBinder类中重写BindProperty方法
protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
{
if (propertyDescriptor.DisplayName != null)
{
var Form = controllerContext.HttpContext.Request.Form;
string currentPropertyFormValue = string.Empty;
string formDerivedTypeKey = bindingContext.ModelName.ToLower() + "." + propertyDescriptor.DisplayName;
string formBaseTypeKey = propertyDescriptor.DisplayName;
List<string> keywordList = null;
Type conversionType = propertyDescriptor.PropertyType;
if (!string.IsNullOrEmpty(Form[formDerivedTypeKey]) || !string.IsNullOrEmpty(Form[formBaseTypeKey]))
{
if (!string.IsNullOrEmpty(Form[formDerivedTypeKey]))
{
//store current derived type property
currentPropertyFormValue = Form[formDerivedTypeKey];
}
if (!string.IsNullOrEmpty(Form[formBaseTypeKey]))
{
//store current base type property
currentPropertyFormValue = Form[formBaseTypeKey];
}
}
if (conversionType.IsGenericType)
{
if (conversionType.GetGenericTypeDefinition() == typeof(List<>))
{
if (propertyDescriptor.DisplayName == "KeyWords")
{
string[] keywords = currentPropertyFormValue.Split(',');
if (keywords != null && keywords.Count() > 0)
{
//create keyword list
keywordList = new List<string>();
foreach (var item in keywords)
{
if (!string.IsNullOrEmpty(item) && !item.Contains(','))
{
keywordList.Add(item);
}
}
}
}
}
if (conversionType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// nullable type property.. re-store nullable type to a safe type
conversionType = Nullable.GetUnderlyingType(conversionType) ?? propertyDescriptor.PropertyType;
}
}
if (!string.IsNullOrEmpty(currentPropertyFormValue))
{
//bind property
if (propertyDescriptor.DisplayName != "KeyWords")
{
propertyDescriptor.SetValue(bindingContext.Model, Convert.ChangeType(currentPropertyFormValue, conversionType));
}
else
propertyDescriptor.SetValue(bindingContext.Model, Convert.ChangeType(keywordList, conversionType));
}
}
else
base.BindProperty(controllerContext, bindingContext, propertyDescriptor); //default condition
}
protected override void BindProperty(ControllerContext ControllerContext,ModelBindingContext bindingContext,System.ComponentModel.PropertyDescriptor PropertyDescriptor)
{
if(propertyDescriptor.DisplayName!=null)
{
var Form=controllerContext.HttpContext.Request.Form;
string currentPropertyFormValue=string.Empty;
string formDerivedTypeKey=bindingContext.ModelName.ToLower()+“”+propertyDescriptor.DisplayName;
字符串formBaseTypeKey=propert
@using Models.ViewModels;
@using Models.ResourceTypes;
@using Helper;
@model Models.Resource
@Html.HiddenFor(model => Model.DiscriminatorValue);
<table cellspacing="2" cellpadding="2" border="0">
@{
string type = Model.DiscriminatorValue;
switch (type)
{
case "Book":
Book book = (Book)Model;
<tr>
<td colspan="2">
<div class="editor-label" style="padding-top: 15px;">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.Title, new { style = "width: 750px; height: 65px;" })
@Html.ValidationMessageFor(model => model.Title)
</div>
</td>
</tr>
<tr>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.Edition)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => book.Edition, new { style = "width: 150px;" })
@Html.ValidationMessageFor(model => book.Edition)
</div>
</td>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.Author)
</div>
<div class="editor-field">
@Html.EditorFor(model => book.Author)
@Html.ValidationMessageFor(model => book.Author)
</div>
</td>
</tr>
<tr>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.Pages)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => book.Pages, new { style = "width: 75px;" })
@Html.ValidationMessageFor(model => book.Pages)
</div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="editor-label">
@Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.Description, new { style = "width: 750px; height: 105px;" })
@Html.ValidationMessageFor(model => model.Description)
</div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="editor-label">
@Html.LabelFor(model => model.AdminNote)
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.AdminNote, new { style = "width: 750px; height: 105px;" })
@Html.ValidationMessageFor(model => model.AdminNote)
</div>
</td>
</tr>
<tr>
<td>
<div class="editor-label">
@{ int copies = Model == null ? 1 : Model.Copies; }
@Html.LabelFor(model => model.Copies)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.Copies, new { style = "width: 75px;", @Value = copies.ToString() })
@Html.ValidationMessageFor(model => model.Copies)
</div>
</td>
</tr>
<tr>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.ISBN10)
</div>
<div class="editor-field">
@Html.EditorFor(model => book.ISBN10)
@Html.ValidationMessageFor(model => book.ISBN10)
</div>
</td>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.ISBN13)
</div>
<div class="editor-field">
@Html.EditorFor(model => book.ISBN13)
@Html.ValidationMessageFor(model => book.ISBN13)
</div>
</td>
</tr>
break;
protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
{
if (propertyDescriptor.DisplayName != null)
{
var Form = controllerContext.HttpContext.Request.Form;
string currentPropertyFormValue = string.Empty;
string formDerivedTypeKey = bindingContext.ModelName.ToLower() + "." + propertyDescriptor.DisplayName;
string formBaseTypeKey = propertyDescriptor.DisplayName;
List<string> keywordList = null;
Type conversionType = propertyDescriptor.PropertyType;
if (!string.IsNullOrEmpty(Form[formDerivedTypeKey]) || !string.IsNullOrEmpty(Form[formBaseTypeKey]))
{
if (!string.IsNullOrEmpty(Form[formDerivedTypeKey]))
{
//store current derived type property
currentPropertyFormValue = Form[formDerivedTypeKey];
}
if (!string.IsNullOrEmpty(Form[formBaseTypeKey]))
{
//store current base type property
currentPropertyFormValue = Form[formBaseTypeKey];
}
}
if (conversionType.IsGenericType)
{
if (conversionType.GetGenericTypeDefinition() == typeof(List<>))
{
if (propertyDescriptor.DisplayName == "KeyWords")
{
string[] keywords = currentPropertyFormValue.Split(',');
if (keywords != null && keywords.Count() > 0)
{
//create keyword list
keywordList = new List<string>();
foreach (var item in keywords)
{
if (!string.IsNullOrEmpty(item) && !item.Contains(','))
{
keywordList.Add(item);
}
}
}
}
}
if (conversionType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// nullable type property.. re-store nullable type to a safe type
conversionType = Nullable.GetUnderlyingType(conversionType) ?? propertyDescriptor.PropertyType;
}
}
if (!string.IsNullOrEmpty(currentPropertyFormValue))
{
//bind property
if (propertyDescriptor.DisplayName != "KeyWords")
{
propertyDescriptor.SetValue(bindingContext.Model, Convert.ChangeType(currentPropertyFormValue, conversionType));
}
else
propertyDescriptor.SetValue(bindingContext.Model, Convert.ChangeType(keywordList, conversionType));
}
}
else
base.BindProperty(controllerContext, bindingContext, propertyDescriptor); //default condition
}