Правильный способ использования асинхронной библиотеки с ASP.NET/MVC/REST

У меня есть асинхронная библиотека для обработки аудиофайлов. Кроме того, я хочу предложить эти методы через отдых. Итак, я сделал проект MVC WebApi. Библиотеке нужно некоторое время для запуска, поэтому я добавил класс, который предлагает способ инициализации и предоставляет доступ к основному объекту библиотеки.

public static class MusicHandler
{
    public static MusicCapture.MusicCapture MusicCapture;
    public static void init()
    {
        MusicCapture = new MusicCapture.MusicCapture("D:\\Temp", "D:\\test", "E:\\FingerPrintDB2.ss");
        MusicCapture.Start();
    }
}

Я запускаю его в Application_Start()

protected void Application_Start()
{
    MusicHandler.init();
}

Теперь, когда мой метод инициализации содержит некоторые асинхронные вызовы, подобные этому:

var hashedFingerprints = command.Hash().Result;

Программа просто пропустит эти строки. Насколько я могу судить, их не казнят. То же самое происходит, когда я вызываю любой из асинхронных методов объектов из моих конечных точек REST. Когда я запускаю библиотеку не из ASP.NET/MVC, код работает безупречно.

Я нашел несколько комментариев, в которых говорилось, что это проблема из-за взаимоблокировок, но нет советов или кода, как этого избежать/заставить эту работу работать.

Заранее спасибо.


person Master117    schedule 01.02.2020    source источник
comment
Никогда не используйте '.Result', вы должны 'wait command.Hash()'   -  person IeuanW    schedule 01.02.2020
comment
@IeuanW, но тогда я должен сделать этот метод асинхронным, вплоть до самого верха, но Application_Start() не является асинхронным.   -  person Master117    schedule 01.02.2020
comment
если вы используете DI, вам не нужно ничего добавлять в автозагрузку. то есть, если вы используете синглтон, тогда весь класс будет готов и ожидает использования другими вызывающими объектами.   -  person IeuanW    schedule 03.02.2020


Ответы (2)


Итак, насколько я понимаю, вы хотите запустить что-то под названием MusicHandler, запуск которого занимает некоторое время. Как только он загрузится, связь с вашей системой будет осуществляться через HTTP-вызовы RESTful.

В вашем MusicHandler вы можете иметь флаг, чтобы указать, закончилась ли загрузка.

public static class MusicHandler
{
    public static MusicCapture.MusicCapture MusicCapture;
    public static bool Initialized {get;} = False;
    public static void init()
    {
        MusicCapture = new MusicCapture.MusicCapture("D:\\Temp", "D:\\test", "E:\\FingerPrintDB2.ss");
        MusicCapture.Start();
        Initialized = true;
    }
}

Затем в вашем контроллере MVC вы можете проверить этот флаг и вернуть ошибку, если инициализация не завершена.

Таким образом, вам не нужно беспокоиться о том, чтобы быть async на всем пути к вершине.

Но я удивлен, что вы вообще используете application_start... размещайте это с помощью пустельги и выполняйте эту настройку в program.cs или где-то еще, где вы можете изначально быть асинхронным с вершиной.

person Simon    schedule 01.02.2020

Я понял свою проблему, она была двоякой.

  1. Сбой моей библиотеки при запуске был ошибкой в ​​​​библиотеке, которая привела к исключению, которое не всплывало. Я смог смягчить эту ошибку. Асинхронные вызовы при запуске с приложением MVC с .Result внутри, похоже, не проблема.

  2. Мои вызовы REST, не работающие в асинхронном режиме, можно исправить, изменив методы остальных контроллеров на асинхронные. Никогда бы не подумал, что это возможно, но нашел пример здесь: https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

// GET api/music
public async System.Threading.Tasks.Task<string> GetAsync()
{
    string result = await MusicHandler.MusicCapture.DetectAsync(5);
    Console.WriteLine("Server returning: " + result);
    return result;
}
person Master117    schedule 01.02.2020