Asp.Net MVC,WebApi和正确的异步方法

龙舌兰酒

我有一个多层Web应用程序,最近我决定将服务层(在这种情况下为WebApi)转换为异步处理。

在这方面,我将所有WebApi方法都转换为实现Tasks,在MVC部分中,我实现了对WebApi进行调用的业务层。

我的MVC控制器仅使用业务层类来获取视图数据。

我对.Net 4.5中基于任务的编程有点陌生,想知道我的方法是正确的还是有缺陷的。在我的简单测试中,我看到响应时间性能有所提高,但是我不确定我所有的异步调用是否安全或容易出错。

代码示例:

WebApi动作:

[Route("category/withnews/{count:int=5}")]
        public async Task<IEnumerable<NewsCategoryDto>> GetNewsCategoriesWithRecentNews(int count)
        {
            return await Task.Run<IEnumerable<NewsCategoryDto>>(() =>
                {
                    using (var UoW = new UnitOfWork())
                    {
                        List<NewsCategoryDto> returnList = new List<NewsCategoryDto>();

                        var activeAndVisibleCategories = UoW.CategoryRepository.GetActiveCategories().Where(f => f.IsVisible == true);
                        foreach (var category in activeAndVisibleCategories)
                        {
                            var dto = category.MapToDto();
                            dto.RecentNews = (from n in UoW.NewsRepository.GetByCategoryId(dto.Id).Where(f => f.IsVisible == true).Take(count)
                                              select n.MapToDto(true)).ToList();

                            returnList.Add(dto);
                        }

                        return returnList;
                    }
                });
        }

调用此api的业务类方法(MVC应用中的NewsService类。)

public async Task<IndexViewModel> GetIndexViewModel()
        {
            var model = new IndexViewModel();

            using (var stargate = new StargateHelper())
            {
                string categoriesWithNews = await stargate.InvokeAsync("news/category/withnews/" + model.PreviewNewsMaxCount).ConfigureAwait(false);
                var objectData = JsonConvert.DeserializeObject<List<NewsCategoryDto>>(categoriesWithNews);

                model.NewsCategories = objectData;
            }

            return model;
        }

MVC控制器操作获取ViewModel

public async Task<ActionResult> Index()
        {
            _service.ActiveMenuItem = "";

            var viewModel = await _service.GetIndexViewModel();
            return View(viewModel);
        }

但是,某些Controller动作是PartialViewResults,并且由于它们是ChildAction,我无法将它们转换为Index动作之类的异步动作。在这种情况下,我要做的是:

var viewModel = _service.GetGalleryWidgetViewModel().Result;
return PartialView(viewModel);

从同步方法调用异步方法是正确的方法吗?

也添加StargateHelper.InvokeAsync供参考:

public async Task<string> InvokeAsync(string path)
    {
        var httpResponse = await _httpClient.GetAsync(_baseUrl + path).ConfigureAwait(false);
        httpResponse.EnsureSuccessStatusCode();

        using (var responseStream = await httpResponse.Content.ReadAsStreamAsync())
        using (var decompStream = new GZipStream(responseStream, CompressionMode.Decompress))
        using (var streamReader = new StreamReader(decompStream))
        {
            return streamReader.ReadToEnd();
        }
    }
斯蒂芬·克莱里

标准规则之一是不要Task.Run在ASP.NET上使用相反,您应该使用自然异步API。

例如,在WebAPI中,假设您使用的是EF6:

public async Task<IEnumerable<NewsCategoryDto>> GetNewsCategoriesWithRecentNews(int count)
{
  using (var UoW = new UnitOfWork())
  {
    List<NewsCategoryDto> returnList = new List<NewsCategoryDto>();

    var activeAndVisibleCategories = UoW.CategoryRepository.GetActiveCategories().Where(f => f.IsVisible == true);
    foreach (var category in activeAndVisibleCategories)
    {
      var dto = category.MapToDto();
      dto.RecentNews = await (from n in UoW.NewsRepository.GetByCategoryId(dto.Id).Where(f => f.IsVisible == true).Take(count)
          select n.MapToDto(true)).ToListAsync();
      returnList.Add(dto);
    }

    return returnList;
  }
}

您的服务助手通常看起来不错。提示:如果ConfigureAwait(false)在方法中使用一次,则应在该方法中的任何地方使用它。

在当前的MVC中,子操作是一个麻烦点。没有做到这一点的好方法。ASP.NET vNext MVC具有异步兼容的“ ViewComponents”,填补了这一空白。但是今天,您必须选择两个不完善的选项之一:

  1. 使用阻塞,Task.Result并通过使用避免死锁问题ConfigureAwait(false)这种方法的问题在于,如果您不小心忘记ConfigureAwait(false)在需要使用的所有地方使用它,那么您很容易再次造成死锁(这是异步操作将完美运行但可以访问相同代码的一种情况)子操作会陷入僵局,因此单元测试可能无法捕获它,并且代码覆盖率具有误导性)。
  2. 用同步等效项复制子操作所需的所有服务方法。这种方法还存在维护问题:服务逻辑是重复的。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Asp.Net MVC,WebApi和正确的异步方法

来自分类Dev

ASP.NET MVC中的异步方法

来自分类Dev

ASP.NET WebAPI中的模拟和异步

来自分类Dev

在ASP.NET/MVC/REST中使用异步库的正确方法

来自分类Dev

与MVC3和ASP.NET4.5异步

来自分类Dev

同一域上的ASP.NET MVC和WebAPI

来自分类Dev

如何使ASP.NET MVC控制器方法异步

来自分类Dev

异步方法在ASP.NET(MVC)中在哪里执行?

来自分类Dev

asp.net mvc 5异步操作方法

来自分类Dev

在ASP.NET MVC中触发并忘记异步方法

来自分类Dev

异步方法在ASP.NET(MVC)中在哪里执行?

来自分类Dev

ASP.NET MVC在Controller中异步实现的最佳方法

来自分类Dev

ASP .NET MVC 5中的异步任务

来自分类Dev

在ASP.Net MVC中使用异步

来自分类Dev

ASP中的异步Web服务。NET MVC

来自分类Dev

ASP中的异步Web服务。NET MVC

来自分类Dev

在 ASP.Net-MVC 中使用异步

来自分类Dev

将Marten用于ASP.NET MVC / Core的正确方法

来自分类Dev

在 ASP.NET MVC 中填充下拉列表的正确方法

来自分类Dev

在ASP.NET Core 3.x MVC中将nameof()与Url.Action()和异步方法一起使用

来自分类Dev

ASP NET MVC 5任务异步创建异步方法

来自分类Dev

正确处理ASP.net MVC 4 WebApi路由中的嵌套资源

来自分类Dev

在ASP.NET 5 / MVC 6中区分MVC和WebAPI

来自分类Dev

在ASP.NET 5 / MVC 6中区分MVC和WebAPI

来自分类Dev

在ASP.NET WebApi中在后台异步/等待

来自分类Dev

ASP.NET WebAPI 2异步过滤器

来自分类Dev

在asp.net-mvc页面上使用nhibernate事务和二级缓存的正确方法是什么?

来自分类Dev

ASP.NET异步并等待

来自分类Dev

ASP.NET 异步问题