C# 如何禁用ModelMetadata.IsRequired,使其对于不可为null的值类型始终为true
我有一个简单的模型:C# 如何禁用ModelMetadata.IsRequired,使其对于不可为null的值类型始终为true,c#,.net,asp.net-mvc,asp.net-mvc-3,C#,.net,Asp.net Mvc,Asp.net Mvc 3,我有一个简单的模型: public class Sample { public bool A { get; set; } [Required] public bool B { get; set; } } 这显然不是必需的。因此,为了验证,我们在Global.asax中设置了DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes=false 我还有一个简单的html助
public class Sample
{
public bool A { get; set; }
[Required]
public bool B { get; set; }
}
这显然不是必需的。因此,为了验证,我们在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());
}
}
我本以为它会打印A:false,B:true
,但实际上它会打印A:true,B:true
有没有办法让这张照片成为我的预期结果IsRequired
似乎总是返回true,即使我没有明确设置required属性
。默认情况下,对于不可为null的值类型为true的状态。为什么没有简单的方法可以像验证一样将其设置为false
编辑:我可以编写这样的自定义提供程序,但我想知道是否有一种“简单”的方法:
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;
}
}
公共类ExtendedDataAnnotationsModelMetadataProvider:DataAnnotationsModelMetadataProvider
{
私有静态bool addImplicitRequiredAttributeForValueTypes=false;
公共静态bool AddImplicitRequiredAttributeForValueTypes
{
得到
{
返回addImplicitRequiredAttributeForValueTypes;
}
设置
{
addImplicitRequiredAttributeForValueTypes=值;
}
}
受保护的重写ModelMetadata CreateMatadata(IEnumerable属性、类型containerType、Func modelAccessor、类型modelType、字符串propertyName)
{
var result=base.CreateMetadata(属性、containerType、modelAccessor、modelType、propertyName);
如果(!AddImplicitRequiredAttributeForValueTypes&&modelType.IsValueType&&attributes.OfType().Any())
{
result.IsRequired=false;
}
返回结果;
}
}
我猜您正面临一个MVC错误。无论发生什么情况,即使您使用
DataAnnotationsModelValidatorProvider
.AddImplicitRequiredAttributeForValueTypes = false;
这已经得到讨论和报告。本例进一步说明,当隐式required触发时,它不会阻止执行IValidatableObject
。如果您从第二个链接运行演示,您可以复制您的案例,需要的地方总是正确的
无论如何,这很容易解决,因为如果你说A显然不是必需的
与说它可以为null是一样的,那么就这样做:
public bool? A { get; set; }
我在好几个地方遇到过这个问题,并且实现了一个类似这样的简单修复
if (metadata.ModelType == typeof(System.Boolean))
{
metadata.IsRequired = false;
}
正如您所指出的,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))
{ ... }
modelmatadata=modelmatadata.FromLambdaExpression(表达式,html.ViewData);
if((metaData.ModelType.IsValueType&&metaData.ModelType.GetCustomAttributes(typeof(RequiredAttribute),false)。Any())||
(!metaData.ModelType.IsValueType&&metaData.IsRequired))
{ ... }
根据您是否有[必需]选项,以下选项将返回true或false
typeof().GetProperty().GetCustomAttributes(typeof(RequiredAttribute),false)。Any()
如果您像我一样在EditorTemplate中工作,您还需要一个步骤:
var metaData = ModelMetadata.FromLambdaExpression(Model => Model, ViewData);
var required = metaData.ContainerType.GetProperty(metaData.PropertyName).GetCustomAttributes(typeof (RequiredAttribute), false).Any();
您需要从模型元数据中获取容器类型,以便检查特定属性的属性;否则,您只需检查属性的数据类型的属性,而不是属性的属性,,如果您希望它也适用于可为空的类型:
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;
}
将属性设置为
bool?
意味着我不能使用需要布尔值的内置html帮助程序,如CheckBoxFor
。是的-我可以编写自己的html帮助程序,但我仍然很好奇,是否像我在OP中那样编写模型元数据提供程序更有意义。这是您的预期行为,考虑到MVC目前的行为方式,我猜自定义提供程序是您唯一的选择。属性是否触发验证?因为IsRequired
为true
并不意味着属性无效。不,它不是。我不需要这个来验证,但对于仅用于显示的自定义HTML帮助程序,只需在MVC5中简单设置DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes=false
就不会自动为不可为空的值类型添加RequiredAttribute
。这真是太棒了。如果它对任何人都有帮助,我必须组合一个标签扩展方法,如果字段是必需的,则在字段标签前面放置适当的“*”html字符串。它是MVC5,我仍然对ValueTypes返回true存在一些问题。有很多表单字段(49),所以我修改了上面的内容,使用反射来搜索metadata.ContainerType以定位所需的属性:metadata.ModelType.IsValueType&&metadata.ContainerType.GetProperty(metadata.PropertyName).GetCustomAttributes(typeof(RequiredAttribute),false).Any()。这在MVC5.2上也起作用@ViewData.ModelMetadata.IsRequired
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;
}