Проверка объектов в ViewModel без добавления классов проверки CSS - PullRequest
2 голосов
/ 13 января 2012

У меня есть следующие модели представлений:

public class Search {
    public int Id { get; set; }

    [Required(ErrorMessage = "Please choose a name.")]
    public string Name { get; set; }

    [ValidGroup(ErrorMessage = "Please create a new group or choose an existing one.")]
    public Group Group { get; set; }
}

public class Group {
    public int Id { get; set; }
    public string Name { get; set; }
}

Я определил настраиваемый атрибут проверки следующим образом:

public class ValidGroupAttribute : ValidationAttribute {
    public override bool IsValid(object value) {
        if (value == null)
            return false;

        Group group = (Group)value;

        return !(string.IsNullOrEmpty(group.Name) && group.Id == 0);
    }
}

У меня есть следующее представление (некоторые для краткости опущены):

    @Html.ValidationSummary()

    <p>
        <!-- These are custom HTML helper extensions. -->
        @Html.RadioButtonForBool(m => m.NewGroup, true, "New", new { @class = "formRadioSearch", id = "NewGroup" })
        @Html.RadioButtonForBool(m => m.NewGroup, false, "Existing", new { @class = "formRadioSearch", id = "ExistingGroup" })
    </p>
    <p>
        <label>Group</label>
        @if (Model.Group != null && Model.Group.Id == 0) {
            @Html.TextBoxFor(m => m.Group.Name)
        }
        else {
            @Html.DropDownListFor(m => m.Group.Id, Model.Groups)
        }
    </p>

У меня проблема с классом проверки input-validation-error, который не применяется к входным данным группы.Я предполагаю, что это потому, что фреймворк пытается найти поле с id="Group", а генерируемая разметка имеет либо id="Group_Id", либо id=Group_Name.Есть ли способ, которым я могу применить класс?

http://f.cl.ly/items/0Y3R0W3Z193s3d1h3518/Capture.PNG

Обновление

Я пытался реализовать IValidatableObject в модели группового представления вместо использованияатрибут проверки, но я все еще не могу применить класс CSS:

public class Group : IValidatableObject
{
    public int Id { get; set; }
    public string Name { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
        if (string.IsNullOrEmpty(Name) && Id == 0) {
            yield return new ValidationResult("Please create a new group or select an existing one.", new[] { "Group.Name" });
        }
    }
}

Обновление 2

Самостоятельная проверка не работает.Я думаю, это потому, что второй параметр в конструкторе ValidationResult не используется в инфраструктуре MVC.

From: http://www.devtrends.co.uk/blog/the-complete-guide-to-validation-in-asp.net-mvc-3-part-2

В некоторых ситуациях вы можетесоблазн использовать вторую перегрузку конструктора ValidationResult, которая принимает IEnumerable имен членов.Например, вы можете решить, что хотите отобразить сообщение об ошибке в обоих сравниваемых полях, поэтому измените код на следующий:

return new ValidationResult( FormatErrorMessage(validationContext.DisplayName), new[] { validationContext.MemberName, OtherProperty });

Если вы запустите свой код, выне найдете абсолютно никакой разницы.Это связано с тем, что хотя эта перегрузка присутствует и предположительно используется где-либо еще в платформе .NET, платформа MVC полностью игнорирует ValidationResult.MemberNames.

1 Ответ

1 голос
/ 13 января 2012

Я придумала решение, которое работает, но явно работает.

Я удалил атрибут валидации и вместо этого создал пользовательский механизм связывания модели, который вручную добавляет ошибку в ModelStateсловарь для свойства Group.Name.

public class SearchBinder : DefaultModelBinder {
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext,
       PropertyDescriptor propertyDescriptor) {
        if (propertyDescriptor.Name == "Group" &&
            bindingContext.ValueProvider.GetValue("Group.Name") != null &&
            bindingContext.ValueProvider.GetValue("Group.Name").AttemptedValue == "") {
            ModelState modelState = new ModelState { Value = bindingContext.ValueProvider.GetValue("Group.Name") };
            modelState.Errors.Add("Please create a new group or choose an existing one.");
            bindingContext.ModelState.Add("Group.Name", modelState);
        }
        base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
    }
}

// Register custom model binders in Application_Start()
ModelBinders.Binders.Add(typeof(SearchViewModel), new SearchBinder());

Поскольку ModelState["Group.Name"] теперь имеет запись об ошибке, класс CSS отображается в разметке.

Я бы очень предпочел, если быспособ сделать это с помощью идиоматической проверки в MVC.

Решено!

Найден правильный способ сделать это.Я указывал неправильное имя свойства в самопроверяющемся классе, поэтому ключ, который добавлялся в словарь ModelState, был Group.Group.Name.Все, что я должен был сделать, это изменить возвращенный ValidationResult.

yield return new ValidationResult("Please create a new group or select an existing one.", new[] { "Name" });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...