Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net mvc 3 MVC HtmlHelper vs FluentValidation 3.1:获取模型元数据时遇到的问题_Asp.net Mvc 3_Html Helper_Fluentvalidation_Modelmetadata_Isrequired - Fatal编程技术网

Asp.net mvc 3 MVC HtmlHelper vs FluentValidation 3.1:获取模型元数据时遇到的问题

Asp.net mvc 3 MVC HtmlHelper vs FluentValidation 3.1:获取模型元数据时遇到的问题,asp.net-mvc-3,html-helper,fluentvalidation,modelmetadata,isrequired,Asp.net Mvc 3,Html Helper,Fluentvalidation,Modelmetadata,Isrequired,我为标签创建了一个HtmlHelper,如果需要关联字段,则该标签的名称后面会有一个星号: publicstaticmvchtmlstringlabelforr( 此HtmlHelper(html,表达式) { 返回标签助手( html, ModelMetadata.FromLambdaExpression(表达式,html.ViewData), ExpressionHelper.GetExpressionText(表达式), 无效); } 私有静态MvcHtmlString LabelHelp

我为标签创建了一个HtmlHelper,如果需要关联字段,则该标签的名称后面会有一个星号:

publicstaticmvchtmlstringlabelforr(
此HtmlHelper(html,表达式)
{
返回标签助手(
html,
ModelMetadata.FromLambdaExpression(表达式,html.ViewData),
ExpressionHelper.GetExpressionText(表达式),
无效);
}
私有静态MvcHtmlString LabelHelper(HtmlHelper帮助程序、模型元数据、字符串htmlFieldName、字符串文本)
{
…//检查元数据。此处需要
…//如果需要,显示星号
}
如果我在ViewModel中的属性上使用DataAnnotations和slap[Required],则我的私有LabelHelper中的metadata.IsRequired将等于True,并且一切都将按预期工作

但是,如果我使用FluentValidation 3.1并添加这样一个简单的规则:

公共类CheckEmailViewModelValidator:AbstractValidator
{
公共检查EmailViewModelValidator()
{
规则(m=>m.Email)
.NotNull()
.EmailAddress();
}
}
。。。在我的LabelHelper中,metadata.IsRequired将被错误地设置为false。(不过验证器可以工作:您不能提交空字段,它需要像电子邮件一样)。
其余元数据看起来是正确的(例如:metadata.DisplayName=“Email”)。
理论上,如果使用Rule.NotNull(),FluentValidator将在属性上slaprequiredAttribute

供参考: 我的ViewModel:

[Validator(typeof(CheckEmailViewModelValidator))]
公共类CheckEmailViewModel
{
//[必需]
[显示(Name=“电子邮件”)]
公共字符串电子邮件{get;set;}
}
我的控制器:

公共类成员控制器:控制器
{
[HttpGet]
公共行动结果检查电子邮件()
{
var model=新的CheckEmailViewModel();
返回视图(模型);
}
}

非常感谢您的帮助。

默认情况下,MVC将DataAnnotations属性用于两个不同的目的—元数据和验证


当您在MVC应用程序中启用FluentValidation时,FluentValidation将钩住验证基础结构而不是元数据,MVC将继续使用元数据的属性。如果您想对元数据和验证使用FluentValidation,那么您需要编写MVC的ModelMetadataProvider的自定义实现,该实现知道如何查询验证器类-这不是FluentValidation现成支持的功能。

我有一个自定义ModelMetadataProvider,可以增强默认值DataAnnotations提供了以下内容:

  • 如果通过DisplayAttribute未指定任何值,则从驼峰大小写的propertyname拆分字符串填充“DisplayName”
  • 如果ModelMetadata.IsRequired设置为false,它将检查是否存在任何fluent验证程序规则(NotNull或NotEmpty类型)
  • 我确实检查了Jeremy准备的源代码,但是我还没有准备好进行全面的检查,所以我混合并匹配了源代码,以避免丢失默认行为。你可以找到它

    下面是从post中获取的代码,其中包含一些额外的优点

    公共类CustomModelMetadataProvider:DataAnnotationsModelMetadataProvider { 只读的IValidatorFactory; 公共CustomModelMetadataProvider(IValidatorFactory工厂) :base(){ 这个工厂=工厂; } //大写字母后接小写字母,但不在现有单词边界上(例如开头) Regex\u camelCaseRegex=newregex(@“\B\p{Lu}\p{Ll}”,RegexOptions.Compiled); //如果尚未指定显示名,则从模型的属性名创建一个好的显示名 受保护的重写ModelMetadata GetMetadataForProperty( 函数模型访问器, 类型containerType, PropertyDescriptor PropertyDescriptor){ ModelMetadata metadata=base.GetMetadataForProperty(modelAccessor、containerType、propertyDescriptor); metadata.IsRequired=metadata.IsRequired | | IsNotEmpty(containerType,propertyDescriptor.Name); 如果(metadata.DisplayName==null) metadata.DisplayName=displayNameFromCamelCase(metadata.GetDisplayName()); if(string.IsNullOrWhiteSpace(metadata.DisplayFormatString)&& (propertyDescriptor.PropertyType==typeof(DateTime)| | propertyDescriptor.PropertyType==typeof(DateTime?){ metadata.DisplayFormatString=“{0:d}”; } 返回元数据; } 字符串displayNameFromCamelCase(字符串名称){ 名称=_camelCaseRegex.Replace(名称,$0); 如果(名称、尾数(“Id”)) name=name.Substring(0,name.Length-3); 返回名称; } bool IsNotEmpty(类型、字符串名称){ bool notEmpty=false; var validator=factory.GetValidator(类型); if(验证器==null) 返回false; IEnumerable validators=validator.CreateDescriptor().GetValidatorsForMember(名称); notEmpty=validators.OfType().Cast() .Concat(validators.OfType().Cast()).Count()>0; 返回notEmpty; } }
    仅限于杰里米的评论。我没有写“MVC的ModelMetadataProvider的自定义实现,它知道如何查询验证器类”,基本上是因为我不知道如何立即执行,研究它可能需要很多时间。如果你能提供一个这样的例子,那绝对有帮助!我也不知道。我扩展了LabelFor并向其添加了类。这不是最好的解决方案,但我没有时间研究如何实现ModelMetadataProvider。但如果我这样做了,我会在这里写解决方案。传递给
    CustomModelMetaDataProvider
    的构造函数中的
    IValidatorFactory
    是什么?@skeletank这是一个流畅的验证抽象。正如我所记得的,它用于解析中的验证器
    public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
    {
        readonly IValidatorFactory factory;
        public CustomModelMetadataProvider(IValidatorFactory factory) 
            : base() {
            this.factory = factory;
        }
    
        // Uppercase followed by lowercase but not on existing word boundary (eg. the start) 
        Regex _camelCaseRegex = new Regex(@"\B\p{Lu}\p{Ll}", RegexOptions.Compiled);
        // Creates a nice DisplayName from the model’s property name if one hasn't been specified 
    
        protected override ModelMetadata GetMetadataForProperty(
            Func<object> modelAccessor, 
            Type containerType,
            PropertyDescriptor propertyDescriptor) {
    
            ModelMetadata metadata = base.GetMetadataForProperty(modelAccessor, containerType, propertyDescriptor);
            metadata.IsRequired = metadata.IsRequired || IsNotEmpty(containerType, propertyDescriptor.Name);
            if (metadata.DisplayName == null)
                metadata.DisplayName = displayNameFromCamelCase(metadata.GetDisplayName());
    
            if (string.IsNullOrWhiteSpace(metadata.DisplayFormatString) && 
                (propertyDescriptor.PropertyType == typeof(DateTime) || propertyDescriptor.PropertyType == typeof(DateTime?))) {
                metadata.DisplayFormatString = "{0:d}";
            }
    
            return metadata;
        }
    
        string displayNameFromCamelCase(string name) {
            name = _camelCaseRegex.Replace(name, " $0");
            if (name.EndsWith(" Id"))
                name = name.Substring(0, name.Length - 3);
            return name;
        }
    
        bool IsNotEmpty(Type type, string name) {
            bool notEmpty = false;
            var validator = factory.GetValidator(type);
    
            if (validator == null)
                return false;
    
            IEnumerable<IPropertyValidator> validators = validator.CreateDescriptor().GetValidatorsForMember(name);
    
            notEmpty = validators.OfType<INotNullValidator>().Cast<IPropertyValidator>()
                                 .Concat(validators.OfType<INotEmptyValidator>().Cast<IPropertyValidator>()).Count() > 0;
            return notEmpty;
        }
    }