如何禁用ModelMetadata.IsRequired始终为非可空值类型的true

The*_*Sky 14 .net c# asp.net-mvc asp.net-mvc-3

我有一个简单的模型:

public class Sample
{
    public bool A { get; set; }

    [Required]
    public bool B { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

显然不需要A. 因此,已经DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false在Global.asax中设置了验证.

我还有一个简单的html帮助器,如果需要模型,则打印true或false:

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());
    }
} 
Run Code Online (Sandbox Code Playgroud)

我还写了一个视图来展示我的问题:

@model MvcApplication10.Models.Sample

A: @Html.IsRequired(m => m.A), B: @Html.IsRequired(m => m.B)
Run Code Online (Sandbox Code Playgroud)

我本以为要打印A: false, B: true,但实际打印A: true, B: true.

有没有办法让这个打印成为我预期的结果?IsRequired似乎总是返回true,即使我没有明确设置RequiredAttribute.该文档说明它是不可为空值类型,默认为true.为什么没有简单的方法将它设置为假,就像我们可以通过验证一样?

编辑:我可以写这样的自定义提供程序,但我想知道是否有一个"简单"的方法:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Ada*_*cer 10

如您所述,ValueTypes将默认为true.要解决此问题,您可以检查RequiredAttribute类型是否为a ValueType.

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))
{ ... }
Run Code Online (Sandbox Code Playgroud)


Joa*_*oao 4

我猜你正面临 MVC 错误。无论什么情况,即使您使用,必需的总会在这种情况下触发

DataAnnotationsModelValidatorProvider
    .AddImplicitRequiredAttributeForValueTypes = false;
Run Code Online (Sandbox Code Playgroud)

这已经在这里讨论并报告。此示例更进一步,表明当隐式必需的触发器触发时,它不会阻止IValidatableObject执行。如果您从第二个链接运行演示,您可以重现您的案例,其中 required 始终为 true。

不管怎样,这很容易解决,因为如果你说这A is obviously not required与说它可以为空是一样的,那么就这样做:

public bool? A { get; set; }
Run Code Online (Sandbox Code Playgroud)