В ASP.NET MVC3, как вручную применить проверку к сгенерированным свойствам - PullRequest
3 голосов
/ 28 ноября 2011

Вот ситуация, у меня есть список из примерно 20 свойств (называемых атрибутами), которые я определил в своей базе данных.Он состоит из имени, возможных значений, необязательного регулярного выражения, логического значения, которое указывает, что поле является обязательным, и т. Д.

В моей ViewModel я получаю список атрибутов, и в моем представлении в виде списка у меня есть хороший EditorTemplateдля AttributeViewModel, чтобы показать их, используя крутой 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; }
}

Мой вид выглядит следующим образом (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" />
 }

Вот интересный момент, это мой EditorTemplate для AttributeValues:

@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 ]

1 голос
/ 29 ноября 2011

Это не проверено. Возможно, вам придется поиграть с этим, чтобы получить желаемый результат.

Сначала создайте свой собственный 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();
    }
}

Затем добавьте следующее к Application_Start в Global.asax.cs:

ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(new MyModelMetadataValidatorProvider()); 
1 голос
/ 28 ноября 2011

Рассмотрите возможность использования FluentValidation.Net (который доступен через NuGet из следующих Install-Package FluentValidation.MVC3).Это делает любой вид относительно сложной проверки данных намного проще и интуитивно понятнее, чем декларативный стиль.Также поддерживается проверка на стороне клиента.

0 голосов
/ 28 ноября 2011

Надеюсь, я правильно понимаю ваш вопрос.Вы хотите добавить собственные атрибуты проверки, аннотации и логику проверки в ваши представления?

Если это так, вы хотите перейти в пространство имен 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 для получения дополнительной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...