asp.net-mvc-3 – 在MVC3中使用强类型视图时可能的模型继承?
|
我的模型中有以下设置: namespace QuickTest.Models
{
public class Person
{
[Required]
[Display(Name = "Full name")]
public string FullName { get; set; }
[Display(Name = "Address Line 1")]
public virtual string Address1 { get; set; }
}
public class Sender : Person
{
[Required]
public override string Address1 { get; set; }
}
public class Receiver : Person
{
}
}
在我看来: @model QuickTest.Models.Person
@{
ViewBag.Title = "Edit";
}
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm()) {
<fieldset>
<legend>Person</legend>
<div class="editor-label">
@Html.LabelFor(model => model.FullName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.FullName)
@Html.ValidationMessageFor(model => model.FullName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Address1)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Address1)
@Html.ValidationMessageFor(model => model.Address1)
</div>
<div class="errors">
@Html.ValidationSummary(true)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
启用客户端验证.但是,如果我将一个Sender类型的对象发送到View,则客户端验证不会检测到需要Address1字段.有没有办法让客户端验证在这种情况下工作? PS: <div class="editor-field">
@Html.Editor("Address1",Model.Address1)
@Html.ValidationMessageFor(model => model.Address1)
</div>
解决方法您可以自定义验证器和元数据来自您的具体类,但该解决方案有几个移动部件,包括两个自定义元数据提供程序.首先,创建一个自定义属性来装饰基类的每个属性.这是我们的自定义提供程序的标志所必需的,以指示何时需要进一步分析.这是属性: [AttributeUsage(AttributeTargets.All,Inherited = true,AllowMultiple = true)]
public class BaseTypeAttribute : Attribute { }
接下来,创建一个继承自DataAnnotationsModelMetadataProvider的自定义ModelMetadataProvider: public class MyModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(
IEnumerable<Attribute> attributes,Type containerType,Func<object> modelAccessor,Type modelType,string propertyName)
{
var attribute = attributes.FirstOrDefault(a => a.GetType().Equals(typeof(BaseTypeAttribute))) as BaseTypeAttribute;
if (attribute != null && modelAccessor != null)
{
var target = modelAccessor.Target;
var containerField = target.GetType().GetField("container");
if (containerField == null)
{
var vdi = target.GetType().GetField("vdi").GetValue(target) as ViewDataInfo;
var concreteType = vdi.Container.GetType();
return base.CreateMetadata(attributes,concreteType,modelAccessor,modelType,propertyName);
}
else
{
var container = containerField.GetValue(target);
var concreteType = container.GetType();
var propertyField = target.GetType().GetField("property");
if (propertyField == null)
{
concreteType = base.GetMetadataForProperties(container,containerType)
.FirstOrDefault(p => p.PropertyName == "ConcreteType").Model as System.Type;
if (concreteType != null)
return base.GetMetadataForProperties(container,concreteType)
.FirstOrDefault(pr => pr.PropertyName == propertyName);
}
return base.CreateMetadata(attributes,propertyName);
}
}
return base.CreateMetadata(attributes,containerType,propertyName);
}
}
然后,创建一个继承自DataAnnotationsModelValidatorProvider的自定义ModelValidatorProvider: public class MyModelMetadataValidatorProvider : DataAnnotationsModelValidatorProvider
{
protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata,ControllerContext context,IEnumerable<Attribute> attributes)
{
List<ModelValidator> vals = base.GetValidators(metadata,context,attributes).ToList();
var baseTypeAttribute = attributes.FirstOrDefault(a => a.GetType().Equals(typeof(BaseTypeAttribute)))
as BaseTypeAttribute;
if (baseTypeAttribute != null)
{
// get our parent model
var parentMetaData = ModelMetadataProviders.Current.GetMetadataForProperties(context.Controller.ViewData.Model,metadata.ContainerType);
// get the concrete type
var concreteType = parentMetaData.FirstOrDefault(p => p.PropertyName == "ConcreteType").Model;
if (concreteType != null)
{
var concreteMetadata = ModelMetadataProviders.Current.GetMetadataForProperties(context.Controller.ViewData.Model,Type.GetType(concreteType.ToString()));
var concretePropertyMetadata = concreteMetadata.FirstOrDefault(p => p.PropertyName == metadata.PropertyName);
vals = base.GetValidators(concretePropertyMetadata,attributes).ToList();
}
}
return vals.AsEnumerable();
}
}
之后,在Global.asax.cs中的Application_Start中注册两个自定义提供程序: ModelValidatorProviders.Providers.Clear(); ModelValidatorProviders.Providers.Add(new MvcApplication8.Controllers.MyModelMetadataValidatorProvider()); ModelMetadataProviders.Current = new MvcApplication8.Controllers.MyModelMetadataProvider(); 现在,改变你的模型: public class Person
{
public Type ConcreteType { get; set; }
[Required]
[Display(Name = "Full name")]
[BaseType]
public string FullName { get; set; }
[Display(Name = "Address Line 1")]
[BaseType]
public virtual string Address1 { get; set; }
}
public class Sender : Person
{
public Sender()
{
this.ConcreteType = typeof(Sender);
}
[Required]
[Display(Name = "Address Line One")]
public override string Address1 { get; set; }
}
public class Receiver : Person
{
}
请注意,基类具有新属性ConcreteType.这将用于指示哪个继承类已实例化此基类.每当继承类具有覆盖基类中元数据的元数据时,继承类的构造函数应该设置基类ConcreteType属性. 现在,即使您的视图使用基类,特定于任何具体继承类的属性也将出现在视图中,并将影响模型的验证. 此外,您应该能够将View转换为Person类型的模板,并将该模板用于使用基类的任何实例或从中继承. (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- ASP.NET MVC和ORM选择
- asp.net – 有没有办法每天在.Net Web应用程序中运行一个进
- asp.net – 覆盖webapi odata链接的主机
- 实体框架 – 在Db初始化程序的种子方法中创建Asp.net身份用
- asp.net-mvc-4 – MVC 4如果经过身份验证,则从登录页面重定
- 如果没有授权,如何将用户重定向到ASP.NET页面?
- asp.net-mvc – 从桌面开发人员的角度来学习ASP.NET MVC的建
- asp.net – 在网页上的ReportViewer控件中呈现时,Reporting
- asp.net-mvc-3 – 如何在Asp.Net Mvc 3中显示自定义错误页面
- asp.net-mvc – 使用asp.net mvc 2功能与火花浏览引擎
- Asp.NEt邮箱验证修改密码通过邮箱找回密码功能
- asp.net-core – 访问Raw Request Body
- asp.net-mvc – HttpResponse.RemoveOutputCache
- asp.net – 子目录中的Web.config在使用页面路由
- 在ASP.NET MVC2创建方法中使用FormCollection的正
- 使用HttpModule Asp.net重定向URL
- asp.net-mvc – 当使用AutoMapper / AutoMapView
- asp.net-mvc-4 – 如何在mvc4 ActionLink中加密查
- 如何比较vbscript / ASP中的两个日期?
- asp.net-mvc – 将依赖项注入自定义模型绑定器并
