c# - Web API 异步,我做对了吗?

标签 c# entity-framework asynchronous asp.net-web-api async-await

我有一个获取仪表板 View 的 Web API 方法。

该方法调用大约 24 个不同的查询。每个查询执行大约需要 60 毫秒,我使用 Glimpse 进行分析。

我希望做的是异步运行它们,以避免一个接一个地调用每个方法,从而使其成为 60 毫秒 X 5 次方法调用。

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

这是我的 Web API 方法

[HttpGet]
[ExceptionHandling]
public async Task<DashboardResponse> GetDashboard()
{
    return await DashboardResponse.GetDashboard();
}

这是辅助方法

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;
}

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

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;
}

唯一的问题是,在实现所有异步等待更改后,Web API 调用现在运行速度似乎比以前慢了!我不确定我的结构是否正确,或者我的想法是否可行。

最佳答案

The only problem is that after implementing all the async await changes it appears that the web api call is now running slower than before!

异步代码运行速度比同步代码慢,除非您引入并发

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

因此,您需要并发性。

different queries

您可能需要考虑一下。如果您正在访问 SQL Server 的单个实例,那么您真的会从并发执行查询中获得任何好处吗?也许,也许不是。最好先对此进行测试。

请注意, Entity Framework - 虽然它允许异步查询 - only allows one asynchronous query at a time per context .您需要为每个并发查询创建不同的上下文。因此,您需要小心处理并发查询,因为您的一些实体来自不同的上下文。

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

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;
}

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

关于c# - Web API 异步,我做对了吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25725725/

相关文章:

c# - 如何根据 Active Directory 联合身份验证服务 (ADFS) 验证用户名和密码?

c# - Entity Framework 只保存最后一行(主要细节)

c# - 使用基本身份验证的 HTTP 请求始终返回 401

javascript - ASP.NET MVC 在离开当前页面时放弃 session

c# - Entity Framework 中可重用的 linq 选择查询

java - 顶点抛出 IllegalStateException : Response has already been written

debugging - Xamarin 跳过了一个可等待的方法

typescript :此表达式不可调用。类型 '{ getUserInfo(requestData: object): Promise<object>; }' 没有调用签名

c# - MVC - 使用 AJAX 调用导致服务器端页面验证在按钮单击时触发

c# - EF核心: how to share foreign key properties between several zero/one-to-many relationships