ASP.NET MVC 5 Асинхронное управление контекстами

У меня есть довольно стандартное приложение MVC 5, состоящее из уровня репозитория, уровня обслуживания и уровня контроллера. Чтобы каждый слой был развязан и проверен, я использую Ninject для инъекции зависимостей.

Чтобы освежить новый навык, я решил использовать новые новые действия контроллера задачи с async/await для операций с привязкой IO для методов обслуживания и контроллера.

Обычно я просто использую привязку InRequestScope, например,

kernel.Bind<IDbContext>().To<BlogContext>().InRequestScope();

В целом, сейчас это нормально работает, однако, если я решил отлаживать приложение или объединить несколько объектов структуры отслеживаемых сущностей вместе и сохранить, я обнаружил, что контекст был удален или у меня возникают проблемы с отслеживанием. Я понимаю, почему это происходит, это совершенно логично, потому что операция больше не происходит в потоке IIS, так как Ninject знает, что он должен использовать тот же контекст.

Чтобы обойти это, я могу передать свой контекст в каждый вызов репозитория с моего уровня обслуживания или даже с уровня контроллера, если это необходимо. Однако я чувствую, что это выглядит беспорядочно, и я предпочел бы, чтобы Ninject управлял контекстом этого объекта, если это было возможно.

Каковы наилучшие стратегии для этого в элегантной/минималистской манере, сохраняя мой код похожим на приведенные ниже примеры?

Вот пример одного из моих методов контроллера

    public virtual async Task<ActionResult> Edit(int id)
    {
        var editViewModel = await BuildDefaultCreateEditViewModel();

        var post = await postService.GetNonDeletedPost(id);
        ...
        ...
        return View(MVC.Admin.Post.Views.CreateEdit, editViewModel);
    }

Сервисный метод

    public async Task<PostDTO> GetNonDeletedPost(int postId)
    {
        return (await PostRepostiory.GetPost(postId)).ConvertToDTO();
    }

Метод репозитория

    public Task<Post> GetPost(int postId)
    {
        return QueryableExtensions.SingleOrDefaultAsync(
                DbSet.Where(post => post.PostId == postId)
                .Include(post => post.PostVersions)
                .Include(post => post.Categories)
                .Include(post => post.Files));
    }

Ответ 1

В вашем сообщении и в связанных комментариях есть несколько отличных примеров того, как это сделать.

Однако для некоторых других читателей, которые могли бы споткнуться здесь, я хочу выкинуть честный вопрос: Вам действительно нужны асинхронные контроллеры?

Действия асинхронного контроллера освобождают количество потоков, необходимых для обработки запросов; однако, если у вас не хватает нитей и вряд ли, то вы создаете сложность, пытаясь решить проблему, которую вы не имеете и не ожидаете. Или: "Действительно ли Async свободен и всегда лучше?"

Фактически, я пытаюсь продемонстрировать, что одно очень жизнеспособное решение (и, возможно, не то, что вы ищете) было бы просто не использовать асинхронные контроллеры - если это действительно не нужно (что будет зависеть от ваших конкретных обстоятельств. )

Это хорошее старое дурацкое решение проблемы, устраняя проблему. И, в частности, я предлагаю это, потому что устранение сложности является одной из целей.

Как выбрать, что использовать? есть более длинный список, но два из лучших вопросов:

  • Являются ли ваши товары короткими?
  • И если нет, связаны ли ваши ресурсы с процессором?

http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

Из приведенной ссылки "Использование методов асинхронного действия для операций с привязкой к ЦП не дает никаких преимуществ и приводит к большему количеству накладных расходов".