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

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

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

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?

Ответы [ 9 ]

20 голосов
/ 06 марта 2011

Для этого можно использовать атрибут привязки: http://ittecture.wordpress.com/2009/05/01/tip-of-the-day-199-asp-net-mvc-defining-model-binding-explicitly/

Лучшим вариантом будет использование ViewModels.

http://weblogs.asp.net/shijuvarghese/archive/2010/02/01/view-model-pattern-and-automapper-in-asp-net-mvc-applications.aspx

19 голосов
/ 20 сентября 2012

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

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

или

ModelState["Avatar"].Errors.Clear();
5 голосов
/ 06 марта 2011

Это обсуждается в книге Стива Сандерсона 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 атрибутами проверки данных, а в этом случае вы проверяете их только после того, как пользователь заполнил весь мастер, и попытаетесь отправить их в базу данных. С точки зрения пользователя это было бы очень неприятно ...

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

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

4 голосов
/ 10 июля 2015

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

if (ModelState["PropertyName"] != null) ModelState["PropertyName"].Errors.Clear();
2 голосов
/ 20 сентября 2012

Я просто возился с формами проверки и 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";
    }
}
0 голосов
/ 07 января 2019
public override void OnActionExecuting(ActionExecutingContext context)
{
    var modelstate = context.ModelState;
    var keys = modelstate.Keys.Where(x => ExculdeFeilds.Split(",").ToList().Contains(x));
    foreach (var item in keys)
    {
        modelstate[item].ValidationState = ModelValidationState.Valid;
    }
    if (!modelstate.IsValid)
    {
        context.Result = new BadRequestObjectResult(context.ModelState);
    }
}
0 голосов
/ 09 августа 2017

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

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

[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
}
0 голосов
/ 22 ноября 2013

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();
        }
    }
}
0 голосов
/ 25 марта 2013

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

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


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

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