#c_sharp #aspnet_mvc #android_asynctask #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()
Ответы
Ответ 1
Автор библиотеки не удосужился вызвать ConfigureAwait(false) (RequestHandler.cs), так что внутри библиотеки произошёл захват контекста, а вы вызовом Wait() заблокировали поток, в который должно вернуться управление, так что произошёл классический deadlock с async/await, можете почитать детальный разбор тут Еще один аргумент за ConfigureAwait(false) в библиотеках
Комментариев нет:
Отправить комментарий