I'm trying to setup an API for my BLL and I got GET and DELETE actions working fine. Now I'm trying to submit data back to the API with PUT but I can't get it to work. Specifically, I'm using HttpClient as the client to talk to Web API.
Here is the code I'm using which just hangs:
publicstring Put<T>(T data)
{
using (var httpClient = newHttpClient())
{
var mediaType = newMediaTypeHeaderValue("application/json");
var jsonSerializerSettings = newJsonSerializerSettings();
var jsonFormatter = newJsonNetFormatter(jsonSerializerSettings);
var requestMessage = newHttpRequestMessage<T>(data, mediaType, newMediaTypeFormatter[] { jsonFormatter });
var result = httpClient.PutAsync(_endpoint, requestMessage.Content).Result;
return result.Content.ReadAsStringAsync().Result;
}
}
I would encourage you to go and have a look at C# Async CTP. You can get it today and build apps with it. It has go-live licence as well and C# 5 will have the features inside that CTP.
With async CTP, you will be able to write asyncronous code just like you write your syncronous code. I am not a good enough on that to give samples but you can do the following AFAIK:
var result = await httpClient.PutAsync(_endpoint, requestMessage.Content);
return await result.Content.ReadAsStringAsync();
First of all, are generic methods supported in the Web API? I think I read somewhere they currently are not?
What are you trying to accomplish with the method btw? You are accepting a generic class then formatting it into a json string. Why not just use JsonValue? What kind of data are you doing a PUT with btw?
But heres a modified example of how you can leverage async today, but I wrote the example without the generic support.
The trick is to make the API method return a Task, then you are not blocking the request thread when waiting for the client to finish.
public Task<string> Put(string data)
{
var mediaType = new MediaTypeHeaderValue("application/json");
var jsonSerializerSettings = new JsonSerializerSettings();
var jsonFormatter = new JsonNetFormatter(jsonSerializerSettings);
var requestMessage = new HttpRequestMessage<T>(data, mediaType, new MediaTypeFormatter[] { jsonFormatter });
var httpClient = new HttpClient()
return httpClient.PutAsync(_endpoint, requestMessage.Content).ContinueWith(httpResponseMessage =>
{
return httpResponseMessage.Result.Content.ReadAsStringAsync();
});
}
Thanks for the replies guys, but I think that my problem is not with sync/async.
I would love to use the new await keyword, but right now, I don't want to be building against the .NET 4.5 Developer Preview.
Back to the issue.
Even if my code was blocking the thread until the response was returned, the code would still continue (eventually). I'm posting to a local Web API service on another port, and my GET and DELETE actions are instantaneous. So something is fundamentally
wrong with my code, causing it to hang. I think it's on the client end, because I'm pretty sure the request never actually hits the service on the other end.
All I'm trying to do is serialize a POCO and PUT it to the Web API to update a record in a database. My put handler in the Web API controller looks like this:
So the API you showed in your first post is functioning as a kind of reverse proxy?
What are you serializing your POCO as when posting? If it's JSON, then instead of a generic method just use JsonValue and send that on to your backend service?
Try changing your method to not be generic, people have had problems with generic methods on a controller:
http://forums.asp.net/t/1770829.aspx/1?Using+generics+in+ApiController+controller+
If Yes, then there seems to be a problem in the WriteToStreamAsync method of this formatter. I was able to repro this issue. This method seems to work fine while writing the response on the Service side, but has problems writing on the Client side. I have
notified Henrik regarding this. Will post updates.
[UPDATE] : The blog has been updated with the fix to the JsonNetFormatter. You should be able to use it now.
Can you elaborate on the JsonValue mechanism you mentioned?
JsonValue is a really handy type to deal with JSON data in a loosely typed way.
In your case you can do something like this:
public void Post(JsonValue value)
{
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://localhost:31724");
StringContent content = new System.Net.Http.StringContent(value.ToString(), Encoding.UTF8, "application/json");
var result = httpClient.PutAsync("api/Values", content).Result;
}
You can use JsonValue.Parse(string json) to create a new instance.
Just curious, why do you need to new up a JsonValue? When posting data you can just post normal POCO classes. I was just showing you how to use JsonValue to receive loosely typed data.
skippyfire
Member
34 Points
31 Posts
How to correctly use PostAsync and PutAsync?
Feb 23, 2012 12:59 PM|LINK
Hi Everyone,
I'm trying to setup an API for my BLL and I got GET and DELETE actions working fine. Now I'm trying to submit data back to the API with PUT but I can't get it to work. Specifically, I'm using HttpClient as the client to talk to Web API.
Here is the code I'm using which just hangs:
tugberk_ugur...
Participant
1944 Points
1344 Posts
MVP
Re: How to correctly use PostAsync and PutAsync?
Feb 23, 2012 01:32 PM|LINK
I would encourage you to go and have a look at C# Async CTP. You can get it today and build apps with it. It has go-live licence as well and C# 5 will have the features inside that CTP.
With async CTP, you will be able to write asyncronous code just like you write your syncronous code. I am not a good enough on that to give samples but you can do the following AFAIK:
var result = await httpClient.PutAsync(_endpoint, requestMessage.Content); return await result.Content.ReadAsStringAsync();tweets as @tourismgeek
SiggiGG
Member
265 Points
105 Posts
Re: How to correctly use PostAsync and PutAsync?
Feb 23, 2012 01:58 PM|LINK
First of all, are generic methods supported in the Web API? I think I read somewhere they currently are not?
What are you trying to accomplish with the method btw? You are accepting a generic class then formatting it into a json string. Why not just use JsonValue? What kind of data are you doing a PUT with btw?
But heres a modified example of how you can leverage async today, but I wrote the example without the generic support.
The trick is to make the API method return a Task, then you are not blocking the request thread when waiting for the client to finish.
public Task<string> Put(string data) { var mediaType = new MediaTypeHeaderValue("application/json"); var jsonSerializerSettings = new JsonSerializerSettings(); var jsonFormatter = new JsonNetFormatter(jsonSerializerSettings); var requestMessage = new HttpRequestMessage<T>(data, mediaType, new MediaTypeFormatter[] { jsonFormatter }); var httpClient = new HttpClient() return httpClient.PutAsync(_endpoint, requestMessage.Content).ContinueWith(httpResponseMessage => { return httpResponseMessage.Result.Content.ReadAsStringAsync(); }); }skippyfire
Member
34 Points
31 Posts
Re: How to correctly use PostAsync and PutAsync?
Feb 23, 2012 02:40 PM|LINK
Thanks for the replies guys, but I think that my problem is not with sync/async.
I would love to use the new await keyword, but right now, I don't want to be building against the .NET 4.5 Developer Preview.
Back to the issue.
Even if my code was blocking the thread until the response was returned, the code would still continue (eventually). I'm posting to a local Web API service on another port, and my GET and DELETE actions are instantaneous. So something is fundamentally wrong with my code, causing it to hang. I think it's on the client end, because I'm pretty sure the request never actually hits the service on the other end.
All I'm trying to do is serialize a POCO and PUT it to the Web API to update a record in a database. My put handler in the Web API controller looks like this:
Any other ideas?
SiggiGG
Member
265 Points
105 Posts
Re: How to correctly use PostAsync and PutAsync?
Feb 23, 2012 02:46 PM|LINK
So the API you showed in your first post is functioning as a kind of reverse proxy?
What are you serializing your POCO as when posting? If it's JSON, then instead of a generic method just use JsonValue and send that on to your backend service?
Try changing your method to not be generic, people have had problems with generic methods on a controller:
http://forums.asp.net/t/1770829.aspx/1?Using+generics+in+ApiController+controller+
skippyfire
Member
34 Points
31 Posts
Re: How to correctly use PostAsync and PutAsync?
Feb 23, 2012 03:33 PM|LINK
Thanks for another reply SiggiGG.
I don't think generics are my problem. I tried removing all the generic code and just doing a post to the service and it still hangs.
I also tried re-including the async code (in .NET 4), and I still have the same problem.
Can you elaborate on the JsonValue mechanism you mentioned?
Kiran Challa
Participant
1442 Points
281 Posts
Microsoft
Re: How to correctly use PostAsync and PutAsync?
Feb 23, 2012 03:40 PM|LINK
Are you using the JsonNetFormatter from here?
http://code.msdn.microsoft.com/Using-JSONNET-with-ASPNET-b2423706
If Yes, then there seems to be a problem in the WriteToStreamAsync method of this formatter. I was able to repro this issue. This method seems to work fine while writing the response on the Service side, but has problems writing on the Client side. I have notified Henrik regarding this. Will post updates.
[UPDATE] : The blog has been updated with the fix to the JsonNetFormatter. You should be able to use it now.
Kiran Challa
SiggiGG
Member
265 Points
105 Posts
Re: How to correctly use PostAsync and PutAsync?
Feb 23, 2012 03:54 PM|LINK
JsonValue is a really handy type to deal with JSON data in a loosely typed way.
In your case you can do something like this:
public void Post(JsonValue value) { var httpClient = new HttpClient(); httpClient.BaseAddress = new Uri("http://localhost:31724"); StringContent content = new System.Net.Http.StringContent(value.ToString(), Encoding.UTF8, "application/json"); var result = httpClient.PutAsync("api/Values", content).Result; }skippyfire
Member
34 Points
31 Posts
Re: How to correctly use PostAsync and PutAsync?
Feb 23, 2012 03:59 PM|LINK
Stupid question: How do I new up a JsonValue?
It looks like the constructor(s) are not public and I don't see any static methods that would let me "load" a JsonValue from a concrete POCO.
Is JsonObject what I want instead?
SiggiGG
Member
265 Points
105 Posts
Re: How to correctly use PostAsync and PutAsync?
Feb 23, 2012 04:22 PM|LINK
You can use JsonValue.Parse(string json) to create a new instance.
Just curious, why do you need to new up a JsonValue? When posting data you can just post normal POCO classes. I was just showing you how to use JsonValue to receive loosely typed data.