我有一个简单的模型:
public class Sample
{
public bool A { get; set; }
[Required]
public bool B { get; set; }
}
显然不需要A.因此,验证已在Global.asax中设置DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false
。
我还有一个简单的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());
}
}
我还写了一个展示我的问题的观点:
@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
似乎总是返回true,即使我没有明确设置RequiredAttribute
。 docs表示默认情况下对于非可空值类型是正确的。为什么没有简单的方法将它设置为假,就像我们可以通过验证一样?
编辑:我可以写一个像这样的自定义提供商,但我想知道是否有一个“简单”的方法:
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;
}
}
答案 0 :(得分:10)
如您所述,ValueTypes将默认为true。要解决此问题,如果类型为RequiredAttribute
,您可以检查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))
{ ... }
答案 1 :(得分:4)
我猜你正面临一个MVC错误。无论如何,即使您使用
,必需将始终触发该情况DataAnnotationsModelValidatorProvider
.AddImplicitRequiredAttributeForValueTypes = false;
这已经讨论过here并报告了here。此示例更进一步,并显示当隐式必需触发器时,它不会阻止IValidatableObject
执行。如果您从第二个链接运行演示,则可以重现您的案例,必要时始终如此。
无论如何,这很容易解决,因为如果你说A is obviously not required
与它可以为空是一样的话,那就这样做吧:
public bool? A { get; set; }
答案 2 :(得分:3)
如果您正在使用EditorTemplate,就像我一样,您还需要再做一步:
var metaData = ModelMetadata.FromLambdaExpression(Model => Model, ViewData);
var required = metaData.ContainerType.GetProperty(metaData.PropertyName).GetCustomAttributes(typeof (RequiredAttribute), false).Any();
您需要从模型元数据中获取容器类型,以便检查特定属性的属性;否则,您只是检查属性的属性,而不是属性的属性。
答案 3 :(得分:1)
以下将返回true或false,具体取决于您是否具有[Required]。
typeof(<YourModel>).GetProperty(<PropertyName>).GetCustomAttributes(typeof(RequiredAttribute), false).Any()
答案 4 :(得分:0)
我在几个地方遇到过这个问题,并实施了一个像这样的简单修复
if (metadata.ModelType == typeof(System.Boolean))
{
metadata.IsRequired = false;
}
答案 5 :(得分:0)
如果您希望它也适用于可空类型:
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;
}