I’m developing a class library (for use by other developers) which wraps a RESTful web service. I’m using the HttpClient type from the System.Net.Http namespace to do all of my API calls, asynchronously.
In addition to simply sending/receiving content, I want to do additional processing on the returned XML data. No matter how you put it, this involves using the Async/Await keywords somewhere in the class library.
My question is whether it’s a good or bad idea to expose methods which use the Async keyword, and why. I’ve read somewhere that you should make the Async method private, then create an additional method with just a return statement. That’s what I’ve been doing, but it doesn’t feel right.
Public Function InvokeAsync(command As HttpRequestMessage) As Task(Of CommandResult)
Return InvokeAsyncInternal(command)
End Function
Private Async Function InvokeAsyncInternal(command As HttpRequestMessage) As Task(Of CommandResult)
Dim rawCommandResult As HttpResponseMessage = Await myHttpClient.SendAsync(command)
Dim finalResult As CommandResult = AdditionalProcessing(rawCommandResult)
Return finalResult
End Function
Keeping in mind that this is an oversimplified code sample: are there any good arguments not to expose the Async method directly?
This has to do with the compiler transformation; you can separate the “real”
Asyncmethod from itsPubliccounterpart, and you get the same benefits as when you do the same kind of separation for iterator (Yield) methods.In particular, exceptions are handled differently when thrown from the wrapper than when thrown from the
Asyncmethod. When anAsyncmethod that returnsTaskthrows anException, it’s placed on the returnedTaskrather than thrown directly to the caller. When thePublicwrapper method (which is notAsync) throws anException, it’s thrown directly to the caller.So, precondition-style checks can be put in the
Publicmethod. Callers can ignore exceptions placed onTasks, but they can’t ignore exceptions thrown directly. Placing precondition exceptions in aPublicwrapper forces the caller to realize they are misusing the API, and also permits a separation of usage exceptions (which are thrown directly) from runtime exceptions (which are placed on theTask).If your method has no preconditions, then your
Publicwrapper is just returning the innerTask. In this case, thePublicwrapper is unnecessary.