Я хочу использовать фильтр настраиваемых действий для обработки определенных исключений из моих классов обслуживания, чтобы заполнить состояние модели и затем вернуть представление.
Например, возьмите мой предыдущий код:
public ActionResult SomeAction(SomeViewModel model)
{
try
{
_someService.SomeMethod(model);
}
catch (ServiceException ex)
{
ModelState.AddModelError(ex.Key, ex.ErrorMessage);
}
return View();
}
По сути, он будет вызывать службу, и если возникнет исключение ServiceException, он узнает, что существует проблема с данными модели, и добавит ошибку в ModelState, а затем просто вернет представление. Но я заметил некоторые очень не похожие на DRY шаблоны, потому что у меня был один и тот же код try / catch в каждом методе действия.
Итак, чтобы немного подсушить, я в основном создал новый фильтр действий HandleServiceError:
public class HandleServiceErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext context)
{
((Controller)context.Controller)
.ModelState
.AddModelError(
((ServiceException)context.Exception).Key,
((ServiceException)context.Exception).ErrorMessage
);
context.ExceptionHandled = true;
}
}
Затем упростили мои методы действий так:
public ActionResult SomeAction(SomeViewModel model)
{
_someService.SomeMethod(model);
return View();
}
Проблема в том, что когда фильтр действий обрабатывает ошибку, он не возвращается к моему методу действия. Я как бы под капотом понимаю, почему это происходит. Но я все же хотел бы найти способ сделать то, что я пытаюсь сделать.
Возможно ли это?
Заранее спасибо.
UPDATE:
Я попробовал предложения из статьи , которые Дарин предоставил в своем ответе, но столкнулся с проблемами, пытаясь использовать инжекцию конструктора с состоянием модели контроллера.
Например, если вы посмотрите на их код Controllers \ ProductController.cs, у них есть пустой конструктор контроллера, использующий локатор службы для создания службы, передавая ModelState контроллера в этот момент:
public ProductController()
{
_service = new ProductService(new ModelStateWrapper(this.ModelState),
new ProductRepository());
}
Но если вы посмотрите на внедренный конструктор, он предполагает, что ModelState будет внедрен в конструктор для службы:
public ProductController(IProductService service)
{
_service = service;
}
Я не знаю, как заставить CI работать с ModelState текущего контроллера. Если бы я мог понять это, то этот подход может сработать.