在 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 类型的对象发送到视图,客户端验证不会检测到 Address1 字段是必需的。有什么办法可以让客户端验证在这种情况下工作吗?
附: 我发现如果我使用以下命令在视图中显示 Address1 字段,客户端验证就会起作用:
<div class="editor-field">
@Html.Editor("Address1", Model.Address1)
@Html.ValidationMessageFor(model => model.Address1)
</div>
I have the following setup in my model:
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
{
}
}
and in my view:
@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>
}
Client-side validation is enabled. However, if I send an object of type Sender to the View, client-side validation does not detect that the Address1 field is required. Is there any way of making the client validation work in this scenario?
PS:
I discovered that client validation works if I use the following to display the Address1 field in the view:
<div class="editor-field">
@Html.Editor("Address1", Model.Address1)
@Html.ValidationMessageFor(model => model.Address1)
</div>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以自定义来自具体类的验证器和元数据,但该解决方案有几个移动部分,包括两个自定义元数据提供程序。
首先,创建一个自定义
Attribute
来装饰基类的每个属性。作为我们的定制提供商的标志,这是必要的,以指示何时需要进一步分析。这是属性:接下来,创建一个继承自
DataAnnotationsModelMetadataProvider
的自定义ModelMetadataProvider
: 然后,创建一个继承自
DataAnnotationsModelValidatorProvider
的自定义ModelValidatorProvider
code>:之后,在 Global.asax.cs 的
Application_Start
中注册两个自定义提供程序:现在,像这样更改模型:
请注意,基类有一个新属性,
具体类型
。这将用于指示哪个继承类已实例化该基类。每当继承类具有覆盖基类中的元数据的元数据时,继承类的构造函数应设置基类的 ConcreteType 属性。现在,即使您的视图使用基类,特定于任何具体继承类的属性也会出现在您的视图中,并将影响模型的验证。
此外,您应该能够将 View 转换为 Person 类型的模板,并将该模板用于任何使用基类或继承基类的实例。
You can customize the validators and the metadata to come from your concrete class, but the solution has several moving parts, including two custom metadata providers.
First, create a custom
Attribute
to decorate each property of the base class. This is necessary as a flag for our custom providers, to indicate when further analysis is needed. This is the attribute:Next, create a custom
ModelMetadataProvider
inheriting fromDataAnnotationsModelMetadataProvider
:Then, create a custom
ModelValidatorProvider
inheriting fromDataAnnotationsModelValidatorProvider
:After that, register both custom providers in
Application_Start
in Global.asax.cs:Now, change your models like so:
Note that the base class has a new property,
ConcreteType
. This will be used to indicate which inheriting class has instantiated this base class. Whenever an inheriting class has metadata which overrides the metadata in the base class, the inheriting class' constructor should set the base class ConcreteType property.Now, even though your view uses the base class, the attributes specific to any concrete inheriting class will appear in your view, and will affect the validation of the model.
In addition, you should be able to turn the View into a template for the Person type, and use the template for any instance using the base class or inheriting from it.
嗯,这是一个棘手的问题,因为
HtmlHelper.EditorFor
方法使用HtmlHelper
的通用参数来确定需要哪些验证属性。我建议编写您自己的 EditorFor 扩展方法,该方法将调用委托给非通用 HtmlHelper.Editor 方法。
Hmm, this is a tricky one since the
HtmlHelper<T>.EditorFor
method uses the generic parameter of theHtmlHelper<T>
to figure out which validation attributes are required.I would suggest writing your own EditorFor extension method that delegates calls to the non-generic HtmlHelper.Editor method.
您是否考虑过为人员、发送者和接收者创建自己的编辑器模板? EditorFor 和 DisplayFor 查找与对象类型匹配的自定义模板。
内部方法将寻找与对象类型匹配的模板。然后它将查找与基类匹配的模板,然后沿着继承链向上查找。
Have you considered creating your own EditorTemplate for Person, Sender and Receiver? The EditorFor and DisplayFor look for a custom template that match the type of the object.
The internal method will look for a template that matches the type of the object. It will then look for a template that matches the base class and then on up the chain of inheritance.