在webapi中正确使用等待异步

mic*_*win 8 c# async-await asp.net-mvc-4 .net-4.5 asp.net-web-api

我有一个WebApi,对于每个传入请求,调用2个单独的Web服务,执行一些后期处理并返回结果.

第一个webservice调用在本地缓存1小时,其中的数据确定对第二个webservice的查询.每个传入请求都会调用第二个Web服务.在发出第二个请求之后,使用业务逻辑处理每个结果并返回到客户端响应.

对第二个Web服务的调用不能是异步的,因为它使用的是不允许使用await关键字的第三方dll.我所做的是将第二个webservice调用和后处理包装成一个异步函数,该函数从控制器调用.

// /api/controller/news?key=a&state=b
public async Task<HttpResponseMessage> GetNews(string key, string state)
    {
         // call to first webservice if not in cache
         if (JsonConfig != null && JsonConfig.Configuration.NewsQuery.ContainsKey(key))
        { 
            var results = await SearchProxyProvider.Search(filters.All, filters.Any, filters.None, filters.Sort, 100, 0, true, state, true);
            int totalCount = results.TotalCount;

            return Request.CreateResponse(HttpStatusCode.OK, results);
        }
    }


// Helper class method
public async Task<ItemCollection<Item>> Search(List<FieldValuePair> allFilters, List<FieldValuePair> anyFilters, List<FieldValuePair> noneFilters, SortedFieldDictionary sortBy, int pageSize = 100, int pageNumber = 0, bool exact = true, string stateFilter = null, bool getAllResults = true)
        {
            // call to 2nd api
            search = SomeApi.Search(allFilters, anyFilters, noneFilters, pageSize, pageNumber, exact,
                                               sortBy, null, WebApiConstant.Settings.CustomFields, true);

            // post processing on search results
            return search;
        }
Run Code Online (Sandbox Code Playgroud)

因为对第一个web服务的调用是在本地缓存的,所以我并没有看到使这个异步的巨大好处.

我只是想看看这种方法是完全错误还是正确.

Ste*_*ary 8

第一个webservice调用在本地缓存1小时,其中的数据确定对第二个webservice的查询.

你可以做一些技巧AsyncLazy<T>(例如,从我的博客)并缓存它.这为您的请求提供了一种(异步)等待刷新的方法,当您需要刷新数据时,无论同时请求的数量是多少,您都不会多次命中Service1.

对第二个Web服务的调用不能是异步的,因为它使用的是不允许使用await关键字的第三方dll.

那真是太糟糕了.靠它们来修理它.:)

我所做的是将第二个webservice调用和后处理包装成一个异步函数,该函数从控制器调用.

这没有意义.编译器会警告您,"异步"方法实际上是同步的.

如果它是同步的,那么只需同步调用它.在服务器端,包装它Task.Run或其他任何东西都没有意义.

我有一些幻灯片可以从我周一在ThatConference 上发表的"服务器上的异步"谈话获得,你可能会发现它很有帮助.(它们具有如何处理异步请求的动画以及为什么"假异步"方法在服务器端没有帮助).


Ale*_*x S 0

为了使 Search 函数真正异步,可以将对 SomeApi.Search 的调用包装到一个单独的任务中,然后等待。还可以考虑将第一个函数中的代码包装到任务中,您的负载估计缓存验证也可能是一个瓶颈。

// call to 2nd api
var search = await Task.Factory.StartNew(()=> {return Some Api.Search(allFilters, anyFilters, noneFilters, pageSize, pageNumber, exact,
                                               sortBy, null, WebApiConstant.Settings.CustomFields, true);});
Run Code Online (Sandbox Code Playgroud)

  • 我使用术语“真正异步”来表示不将工作排队到线程池的异步方法。在服务器端,“异步”的全部意义在于“释放工作线程”,如果您通过将工作排队到线程池(由另一个工作线程执行)来释放工作线程,您将获得没有什么。OTOH,这是*客户端*上“异步”的一项有用技术,因为重点是释放*UI*线程。因此,您可以将工作排队到线程池中,这很好,因为它不是在 UI 线程上完成的。 (4认同)