gpt4 book ai didi

asp.net-mvc-3 - 在MVC3中使用强类型 View 时可以继承模型吗?

转载 作者:行者123 更新时间:2023-12-04 01:00:49 26 4
gpt4 key购买 nike

我的模型中有以下设置:

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:
我发现如果使用以下方法在 View 中显示Address1字段,则客户端验证有效:
<div class="editor-field">
@Html.Editor("Address1", Model.Address1)
@Html.ValidationMessageFor(model => model.Address1)
</div>

最佳答案

您可以自定义来自具体类的验证器和元数据,但是该解决方案包含多个事件部分,其中包括两个自定义元数据提供程序。

首先,创建一个自定义的Attribute来装饰基类的每个属性。这对于我们的自定义提供程序是必要的,以指示何时需要进一步分析。这是属性:

[AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
public class BaseTypeAttribute : Attribute { }

接下来,创建一个继承自 ModelMetadataProvider的自定义 DataAnnotationsModelMetadataProvider:
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, concreteType, modelAccessor, modelType, propertyName);
}
}
return base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
}
}

然后,创建一个继承自 ModelValidatorProvider的自定义 DataAnnotationsModelValidatorProvider:
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, context, 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 使用基类,特定于任何具体继承类的属性也将出现在您的 View 中,并会影响模型的验证。

另外,您应该能够将View转换为Person类型的模板,并将该模板用于使用基类或从基类继承的任何实例。

关于asp.net-mvc-3 - 在MVC3中使用强类型 View 时可以继承模型吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8311907/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com