Just started using Web API during preview 6 then my world got flipped upside when things shifted to the ASP.NET Web API!
I wanted to get some opinions on some code I wrote usign Web API and if there were any ways I could improve it. Basically, I don't think that I need any of the async stuff right now, and don't want to upgrade and wait for .NET 4.5 to be released.
I just want the code to run like it did during preview 6.
So how does this code look to you guys/gals? All it does is attempt to read a concrete type from the response stream. For some reason, this code didn't work with the built in ReadAsAsync<T> code handling the serialization, so I instead used the Newtonsoft
JSON library:
public T GetDataFromService<T>()
{
using (var httpClient = new HttpClient())
{
T result = default(T);
Task<HttpResponseMessage> responseTask = null;
httpClient.GetAsync(_endpoint).ContinueWith((requestTask) =>
{
responseTask = requestTask;
HttpResponseMessage response = requestTask.Result;
response.EnsureSuccessStatusCode();
response.Content.ReadAsStringAsync().ContinueWith((readTask) =>
{
result = JsonConvert.DeserializeObject<T>(readTask.Result);
});
});
// HACK: My version of the await keyword
while (responseTask == null || !responseTask.IsCompleted || result == null) { }
return result;
}
}
You can call .Result on a Task to wait for the result.
using (var httpClient = new HttpClient())
{
var response = httpClient.GetAsync(_endpoint).Result;
var result = response.Content.ReadAsStringAsync().Result;
/*ToDo: Parse Json*/
return result;
}
I shortened it up a little further, here is the complete generic method for a Get request:
public T GetDataFromService<T>()
{
using (var httpClient = new HttpClient())
{
var response = httpClient.GetAsync(_endpoint).Result;
return JsonConvert.DeserializeObject<T>(response.Content.ReadAsStringAsync().Result);
}
}
While .Result works note that by using it you are losing all the perf benefits that Task provides. When you block a thread your server will not be able to use it to serve other requests meaning you lose scalability. I'd recommend returning Task<T> instead.
Yeah, thanks for the heads up. That thought definitely crossed my mind, but this is for an internal business app, so there will never be the need to scale (I hope). So for now I'll do it the hacky way, but then I'll definitely switch back to async when
the .NET 4.5 comes out.
Unless the complete pipeline (that is fromPage or Handler onwards) is async, you won't get the perf benefits you're talking about as regards the Web Server using I/O completetion ports and being able to serve other requests because threads
are freed up.
From the OP's example, it looks like the method doing the service call it a synchronous call. So at some point during the Request-Response cycle, things are not async all the way. So you're point is moot.
skippyfire
Member
34 Points
31 Posts
Making a request synchronously
Feb 22, 2012 12:30 PM|LINK
Hi everyone,
Just started using Web API during preview 6 then my world got flipped upside when things shifted to the ASP.NET Web API!
I wanted to get some opinions on some code I wrote usign Web API and if there were any ways I could improve it. Basically, I don't think that I need any of the async stuff right now, and don't want to upgrade and wait for .NET 4.5 to be released. I just want the code to run like it did during preview 6.
So how does this code look to you guys/gals? All it does is attempt to read a concrete type from the response stream. For some reason, this code didn't work with the built in ReadAsAsync<T> code handling the serialization, so I instead used the Newtonsoft JSON library:
public T GetDataFromService<T>() { using (var httpClient = new HttpClient()) { T result = default(T); Task<HttpResponseMessage> responseTask = null; httpClient.GetAsync(_endpoint).ContinueWith((requestTask) => { responseTask = requestTask; HttpResponseMessage response = requestTask.Result; response.EnsureSuccessStatusCode(); response.Content.ReadAsStringAsync().ContinueWith((readTask) => { result = JsonConvert.DeserializeObject<T>(readTask.Result); }); }); // HACK: My version of the await keyword while (responseTask == null || !responseTask.IsCompleted || result == null) { } return result; } }SixiS
Member
50 Points
16 Posts
Re: Making a request synchronously
Feb 22, 2012 12:48 PM|LINK
You can call .Result on a Task to wait for the result.
using (var httpClient = new HttpClient()) { var response = httpClient.GetAsync(_endpoint).Result; var result = response.Content.ReadAsStringAsync().Result; /*ToDo: Parse Json*/ return result; }skippyfire
Member
34 Points
31 Posts
Re: Making a request synchronously
Feb 22, 2012 01:10 PM|LINK
Nice! I didn't realize you could get the Result immediately like that, which I assumes just blocks the current thread while waiting. Awesome!
This is the simple code that I've been looking for!
skippyfire
Member
34 Points
31 Posts
Re: Making a request synchronously
Feb 22, 2012 02:26 PM|LINK
I shortened it up a little further, here is the complete generic method for a Get request:
public T GetDataFromService<T>() { using (var httpClient = new HttpClient()) { var response = httpClient.GetAsync(_endpoint).Result; return JsonConvert.DeserializeObject<T>(response.Content.ReadAsStringAsync().Result); } }marcind
Contributor
3344 Points
609 Posts
Microsoft
Re: Making a request synchronously
Feb 22, 2012 02:54 PM|LINK
ASP.NET Team
@marcind
Blog
skippyfire
Member
34 Points
31 Posts
Re: Making a request synchronously
Feb 22, 2012 08:40 PM|LINK
Yeah, thanks for the heads up. That thought definitely crossed my mind, but this is for an internal business app, so there will never be the need to scale (I hope). So for now I'll do it the hacky way, but then I'll definitely switch back to async when the .NET 4.5 comes out.
HSaid
Member
2 Points
9 Posts
Re: Making a request synchronously
Feb 23, 2012 05:10 AM|LINK
if you like RX, (which I like), the following code fragment sample using Async as follows:
GetData(myuri).ObserveOnDispatcher().Subscribe((o) => { XmlSerializer xs = new XmlSerializer(typeof(List<T>)); var data = xs.Deserialize(o.GetResponseStream()) as List<T>; }); public static IObservable<WebResponse> GetData(Uri uri) { var request = (HttpWebRequest)WebRequestCreator.BrowserHttp.Create(uri); request.Method = "GET"; request.Accept = "text/xml"; var observer = Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse); return observer(); }skumar2003
Member
90 Points
51 Posts
Re: Making a request synchronously
Mar 13, 2012 06:53 PM|LINK
Marcind,
Unless the complete pipeline (that is from Page or Handler onwards) is async, you won't get the perf benefits you're talking about as regards the Web Server using I/O completetion ports and being able to serve other requests because threads are freed up.
From the OP's example, it looks like the method doing the service call it a synchronous call. So at some point during the Request-Response cycle, things are not async all the way. So you're point is moot.