在ASP.NET MVC3中,如何在生成的属性上手动应用验证

时间:2011-11-28 14:28:06

标签: asp.net-mvc-3 validation

在这种情况下,我列出了我在数据库中定义的大约20个属性(称为属性)。这包括名称,可能的值,可选的正则表达式,表示该字段是必需的布尔值等。

在我的ViewModel中,我得到属性列表,在我的视图中,作为List,我有一个很好的EditorTemplate for AttributeViewModel,使用Steve Sanderson的酷BeginCollectionItem来显示它们,以确保帖子被绑定回AttributeViewModel列表(这很好用)。

我的AttributeViewModel如下所示:

public class AttributeViewModel
{
    public string Description { get; set; }
    public IEnumerable<SelectListItem> Values { get; set; }
    public string SelectedValue { get; set; }
    public byte RenderAs { get; set; }
    public int AttributeID { get; set; }
    public int ID { get; set; }
    public int RegexValidation { get; set; }
    public bool IsRequired { get; set; }
}

My View看起来像这样(edit.cshtml):

@model Company.Services.ViewModels.StaffMemberViewModel

<h2>Edit</h2>
@using (Html.BeginForm())
{
    Some fields here, nothing of interest.

    @Html.EditorFor(model => model.AttributeValues)

    <input type="submit" value="Send" />
 }

这是有趣的一点,这是我对AttributeValues的EditorTemplate:

@using Company.Web.Helpers // This is where "BeginCollectionItem" lives
@model Company.Services.ViewModels.AttributeViewModel

using (Html.BeginCollectionItem("attributes"))
{
    <div class="editor-label">
        @Model.Description
    </div>
    <div class="editor-field">
       @Html.DropDownListFor(m => m.SelectedValue, new SelectList(Model.Values, "Value", "Text"), "-- Select --")
       @Html.HiddenFor(model => model.AttributeID) 
    </div>
}

我想要做的是使用IsRequired和RegexValidation来确保每个属性的SelectedValue有效。我该怎么做呢?如果可能的话,我真的很想利用MVC3验证框架和不引人注意的验证,就像我“通常”那样。

我显然无法动态添加RequiredAttribute或RegularExpressionAttribute,因为这些对于列表中的每个属性对象都不同。

3 个答案:

答案 0 :(得分:1)

考虑使用FluentValidation.Net(可通过以下Install-Package FluentValidation.MVC3中的NuGet获得)。它使任何类型的相对复杂的数据验证比声明式样式更简单,更直观。也支持客户端验证。

答案 1 :(得分:1)

这是未经测试的。你可能不得不玩这个来获得你想要的结果。

首先,创建自定义DataAnnotationsModelValidatorProvider类:

public class MyModelMetadataValidatorProvider : DataAnnotationsModelValidatorProvider
{
    internal static DataAnnotationsModelValidationFactory DefaultAttributeFactory = Create;
    internal static Dictionary<Type, DataAnnotationsModelValidationFactory> AttributeFactories = 
        new Dictionary<Type, DataAnnotationsModelValidationFactory>() 
        {
            {
                typeof(RequiredAttribute),
               (metadata, context, attribute) => new RequiredAttributeAdapter(metadata, context, (RequiredAttribute)attribute)
            },
            {
                typeof(RegularExpressionAttribute),
               (metadata, context, attribute) => new RegularExpressionAttributeAdapter(metadata, context, (RegularExpressionAttribute)attribute)
            }
        };

    internal static ModelValidator Create(ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute)     
    {
        return new DataAnnotationsModelValidator(metadata, context, attribute);
    }

    protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
    {
        List<ModelValidator> vals = base.GetValidators(metadata, context, attributes).ToList(); 
        if (metadata.ModelType.Name == "SelectedValue")
        {
            // get our parent model
            var parentMetaData = ModelMetadataProviders.Current.GetMetadataForProperties(context.Controller.ViewData.Model, 
                metadata.ContainerType);

            // get the associated AttributeId
            var attributeId = Convert.ToInt32(parentMetaData.FirstOrDefault(p => p.PropertyName == "AttributeId").Model);

            // get AttributeViewModel with specified AttributeId from repository
            var attributeViewModel = _db.AttributeViewModels.FirstOrDefault(x => x.AttributeId == attributeId);

            DataAnnotationsModelValidationFactory factory;

            // check if required
            if (attributeViewModel.IsRequired)
            {
                // must be marked as required
                var required = new RequiredAttribute();
                required.ErrorMessage = attributeViewModel.Description.Trim() +
                    " is Required";
                if (!AttributeFactories.TryGetValue(required.GetType(), out factory))
                    factory = DefaultAttributeFactory;

                vals.Add(factory(metadata, context, required));
            }

            // check for regex
            if (attributeViewModel.RegexValidation > 0)
            {
                // get regex from repository
                var regexValidation = _db.attributeViewModels.
                    FirstOrDefault(x => x.RegexValidation == attributeViewModel.RegexValidation);
                var regex = new RegularExpressionAttribute(regexValidation.Pattern);
                regex.ErrorMessage = attributeViewModel.Description.Trim() +
                    " is not in a valid format";
                if (!AttributeFactories.TryGetValue(regex.GetType(), out factory))
                    factory = DefaultAttributeFactory;

                vals.Add(factory(metadata, context, regex));
            }
        }
        return vals.AsEnumerable();
    }
}

然后,将以下内容添加到Global.asax.cs中的Application_Start

ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(new MyModelMetadataValidatorProvider()); 

答案 2 :(得分:0)

我希望我能正确理解你的问题。您想为视图添加自定义验证属性,注释和验证逻辑吗?

如果是这样,您想要转到System.ComponentModel.DataAnnotation命名空间。您的验证逻辑将放在源自ValidationAttribute

的类中
using System.ComponentModel.DataAnnotation;

public class MyValidationAttribute : ValidationAttribute
{
    string readonly _validationParameter;

    public MyValidationAttribute(string validationParameter)
    {
        _validationParameter = validationParameter;
    }

    protected override ValidationResult IsValid(object value,
        ValidationContext validationContext)
    {
        // add validation logic here
        if (//not valid)
        {
            var errorMessage = FormatErrorMessage(validationContext.DisplayName);
            return new ValidationResult(errorMessage);
        }
        return ValidationResult.Success;
    }
}

您可以将该属性应用于任何模型属性

[Required]
[MyValidationAttribute("parameter", ErrorMessage="Error in {0}")]
public string MyProperty { get; set; }

我希望这会有所帮助。见

Professional ASP.NET MVC 3

第127页了解更多信息。