Страницы

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

суббота, 11 января 2020 г.

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

#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) в библиотеках

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

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