ASP.NET MVC: устранение ошибок ввода (восстанавливаемых) и отсутствующих данных (невосстанавливаемых) пользователем - PullRequest
0 голосов
/ 26 октября 2009

Предположим, у меня есть эта модель:

public class ViewModel
{
  [Required]
  public string UserInput { get; set; }
  [Required]
  public Guid EntityId { get; set; }
}

Теперь, когда пользовательский ввод неправильный, я хочу повторно отобразить ту же страницу, но с ошибками проверки (например, / Изменить). Однако, когда EntityId неверен, я хочу перенаправить на другую страницу (например, /Create).

Я могу сделать это вручную внутри каждого контроллера ...

if (!ModelState.IsValidField("EntityId")) { redirect }
//or
if (string.IsNullOrEmpty(data.EntityId)) { redirect }

но это немного скучно и нарушает СУХОЙ. Отображение нескольких объектов, вложенных моделей просмотра с объектами ... слишком громоздко. Мне бы лучше иметь что-то вроде ModelState.IsValidUserData и ModelState.IsValidCriticalData. Но такого нет.

Теперь EntityId на самом деле связан с помощью моего пользовательского связывателя модели, который знает , что он критически важен. Итак, есть такое решение:

  1. Обычные поля заполняют ModelState ошибками, как обычно.
  2. (a) Критические поля связываются с помощью пользовательского связывателя модели, который выдает специальное «CriticalModelErrorException». Действия контроллера имеют атрибут [HandleCrirticalError ("action", "controller ')] - который обрабатывает критические ошибки и перенаправляет на указанное действие.
  3. (b) Критические поля связываются с помощью пользовательского связывателя модели, который устанавливает свойство BaseController.CriticalModelErrors (очевидно, что все контроллеры получены из базового класса суперконтроллера). Каждое действие может свободно проверять ModelState.IsValid и base.CriticalModelErrors и вести себя свободно на этом основании.
  4. (c) Критические поля связываются с помощью пользовательского связывателя модели, который устанавливает ошибки состояния модели специального формата, например, AddModelError (name, "! CRITICAL! Text"; тогда у базового контроллера есть метод, который обнаруживает такие строки.

2a пример:

[HandleCriticalError("Create")] // uses the same controller
[HandleModelStateError("Edit")] // redisplays page with validation errors
public ActionResult Edit(ViewModel data)
{
  // here we know both our data entities and user data are valid and safe
}

2b пример

public ActionResult Edit(ViewModel data)
{
  if (!ModelState.IsValid)
     return View(data);
  if (base.CriticalModelErrors.Count > 0)
     return RedirectToAction("Create");
  // here we know both our data entities and user data are valid and safe
}

2c пример

protected bool HasCriticalErrors()
{
   return ModelState.Any(x => x.Value.Errors.Any(x => x.ErrorMessage.StartsWith("!CRITICAL!")))
}
// then same as 2b

Теперь вопросы: как с этим справляются другие приложения и разработчики (вы и ваши приложения)? Какой из них вы бы предпочли? Есть ли недостатки или лучшие решения?

1 Ответ

1 голос
/ 26 октября 2009

Используйте тот, который вводит наибольшее количество автоматизации для вас, чтобы вам не пришлось повторять один и тот же код на моих местах. Как вы уже сделали, я бы пошел с 2a , но немного изменил бы его, чтобы я не использовал эти атрибуты для каждого отдельного действия, а скорее для всего класса Controller. Если это вообще возможно (если требуется хотя бы большинством действий). Если вам нужно исключить определенные действия, создайте отдельный фильтр действий, который отключит перенаправление.

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