Подтвердить что ты не робот

Есть ли способ игнорировать некоторые свойства (в POCO) при проверке формы в ASP.NET MVC3?

У меня есть мастер регистрации для регистрации нового пользователя. Когда я пытаюсь перейти на вторую страницу, я получаю ошибки проверки, потому что мой объект User еще не был полностью заполнен. Можно ли каким-либо образом указать каждому ActionMethod игнорировать некоторые свойства при проверке проверки ModelState.IsValid?

например. (Упрощенный код pseduo)

public class User
{
   [Required]
   public string Name; // Asked on page 1.
   [Required]
   public int Age; // Asked on page 1.
   [Required]
   public string Avatar;  // Asked on Page 2.
}

он жалуется на то, что Аватар требуется/не может быть нулевым. Но у меня нет возможности попросить пользователя заполнить эту информацию до следующей страницы.

Можно ли просить игнорировать эту проверку на стр. 1?

4b9b3361

Ответ 2

В действии просто удалите ошибки для элементов, еще не проверенных. Это делает вашу модель действительной для уже проверенных элементов.

foreach (var error in ModelState["Avatar"].Errors)
 {
      ModelState["Avatar"].Errors.Remove(error);
 }

или

ModelState["Avatar"].Errors.Clear();

Ответ 3

Это обсуждается в книге Стив Сандерсон asp.net mvc 2, стр. 486.

Создайте настраиваемый атрибут ValidateIncomingValuesOnlyAttribute, который наследует ActionFilterAttribute и применит его к вашему классу контроллера.

Отменить метод OnActionExecuting:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{

var modelState = filterContext.Controller.ViewData.ModelState;
var incomingValues = filterContext.Controller.ValueProvider;

var keys = modelState.Keys.Where(x => !incomingValues.ContainsPrefix(x));
foreach(var key in keys)
{
modelState[key].Errors.Clear();
}
}

Таким образом, вы проверяете данные, относящиеся только к каждому шагу мастера. Затем вам нужна страница подтверждения без ввода данных для отправки проверенных данных на сервер.

Но прежде всего, прочитайте книгу Стива Сандерсона, он дает рабочее решение этой и вашей другой проблеме.

Добавление:

Если вместо вышесказанного вы решите отобразить на viewmodel, будьте осторожны, потому что вам либо придется:

а. Не украшайте свойства viewmodel атрибутами атрибутов data validation, в этом случае вы проверяете только после того, как пользователь заполнил весь мастер и попытайтесь отправить в базу данных. Это будет очень неприятно с точки зрения пользователя...

б. Кроме того, вам все равно придется использовать технику, описанную S Sanderson, т.е. Очистить все ошибки проверки, которые не относятся к полям текущего шага.

Я не вижу принятого ответа, отвечая на вопрос, как его спрашивали.

Ответ 4

Чтобы игнорировать свойства ModelState, вот простейший код.

if (ModelState["PropertyName"] != null) ModelState["PropertyName"].Errors.Clear();

Ответ 5

Я просто возился с формами проверки и ModelState и обнаружил очень простое решение вашей проблемы без написания нового метода, переопределения и т.д.

ModelState.Where(m => m.Key == "Avatar").FirstOrDefault().Value.Errors.Clear();
// At  this point ModeState will have an error for that Key,
// by applying Clear it remove the error so modelstate becomes valid again

if (!ModelState.IsValid) {
    return View("User", model);
} else {     
    try  {
        // do something
    } catch {
        TempData["errorMessage"] = "something went wrong";
    }
}

Ответ 6

Как насчет пользовательского класса IgnoreModelErrors?

http://mrbigglesworth79.blogspot.in/2011/12/partial-validation-with-data.html


Наследовать от класса ActionFilterAttribute и очищать ошибки [на основе совпадений имен или шаблонов регулярных выражений] в OnActionExecuting, как показано в приведенной выше ссылке. Это будет более чистым.

Ответ 7

ViewModels, которые точно соответствуют отправляемым данным, обычно рекомендуются, потому что они очень предсказуемы, и вы получаете все преимущества сильной печати, строительных лесов и т.д. С другой стороны, использование BindAttribute может потребовать от вас свойства, которые не отправляются обратно в учетную запись, и могут привести к бесшумному сбою во время выполнения при изменении имени свойства, но строки BindAttribute Include или Exclude не являются. Избегание использования атрибутов проверки имеет множество недостатков в MVC и должно быть заменено некоторыми другими методами проверки, такими как IValidatableObject или FluentValidation.

Несмотря на все преимущества ViewModels и предостережения, которые сопровождают BindAttribute, иногда может быть предпочтительнее использовать BindAttribute и частично публиковать в модели/режиме просмотра. Этот ActionFilterAttribute охватывает этот точный случай. Он принимает код @awrigley, процитированный шаг дальше, но вместо устранения ошибок на основе ValueProvider он очищает ошибки на основе использования BindAttribute (например, Include и Exclude). Этот атрибут можно безопасно добавить в GlobalFilterCollection, потому что он не изменит поведение проверки MVC, если BindAttribute не был применен. Обратите внимание: я не очень использовал это, но он хорошо подходит для моих основных случаев.

using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Mvc;

/// <summary>
/// When the BindAttribute is in use, validation errors only show for values that 
/// are included or not excluded.
/// </summary>
public class ValidateBindableValuesOnlyAttributes : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var modelState = filterContext.Controller.ViewData.ModelState;
        var includedProperties = filterContext.ActionDescriptor.GetParameters()
            .SelectMany(o => o.BindingInfo.Include.Select(name => (string.IsNullOrWhiteSpace(o.BindingInfo.Prefix) ? "" : o.BindingInfo.Prefix + ".") + name));
        var excludedProperties = filterContext.ActionDescriptor.GetParameters()
            .SelectMany(o => o.BindingInfo.Exclude.Select(name => (string.IsNullOrWhiteSpace(o.BindingInfo.Prefix) ? "" : o.BindingInfo.Prefix + ".") + name));

        var ignoreTheseProperties = new List<KeyValuePair<string, ModelState>>();
        if (includedProperties.Any())
        {
            ignoreTheseProperties.AddRange(modelState.Where(k => !includedProperties.Any(name => Regex.IsMatch(k.Key, "^" + Regex.Escape(name) + @"(\.|\[|$)"))));
        }
        ignoreTheseProperties.AddRange(modelState.Where(k => excludedProperties.Any(name => Regex.IsMatch(k.Key, "^" + Regex.Escape(name) + @"(\.|\[|$)"))));

        foreach (var item in ignoreTheseProperties)
        {
            item.Value.Errors.Clear();
        }
    }
}

Ответ 8

У меня был ссылочный объект, который не должен был быть проверен.

Удалено из проверки в начале действия:

[HttpPost]
public async Task<IActionResult> Post([FromBody] Contact contact)
{
  var skipped = ModelState.Keys.Where(key => key.StartsWith(nameof(Contact.Portfolios)));
  foreach (var key in skipped)
    ModelState.Remove(key);
    //ModelState doesn't include anything about Portfolios which we're not concerned with

  if (!ModelState.IsValid)
    return BadRequest(ModelState);

  //Rest of action
}