如何禁用ModelMetadata.对于非空值类型总是为真
本文关键字:类型 空值 何禁用 ModelMetadata 于非 | 更新日期: 2023-09-27 18:16:26
我有一个简单的模型:
public class Sample
{
public bool A { get; set; }
[Required]
public bool B { get; set; }
}
A显然不是必需的。因此,为了验证,我在Global.asax中设置了DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false
。
我也有一个简单的html帮助,打印真或假,如果模型是必需的:
public static class HtmlHelperExtensions
{
public static MvcHtmlString IsRequired<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
return new MvcHtmlString(metadata.IsRequired.ToString());
}
}
我还写了一个视图来展示我的问题:
@model MvcApplication10.Models.Sample
A: @Html.IsRequired(m => m.A), B: @Html.IsRequired(m => m.B)
我本来希望打印A: false, B: true
,然而,它实际上打印了A: true, B: true
。
有没有办法使这个打印我的预期结果?IsRequired
似乎总是返回真,即使我没有明确地设置RequiredAttribute
。文档声明默认情况下对于非空值类型为真。为什么没有简单的方法将其设置为false,就像我们可以使用验证一样?
EDIT:我可以这样写一个自定义提供程序,但我想知道是否有一个"简单"的方法来解决这个问题:
public class ExtendedDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
private static bool addImplicitRequiredAttributeForValueTypes = false;
public static bool AddImplicitRequiredAttributeForValueTypes
{
get
{
return addImplicitRequiredAttributeForValueTypes;
}
set
{
addImplicitRequiredAttributeForValueTypes = value;
}
}
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
var result = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
if (!AddImplicitRequiredAttributeForValueTypes && modelType.IsValueType && !attributes.OfType<RequiredAttribute>().Any())
{
result.IsRequired = false;
}
return result;
}
}
正如您注意到的,ValueTypes将默认为true。为了解决这个问题,如果类型是ValueType
,您可以检查RequiredAttribute
。
ModelMetadata metaData = ModelMetadata.FromLambdaExpression<TModel, TValue>(expression, html.ViewData);
if ((metaData.ModelType.IsValueType && metaData.ModelType.GetCustomAttributes(typeof(RequiredAttribute), false).Any()) ||
(!metaData.ModelType.IsValueType && metaData.IsRequired))
{ ... }
我猜你正面临MVC错误。Required总是在这种情况下触发,无论什么情况,即使你使用
DataAnnotationsModelValidatorProvider
.AddImplicitRequiredAttributeForValueTypes = false;
这已经在这里讨论和报道过了。这个例子进一步说明,当隐式的required触发时,它不会阻止IValidatableObject
的执行。如果你从第二个链接运行演示,你可以复制你的案例,在需要的地方总是为true。
无论如何,这很容易解决因为如果你说A is obviously not required
等于说它是可空的,那么就这样做:
public bool? A { get; set; }
如果您像我一样在EditorTemplate中工作,则需要再执行一步:
var metaData = ModelMetadata.FromLambdaExpression(Model => Model, ViewData);
var required = metaData.ContainerType.GetProperty(metaData.PropertyName).GetCustomAttributes(typeof (RequiredAttribute), false).Any();
您需要从模型元数据中获取容器类型,以便检查您的特定属性的属性;否则,您只是检查属性的数据类型的属性,而不是属性的属性。 根据是否有[Required]返回true或false。 我在几个地方都遇到过这个问题,我已经实现了一个简单的修复,像这样 如果您希望它也适用于可空类型:typeof(<YourModel>).GetProperty(<PropertyName>).GetCustomAttributes(typeof(RequiredAttribute), false).Any()
if (metadata.ModelType == typeof(System.Boolean))
{
metadata.IsRequired = false;
}
private static bool RequiredAttrExists(ModelMetadata metaData)
{
if(!metaData.ModelType.IsValueType && metaData.IsRequired)
return true;
else if (metaData.ModelType.IsValueType && metaData.ContainerType.GetProperty(metaData.PropertyName).GetCustomAttributes(typeof(RequiredAttribute), false).Any())
return true;
return false;
}