Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct usage of await async in webapi

I have a WebApi that for each incoming request, calls 2 separate webservices, performs some post processing and returns the results.

The first webservice call is cached locally for 1 hour, and the data in this determines the query to the 2nd webservice. The 2nd webservice is called on each incoming request. After that 2nd request is made, each result is processed with business logic and returned back to the client response.

The call to the 2nd webservice cannot be asynchronous because it is using a 3rd party dll that does not allow the await keyword. What I've done, is wrapped the 2nd webservice call and post processing into one async function, which is called from the controller.

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

Because the call to the first webservice is cached locally, I don't really see a huge benefit to making this asynchronous.

I'm just looking to see if this approach is totally wrong, or right.

like image 527
mickyjtwin Avatar asked Aug 13 '13 05:08

mickyjtwin


1 Answers

The first webservice call is cached locally for 1 hour, and the data in this determines the query to the 2nd webservice.

You can do some tricks with AsyncLazy<T> (e.g., from my blog) and cache that instead. That gives your requests a way to (asynchronously) wait for a refresh, and you won't hit Service1 multiple times when you need to refresh the data, regardless of the number of simultaneous requests.

The call to the 2nd webservice cannot be asynchronous because it is using a 3rd party dll that does not allow the await keyword.

That's a bummer. Do lean on them to fix it. :)

What I've done, is wrapped the 2nd webservice call and post processing into one async function, which is called from the controller.

There's no point to that. The compiler will warn you that your "async" method is in fact synchronous.

If it's synchronous, then just call it synchronously. On the server side, there's no point in wrapping it in Task.Run or anything like that.

I have some slides available from an "Async on the Server" talk I gave Monday at ThatConference, which you may find helpful. (They have animations of how asynchronous requests are handled and why "fake asynchronous" methods don't help on the server side).

like image 146
Stephen Cleary Avatar answered Oct 05 '22 18:10

Stephen Cleary