Шаблон проектирования для рефакторинга и обработки неисключительных ошибок в контроллере MVC - PullRequest
1 голос
/ 22 марта 2012

В моем приложении MVC3 у меня есть класс «запросов», специфичный для каждого контроллера, который выполняет преобразования между сущностями домена и преобразует их для просмотра моделей. Я делаю это, чтобы поддерживать чистоту моих контроллеров, и проще проводить модульное тестирование контроллеров и запросов по отдельности.

Однако существуют случаи, когда метод запроса должен передавать неисключительные сообщения об ошибках в представление (например, объект не был найден). Однако, поскольку мой контроллер получает только ViewModel от метода запроса, а не код возврата любого типа, я обнаружил только две опции для передачи этой ошибки:

  1. Выдать исключение из метода запроса и использовать блок Try / Catch, чтобы перехватить исключение в контроллере.

  2. Добавьте свойство к модели представления с именем «ErrorMessage», которое заполняется методом запроса, который представление использует для выполнения логики отображаемых потребностей.

Поскольку это не исключительные случаи, и я знаю, что не следует использовать Try / Catch для управления потоком программы, я решил использовать второй метод. Хотя сейчас это работает, мне кажется, что это «грязно» по следующим причинам:

  • Контроллер должен получать всю модель представления в случае возникновения ошибки только для того, чтобы получить свойство ErrorMessage.
  • Представление должно иметь жестко запрограммированную логику и два раздела для отображения либо ошибки, либо нормального содержимого
  • Хотя я мог бы добавить if (Model.ErrorMessage != null) логику в мой контроллер, чтобы определить, какой вид пройти, он все еще не выглядит как «чистое» решение.

Существуют ли какие-либо шаблоны проектирования, которые я мог бы использовать, чтобы помочь мне реорганизовать этот код и сделать его чище?

Пример представления модели:

public class ApplicationViewModel
{
  public string ErrorMessage { get; set; }
  public int Id { get; set; }
  public string Name { get; set; }
  // Other properties here...
}

Пример метода контроллера:

public ActionResult Retrieve(Guid guid)
{
  return View("Application", _applicationQueries.GetApplicationViewModel(guid));
}

Пример метода ApplicationQueries:

public ApplicationViewModel GetApplicationViewModel(Guid guid)
{
  var applicationViewModel = new applicationViewModel();

  if (!_applicationServices.Exists(guid))
  {
    applicationViewModel.ErrorMessage = "The requested application does not exist.";
    return applicationViewModel;
  }

  // More code here that checks things which might set the ErrorMessage property...

  var application = _applicationServices.GetApplicationByGuid((Guid)guid);
  Mapper.Map(grantApplication, grantApplicationViewModel);
  return grantApplicationViewModel;
}

Фрагмент из Application.cshtml Представление для обработки ошибок:

@model MyApp.Web.Areas.Application.Models.ApplicationViewModel
if (Model.ErrorMessage != null)
{
  <div>@Model.ErrorMessage</div>
}
else
{
  <!-- Display "normal" content here //>
}

1 Ответ

2 голосов
/ 23 марта 2012

Вы можете передать экземпляр ModelState своему слою queries, и он позаботится о добавлении ошибки:

public ApplicationViewModel GetApplicationViewModel(Guid guid, ModelStateDictionary modelState)
{
    var applicationViewModel = new applicationViewModel();
    if (!_applicationServices.Exists(guid))
    {
        modelState.AddModelError("", "The requested application does not exist.");
        return applicationViewModel;
    }

    // More code here that checks things which might set the ErrorMessage property...

    var application = _applicationServices.GetApplicationByGuid((Guid)guid);
    Mapper.Map(grantApplication, grantApplicationViewModel);
    return grantApplicationViewModel;
}

и по вашему мнению:

@model MyApp.Web.Areas.Application.Models.ApplicationViewModel

@Html.ValidationSummary()

@if (ViewData.ModelState.IsValid)
{
    <!-- Display "normal" content here //>
}
...