Страницы

Поиск по вопросам

вторник, 9 июля 2019 г.

ASP.NET MVC и библиотека MediatR, странное поведение

В одном из проектов подключена библиотека MediatR.
Используя абстракции из данной библиотеки определил команду:
public class TestCommand: IRequest { }
и обработчик данной команды:
public class TestHandler : IAsyncRequestHandler { public Task Handle(TestCommand command) { return Task.Factory.StartNew(() => { // Здесь намеренно бросается исключение. throw new ApplicationException(); }); } }
Далее в контроллер инжектится сам IMediator, через который мы можем вызвать нужный обработчик для конкретной команды.
Контроллер:
public class HomeController : Controller { private readonly IMediator _mediator;
public HomeController(IMediator mediator) { _mediator = mediator; }
public ActionResult Index() { try { // Передаем команду, тем самым вызываем обработчик данной команды - TestHandler. _mediator.Send(new TestCommand()).Wait(); } catch (Exception e) { // Сюда никогда не попадаем }
return View(); }
}
Суть проблемы:
Как можно заметить, в методе Handle класса TestHandler, который обрабатывает команду TestCommand создается и возвращается новая задача, в которой просто бросается исключение ApplicationException.
Далее в экшене Index контроллера Home, к возвращаемой из TestHandler.Handle задаче применен метод Wait(), который должен дождаться ее выполнения. Так как в возвращенной задаче бросается исключение ApplicationException мы по идее должны попасть в блок catch, но этого не происходит, вместо этого, такое ощущение, что возникает какой-то deadlock.
Собственно вопрос, это баг в библиотеке или я что-то упустил и не заметил и данное поведение нормально?
P.S. Если заменить
_mediator.Send(new TestCommand()).Wait();
на
await _mediator.Send(new TestCommand());
то поведение будет ожидаемым, т.е. мы попадем в блок catch. Но лично мне хотелось бы понять, почему код перестает работать если используется метод Wait()


Ответ

Автор библиотеки не удосужился вызвать ConfigureAwait(false) (RequestHandler.cs), так что внутри библиотеки произошёл захват контекста, а вы вызовом Wait() заблокировали поток, в который должно вернуться управление, так что произошёл классический deadlock с async/await, можете почитать детальный разбор тут Еще один аргумент за ConfigureAwait(false) в библиотеках

Комментариев нет:

Отправить комментарий