Reputation:
In the context of .NET...
For a web application I'm developing, I have the following architecture (from topmost to bottommost, loosely speaking):
Focusing now on one controller in particular and two services, I have the following: A ProjectsController ("PC") calling into the ProjectsService ("PS"), which has a SmartyStreetsGeocodingService ("SSGS") injected into it and that the ProjectsService calls. I wrote SSGS as a synchronous service initially just for testing purposes. But now the time has come to convert the sync call out to the Smarty Streets RESTful API to an async call. I'm having a timing issue right now that is related to synchronicity, and the GeocodingResult it processes too soon.
My question really revolves around architecture. Also, I would like to stay within the confines of just converting from sync to async (I'm aware of other approaches, such as .NET Service Bus, SignalR, etc., all of which I'll look at later).
Consider the following code from the SSGS:
using (var response = request.GetResponse() as HttpWebResponse)
{
if (response == null) return geocodingResult;
var jsonSerializer = new DataContractJsonSerializer(typeof(CandidateAddress[]));
var stream = response.GetResponseStream();
if (stream == null) return geocodingResult;
var objResponse = jsonSerializer.ReadObject(stream);
jsonResponse = objResponse as CandidateAddress[];
}
if (jsonResponse == null || jsonResponse.Length == 0) //<-- Executes too soon
{
geocodingResult.IsVerified = false;
return geocodingResult;
}
geocodingResult.IsVerified = true;
The fragment above is what I wish to convert to async as the portion of code immediately following the using statement executes too soon. But that leads to questions:
Thank you.
Upvotes: 0
Views: 2166
Reputation: 1038730
The most important thing that should be asynchronous in your case is the HTTP call to the remote service. From there on, everything that is calling this service should of course be asynchronous.
At the end of the day you should have an asynchronous controller action in your outermost layer (the Web API):
public async Task<HttpResponseMessage> Get()
{
var request = WebRequest.Create("http://google.com");
using (var response = await request.GetResponseAsync())
using (var stream = response.GetResponseStream())
using (var reader = new StreamReader(stream))
{
string responseContent = reader.ReadToEnd();
return Request.CreateResponse(HttpStatusCode.OK, responseContent);
}
}
So as you can see from this controller action I have used an asynchronous Httprequest. So in order to achieve that in your current design you need to make everything asynchronous and expose async methods in your service layer as well so that you can async/await on the result that's gonna get you the JSON from the service layer.
In my example I have simply returned a string from the remote HTTP call but you could easily adapt your service layer to return complex objects as well:
public async Task<MyModel> GetMyModelfromRemoteServiceCall();
{
var request = WebRequest.Create("http://google.com");
using (var response = await request.GetResponseAsync())
using (var stream = response.GetResponseStream())
using (var reader = new StreamReader(stream))
{
string responseContent = reader.ReadToEnd();
return JsonConvert.DeserializeObject<MyModel>(responseContent);
}
}
You could then trivially easy await
on this service layer method from your async Web API controller action.
Upvotes: 4