#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) в библиотеках
Комментариев нет:
Отправить комментарий