I am running into a deadlock situation when trying to post to WebApi 2 from WebApi 1 using HttpClient PostAsync and using async and await.
Below is WebAPI 1:
public HttpResponseMessage Get([FromUri]int oid)
{
var orderdetails = _orderServices.GetOrderDetails(oid);
var xml = new XmlMediaTypeFormatter();
xml.UseXmlSerializer = true;
string orderdetailsser = Serialize(xml, orderdetails);
var result = PostXml(orderdetailsser);
return Request.CreateResponse(HttpStatusCode.OK);
}
public static async Task<HttpResponseMessage> PostXml(string str)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:58285/");
var content = new StringContent(str);
var response = await client.PostAsync("api/default/ReceiveXml", content).ConfigureAwait(false);
return response;
}
}
And WebApi2:
[System.Web.Http.HttpPost]
public HttpResponseMessage ReceiveXml(HttpRequestMessage request)
{
var xmlDoc = new XmlDocument();
xmlDoc.Load(request.Content.ReadAsStreamAsync().Result);
xmlDoc.Save(#"C:\xmlfiles\xml2.xml");
XmlSerializer deserializer = new XmlSerializer(typeof(OrderInfoModel));
TextReader reader = new StreamReader(#"C:\xmlfiles\xml2.xml");
object obj = deserializer.Deserialize(reader);
OrderInfoModel orderdetails = (OrderInfoModel)obj;
reader.Close();
var patient_id = _patientServices.ProcessPatient(orderdetails.Patient, orderdetails.OrderInfo);
var orderid = _orderServices.ProcessOrder(orderdetails.Patient, orderdetails.OrderInfo, patient_id);
if (orderdetails.OrderNotes != null && orderdetails.OrderNotes.Count() > 0)
{
var success = _orderServices.ProcessOrderNotes(orderid, orderdetails.OrderNotes);
}
var prvid = _orderServices.ProcessOrderProvider(orderid, orderdetails.ReferringProvider);
var shpngid = _orderServices.ProcessOrderShipping(orderid, orderdetails.ShippingInfo);
var payerid = _orderServices.ProcessOrderPayer(orderid, orderdetails.Insurances);
return Request.CreateResponse(HttpStatusCode.OK, orderid);
}
I am not getting any response back to WebAPI 1 from WebAPI 2. I have gone through several articles online about deadlock situation. However, I am unable to resolve the deadlock in my case. What am I doing wrong here? Am I using async and await properly?
To build off my comment above, modify your code so that you are not blocking on an async operation. Additionally _orderServices.GetOrderDetails(oid); sounds like a method that hits a database and as such should be await _orderServices.GetOrderDetailsAsync(oid); wherein you use the whatever async api is available for your database access.
[HttpGet()]
public async Task<HttpResponseMessage> Get([FromUri]int oid) {
var orderdetails = _orderServices.GetOrderDetails(oid);
var xml = new XmlMediaTypeFormatter();
xml.UseXmlSerializer = true;
string orderdetailsser = Serialize(xml, orderdetails);
var result = await PostXml(orderdetailsser);
return Request.CreateResponse(HttpStatusCode.OK);
}
public static async Task<HttpResponseMessage> PostXml(string str) {
using(var client = new HttpClient()) {
client.BaseAddress = new Uri("http://localhost:58285/");
var content = new StringContent(str);
var response = await client.PostAsync("api/default/ReceiveXml", content).ConfigureAwait(false);
return response;
}
}
[HttpPost()]
public async Task<HttpResponseMessage> ReceiveXml(HttpRequestMessage request) {
var xmlDoc = new XmlDocument();
xmlDoc.Load(await request.Content.ReadAsStreamAsync());
xmlDoc.Save(#"C:\xmlfiles\xml2.xml");
XmlSerializer deserializer = new XmlSerializer(typeof(OrderInfoModel));
TextReader reader = new StreamReader(#"C:\xmlfiles\xml2.xml");
object obj = deserializer.Deserialize(reader);
OrderInfoModel orderdetails = (OrderInfoModel)obj;
reader.Close();
var patient_id = _patientServices.ProcessPatient(orderdetails.Patient, orderdetails.OrderInfo);
var orderid = _orderServices.ProcessOrder(orderdetails.Patient, orderdetails.OrderInfo, patient_id);
if(orderdetails.OrderNotes != null && orderdetails.OrderNotes.Count() > 0) {
var success = _orderServices.ProcessOrderNotes(orderid, orderdetails.OrderNotes);
}
var prvid = _orderServices.ProcessOrderProvider(orderid, orderdetails.ReferringProvider);
var shpngid = _orderServices.ProcessOrderShipping(orderid, orderdetails.ShippingInfo);
var payerid = _orderServices.ProcessOrderPayer(orderid, orderdetails.Insurances);
return Request.CreateResponse(HttpStatusCode.OK, orderid);
}
Resources
Don't Block on Async Code
Avoid Async Void
Related
I'm learning how to create WEB-API client
I've created some simple API:
[HttpGet]
public IHttpActionResult GetInfo()
{
return Ok("Its working!");
}
[HttpPost]
public IHttpActionResult PostInfo(ClientDataDto dto)
{
try
{
someMethod(dto.IdKlienta, dto.Haslo, dto.IdZgloszenia, dto.HardwareInfo, dto.SoftwareInfo);
return Ok("sent");
}
catch
{
return BadRequest();
}
}
For now I just trying to call GET method.
When I use Fiddler with addr
localhost:someport/api/Client2
its working
but when i try to do it by client, which code is below:
private static HttpClient client = new HttpClient();
static void Main(string[] args)
{
#region TESTONLY
var debug = new XMLData();
string HardwareInfoXML = debug.HardwareXML;
string SoftInfoXML = debug.SoftwareXML;
int id_zgloszenia = 20;
int idKlienta = 25;
//haslo = "202cb962ac59075b964b07152d234b70";
#endregion
var data = new ClientDataDto() { HardwareInfo = HardwareInfoXML, SoftwareInfo = SoftInfoXML, IdKlienta = idKlienta, IdZgloszenia = id_zgloszenia };
RunAsync(data);
}
private static async Task RunAsync(ClientDataDto data)
{
var stringContent = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.BaseAddress = new Uri(#"http://localhost:7774/api/client2/");
var url = new Uri(#"http://localhost:7774/api/client2/");
var res1 = await client.GetAsync(url);
var res = await client.PostAsync(url, stringContent);
res.EnsureSuccessStatusCode();
}
Application closing without any info at
var res1 = await client.GetAsync(url);
I have checked to see all exceptions in Debug exception Windows, but it is just closing after trying call GetAsync
PostASync doesn't work too.
What is wrong here?
i'm really sorry that i've posted simpe problem.
sulotion is to add .Wait() on RunAsync(data);
RunAsync(data).Wait();
I am calling an API Post method, however, I am not sure what I am doing wrong but the value in the API is always null. The method I am calling the API from is below. When I hit this I can see Ids is list of ints with 5 values for example.
private void Save(List<int> Ids)
{
var myAPI = ConfigurationManager.AppSettings["MyAPI"];
string myIds = string.Join(",", Ids);
using (var client = new HttpClient())
{
int result = client.PostAsync(myAPI, new { test = myIds }, new JsonMediaTypeFormatter())
.Result
.Content
.ReadAsAsync<int>()
.Result;
}
}
My API signature is like below - with a breakpoint on I can see it is getting hit but test the parameter I am trying to pass is always null
[HttpPost]
[Route("api/MyController/SaveData")]
public HttpResponseMessage SaveData([FromBody]List<string> test)
{
try
{
//Rest of method removed for brevity
I have tried removing the [FromBody] Annotation from the WebAPI controller but test still is getting null with breakpoint in the SaveData API method
Try this:
private void Save(List<int> Ids)
{
var myAPI = ConfigurationManager.AppSettings["MyAPI"];
using (var client = new HttpClient())
{
var requestBody = JsonConvert.SerializeObject(Ids);
var postRequest = new StringContent(requestBody, Encoding.UTF8, "application/json");
var response = client.PostAsync(myAPI, postRequest).GetAwaiter().GetResult();
var rawResponse = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
// Do something with the answer
}
}
I also suggest to make the method private Task Save and replace .GetAwaiter().GetResult(); with await in front of that calls.
In my case i used System.Web.Http.ApiController instead of System.Web.Mvc.Controller. So over all code looks like
public class YourAppController : ApiController
{
[System.Web.Http.Route("publish-message")]
public HttpResponseMessage Post([System.Web.Http.FromBody] string msges)
{
//Your Code
return Request.CreateResponse(HttpStatusCode.OK, "");
}
}
public async Task<string> PublishMessageCall(string publishMessage){
var returnval = "";
string httpWebRqst = "http://localhost:543134535/publish-message";
using (HttpClient myClient = new HttpClient())
{
var jsonString = JsonConvert.SerializeObject(publishMessage);
var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
var response = await myClient.PostAsync(httpWebRqst, content);
var responseString = await response.Content.ReadAsStringAsync();
}
return await Task.FromResult(returnval);}
I have an object.
I'am sending it this to my api project this way :
mymodel obj = new mymodel();
obj.prop = "this";
obj.prop2 = "prop2";
var content = JsonConvert.SerializeObject(obj);
var buffer = System.Text.Encoding.UTF8.GetBytes(content);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
string response = "";
using (HttpClient client = new HttpClient())
{
var rez = await client.PostAsync(uri + myenum.Insert, byteContent).ConfigureAwait(false);
response = rez.ToString();
}
In my api method i want to convert that string or http content again to model.
[ActionName("Insert")]
[HttpGet]
public bool Insert(string obj)
{
try
{
mymodel model = JsonConvert.DeserializeObject<mymodel>(obj);
How to handle object i'am sending with postasync in my api method ?
Any help ?
First you cannot use PostAsync on a HTTPGet method.
Second, I dont understand what you mean. If you are using json then you dont have to do anything. Just have a simple client method as such:
public async Task<TResult> PostAsync<TResult, TInput>(string uriString, TInput payload = null) where TInput : class
{
var uri = new Uri(uriString);
using (var client = GetHttpClient())
{
var jsonContent = JsonConvert.SerializeObject(payload, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
HttpResponseMessage response = await client.PostAsync(uri, new StringContent(jsonContent, Encoding.UTF8, "application/json"));
if (response.StatusCode != HttpStatusCode.OK)
{
//Log.Error(response.ReasonPhrase);
return default(TResult);
}
var json = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TResult>(json);
}
}
And you can just add the same object to your API like
[ActionName("Insert")]
[HttpPost]
public bool Insert(YourObjectClass obj)
{
try
{
....code....
}
}
public async static Task<RootObject> GetWeather(string username, string password)
{
var http = new HttpClient();
var response = await http.GetAsync(postURI);
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var datax = (RootObject)serializer.ReadObject(ms);
return datax;
}
I have the necessary models ready and I made the function call with some hard-coded data to test but its not working.
I have no idea how to POST JSON with HttpClient. I find some solution, like this, but I have to use HttpClient, cause of async and have to add a header.
This is my code below. Any idea how to fix it?
List<Order> list = new List<Order> { new Order() { Name = "CreatedTime", OrderBy = 1 } };
Queues items = new Queues { Orders = list };
var values = new Dictionary<string, string> { { "Orders", JsonConvert.SerializeObject(list) } };
var content = new FormUrlEncodedContent(values);
//HttpContent cc = new StringContent(JsonConvert.SerializeObject(items));
_msg = await _client.PostAsync(input, content);
//_msg = await _client.PostAsync(input, cc);
var response = await _msg.Content.ReadAsStringAsync();
You can use the method PostAsJsonAsync which can be found in the extensions assemblies:
System.Net.Http.Formatting.dll
Example
public static async Task SendJsonDemo(object content)
{
using(var client = new HttpClient())
{
var response = await client.PostAsJsonAsync("https://example.com", content);
}
}
If you want to add custom headers to the request, add it to DefaultRequestHeaders:
client.DefaultRequestHeaders.Add("mycustom", "header1");
You can send any type of request like as
public static async Task<HttpResponseMessage> SendRequest(HttpMethod method, string endPoint, string accessToken, dynamic content = null)
{
HttpResponseMessage response = null;
using (var client = new HttpClient())
{
using (var request = new HttpRequestMessage(method, endPoint))
{
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
if (content != null)
{
string c;
if (content is string)
c = content;
else
c = JsonConvert.SerializeObject(content);
request.Content = new StringContent(c, Encoding.UTF8, "application/json");
}
response = await client.SendAsync(request).ConfigureAwait(false);
}
}
return response;
}