Web API Async,我做得对吗?

998*_*823 2 c# asynchronous entity-framework async-await asp.net-web-api

我有一个Web API方法,可以获得仪表板视图.

该方法调用大约24个不同的查询.每个查询执行大约需要60ms,我正在使用Glimpse进行配置.

我希望这样做,是异步运行它们,以避免一个接一个地调用每一个,从而使它成为60ms X 5方法调用.

我也是Async Await的新手,所以我的期望可能不正确.

这是我的Web API方法

[HttpGet]
[ExceptionHandling]
public async Task<DashboardResponse> GetDashboard()
{
    return await DashboardResponse.GetDashboard();
}
Run Code Online (Sandbox Code Playgroud)

这是辅助方法

public static async Task<DashboardResponse> GetDashboard()
{
    var resp = new DashboardResponse();

    resp.MonthGlance = await GetMonthAtAGlance();
    resp.MostRecentOrder = await GetMostRecentOrder();
    resp.CreateAnOrder = await GetCreateAnOrder();
    resp.RecentOrders = await GetRecentOrders();
    resp.RecentNotifications = await GetRecentNotifications();

    var messages = MessageResponse.GetMessages(new MessageFilters() { PageNumber = 1, PageSize = 10 }).Messages;

    resp.RecentMessages.Messages = messages;
    resp.OrderLineChart = GetOrderLineChart();

    return resp;
}
Run Code Online (Sandbox Code Playgroud)

这是辅助方法内部调用的方法之一(其余方法设置非常相似)

public static async Task<MonthGlanceResp> GetMonthAtAGlance()
{
    var monthAtAGlance = new MonthGlanceResp();

    var monthStart = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
    var monthEnd = monthStart.AddMonths(1).AddDays(-1);

    var monthGlanceQuery = Helpers.DbContext.Current.Orders
                            .Where(c => c.Status != OrderStatuses.Deleted &&
                                (c.OrderSubSource == OrderSubSources.ApplicantLink ||
                                c.OrderSubSource == OrderSubSources.BulkImport ||
                                c.OrderSubSource == OrderSubSources.OrderComprehensive) &&
                                c.DateIn >= monthStart &&
                                c.DateIn <= monthEnd).AsQueryable();

    if (UserContext.Current.AccountAccess == CustomerAccessTypes.Global)
    {
        monthGlanceQuery = monthGlanceQuery.Where(c => c.CustomerId == UserContext.Current.CustomerId);
    }
    else if (UserContext.Current.AccountAccess == CustomerAccessTypes.Account)
    {
        monthGlanceQuery = monthGlanceQuery.Where(c => c.CustomerAccountId == UserContext.Current.CustomerAccountId);
    }
    else
    {
        monthGlanceQuery = monthGlanceQuery.Where(c => c.CustomerAccountPersonId == UserContext.Current.CustomerAccountPersonId);
    }

    monthAtAGlance.ClearOrderCount = await monthGlanceQuery
                                        .CountAsync(c => c.OrderLineItems
                                                        .Where(d => d.ItemType == "package_service" || d.ItemType == "service")
                                                        .All(d => d.Result == OrderLineItemResults.Clear && d.Status == OrderLineItemStatuses.ApprovedForClient));

    monthAtAGlance.QuestionableOrderCount = await monthGlanceQuery
                                        .CountAsync(c => c.OrderLineItems
                                                        .Where(d => d.ItemType == "package_service" || d.ItemType == "service")
                                                        .All(d => d.Status == OrderLineItemStatuses.ApprovedForClient) &&
                                                        c.OrderLineItems
                                                        .Where(d => d.ItemType == "package_service" || d.ItemType == "service")
                                                        .Any(d => d.Result == OrderLineItemResults.Questionable));

    monthAtAGlance.PendingOrderCount = await monthGlanceQuery
                                        .CountAsync(c => c.OrderLineItems
                                                        .Where(d => d.ItemType == "package_service" || d.ItemType == "service")
                                                        .Any(d => d.Status != OrderLineItemStatuses.ApprovedForClient));

    monthAtAGlance.OrderCount = await monthGlanceQuery.CountAsync();

    return monthAtAGlance;
}
Run Code Online (Sandbox Code Playgroud)

唯一的问题是,在实现所有异步等待更改后,似乎web api调用现在比以前运行得慢!我不确定我是否有正确的结构,或者即使我正在考虑的是可能的.

Ste*_*ary 7

唯一的问题是,在实现所有异步等待更改后,似乎web api调用现在比以前运行得慢!

除非引入并发,否则异步代码的运行速度比同步代码慢.

旁注:异步代码通常用在服务器应用程序(例如,ASP.NET)上,即使单个请求没有并发性,因为即使每个单独的请求(稍微)较慢,整个系统也可以进一步扩展.

所以,你需要并发.

不同的查询

你可能想要考虑一下.如果您正在使用SQL Server的单个实例,那么您是否真的可以从同时执行查询中获得任何好处?也许,也许不是.最好先测试一下.

请注意,实体框架 - 虽然它允许异步查询 - 但每个上下文一次只允许一个异步查询.您需要为每个并发查询创建不同的上下文.所以你需要小心并发查询,因为你的一些实体来自不同的上下文.

也就是说,您可以执行如下所示的并发调用:

public static async Task<DashboardResponse> GetDashboardAsync()
{
  var resp = new DashboardResponse();
  var monthAtAGlanceTask = GetMonthAtAGlanceAsync();
  var mostRecentOrderTask = GetMostRecentOrderAsync();
  ...
  await Task.WhenAll(monthAtAGlanceTask, mostRecentOrderTask, ...);
  resp.MonthGlance = await monthAtAGlanceTask;
  resp.MostRecentOrder = await mostRecentOrderTask;
  ...
  return resp;
}
Run Code Online (Sandbox Code Playgroud)

请注意,您的代码几乎肯定无法使用Helpers.DbContext.Current; 每个并发查询都需要自己的上下文.