Generic async HttpClient method sometimes doesn't work? - c#

I'm creating an application with Xamarin.Forms which consume from SOAP services using POST method; I have a bunch of services that work correctly, indeed, one of these methods is used to send information in multiple cases and my problem is related with this.
I have the following HttpClient method, but sometimes doesn't work... unfortunately I don't have access to back-end code and they are not for the labour of help me with that.
Any idea about how to improve my method or get any approach to the real error? I'm stuck here, since I send the same fields each time.
public async Task<string> InvokeAsync (string uri, string xmlSOAP) {
try {
using (var handler = new HttpClientHandler () { UseCookies = false })
using (var client = new HttpClient (new NativeMessageHandler ())) {
client.DefaultRequestHeaders.Accept.Add (new MediaTypeWithQualityHeaderValue ("application/xml"));
client.DefaultRequestHeaders.Add ("Cache-Control", "no-cache, no-store, must-revalidate");
client.DefaultRequestHeaders.Add ("Pragma", "no-cache");
client.Timeout = TimeSpan.FromSeconds (timeout);
client.DefaultRequestHeaders.CacheControl.NoCache = true;
var req = new HttpRequestMessage (HttpMethod.Post, uri)
{
Content = new StringContent (xmlSOAP, Encoding.UTF8)
};
req.Content.Headers.ContentType = MediaTypeHeaderValue.Parse ("text/xml; charset=utf-8");
if (uri.ToLowerInvariant ().Equals (jsessionUrlCheck)) {
if (jsession != null && jsession.Count > 0) {
foreach (var cookie in jsession) {
req.Headers.Add ("JSESSIONID", cookie);
}
}
jsession = null;
}
HttpResponseMessage response = await client.SendAsync (req);
string responseBodyAsText = response.IsSuccessStatusCode ? await response.Content.ReadAsStringAsync () : string.Empty;
if (!string.IsNullOrEmpty (responseBodyAsText))
{
return responseBodyAsText;
}
return null;
}
} catch (Exception e) {
Debug.WriteLine ("========= InvokeAsync Exception =========");
Debug.WriteLine ("Error: " + e.Message);
return null;
}}

Any idea about how to [...] get any approach to the real error?
It sounds like you don't really know what exactly happens when it "doesn't work". The way you approach the real error is by finding out what exactly happens in this code when it is reported not to work.
Do you have logs? Check the logs. If the exception is there, that should point you in the right direction. Exception not there? Maybe start logging the data received too. No logs? Start logging; there's no better way to handle intermittent failures that you can't reproduce on demand.

Related

Code gets skipped after doing a HttpRequest

So I'm making a POST call to my API to get multiple objects which then get added to a list and are displayed in the RecyclerView. The problem is, after getting to the var result it skips the entire remaining code in that method and executes the next method SetupRecyclerView. The catch doesn't catch any exception. What's wrong with that code?
async void GetPostList()
{
try
{
string url = "linkToMyWebService";
var uri = new Uri(url);
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = uri
};
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
HttpClient client = new HttpClient(clientHandler);
var result = await client.SendAsync(request);
var contentBody = await result.Content.ReadAsStringAsync();
List<postRetrieved> posts = JsonConvert.DeserializeObject<List<postRetrieved>>(contentBody);
foreach (var post in posts)
{
postModel newPost = new postModel();
newPost.username = post.fullName;
newPost.description = post.postTitle;
newPost.city = post.postCity;
postList.Add(newPost);
}
}
catch
{
}
}
void SetupRecyclerView()
{
postRecyclerView.SetLayoutManager(new Android.Support.V7.Widget.LinearLayoutManager(postRecyclerView.Context));
postAdapter = new PostAdapter(MainScreenPosts);
postRecyclerView.SetAdapter(postAdapter);
}
It is likely about Catch. Some error is being returned, and an empty catch causes the method to get skipped.
You can either enable "Common Language Runtime Exception" in "Exception settings" or log the error inside the catch. This will help you to get more details about what went wrong in your code.
Alright, so the problem was with the fact that GetPostList was asynchronous. While waiting for the request to get the list of objects, it started doing the method SetupRecyclerView which required those objects to function. I've put that in the Finally{} block in my trycatch and now it works fine.

Xamarin HttpClient GetStringAsync seems inconsistent

I'm pulling my hair out on this.
I'm working on a Xamarin Forms project and Prism. I have this function that calls Google Map Autocomplete. This past few days it work, but now it doesn't. I traced it and found that my GetStringAsync is not returning anything. It just stop at that function, no errors thrown.
This is my code.
public async Task<List<PredictionsItem>> Predict(string address)
{
List<PredictionsItem> predictions = new List<PredictionsItem>();
try
{
if (Connectivity.NetworkAccess == NetworkAccess.Internet)
{
HttpClient client = new HttpClient();
string _url = "https://maps.googleapis.com/maps/api/place/autocomplete/json?input=" + address +"&types=geocode&components=country:ph&key=" + Key;
string response = await client.GetStringAsync(_url);
client.Dispose();
var result = JsonConvert.DeserializeObject<Root>(response);
return result.predictions;
}
return predictions;
}
catch
{
return predictions;
}
}
It just stops here "string response = await client.GetStringAsync(_url);". No errors thrown.
Am I missing something or doing something wrong?

WebAPI is returning 200 but the SendAsync call shows 500

I have an MVC application that calls a WebAPI async, both on POST and GET. When running both the WebAPI and MVC applications locally, the WebAPI response shows successful but the SendAsync request returns 500. Also, Fiddler doesn't show the API call. I have a suspicion that it has to do with how the async request is being handled, but I'm not sure what I'm missing.
MVC Controller call to the API:
public Model UploadFile(Model formCollection)
{
var documentModel = formCollection.ToString();
var client = new HttpClient();
var uri = new Uri(BaseUri + "document/");
var content = new StringContent(documentModel);
var request = new HttpRequestMessage(HttpMethod.Post, uri) {Content = content};
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = client.SendAsync(request);
response.Wait();
try
{
var returned = response.Result;
if (returned.StatusCode != HttpStatusCode.OK)
{
throw new Exception(returned.RequestMessage.ToString());
}
var model = JsonConvert.DeserializeObject<Model> (returned.Content.ReadAsStringAsync().Result);
model.FileContents = "";
return model;
}
catch(Exception e)
{
var error = new Exception("Service failure - ", e);
throw error;
}
}
The WebAPI Post:
[HttpPost]
public async Task<HttpResponseMessage> Post([FromBody]Model model)
{
var response = await SubmitNew(model);
return Request.CreateResponse(response);
}
Setting the breakpoint on the return in the Post shows a valid response, but on the response.Result in the MVC Controller it shows 500. I've even tried returning an OK request no matter the response as below:
return Request.CreateResponse(HttpStatusCode.OK, result);
Any ideas as to why the client is showing 500?
In your Global.asax.cs
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// Try adding the following lines:
var configuration = GlobalConfiguration.Configuration;
var formatters = configuration.Formatters;
formatters.Clear();
formatters.Add(new JsonMediaTypeFormatter());
}
// A good idea to have this:
protected void Application_Error()
{
Exception unhandledException = Server.GetLastError();
// Set a breakpoint here or do something to log the exception
}
The code added to Application_Start will ensure that serialization is only to/from JSON. While it may not be what you want in your final code, it may be helpful as a temporary measure to isolate the cause of your problem.
Adding Application_Error should help to catch issues which occur within the WebAPI layer, such as when it serializes the object you've returned from your controller method.
My suspicion is that SubmitNew is returning something which cannot be serialized such as an infinitely recursive reference (example: parent/child structure with mutual references).
I found the issue, there was a timeout error in the WebAPI's logging service that was happening after the initial POST and GET calls result.. Issue is resolved.
I had a similar issue with some code that I "improved" - I saw HttpResponseMessage implements the IDisposable interface so decided to wrap the Return Request.CreateResponse method is a using statement, leading to a 500 error.
Removing the using statement fixed the issue for me.

RestSharp weird error on Method.Put

I'm trying to update a resource using RestSharp. The API works well because are used in another application so this exclude some routing issues or whatever the problem is on my side not on API one.
Anyways. My current scenario is that I want to update a specific resource located at host/api/resource/id
This is my current code inside the DataProvider layer
public override bool Update(string resource, Dictionary<string, object> properties)
{
this.request = new RestRequest(resource + "/{id}", Method.PUT);
for (int i = 0; i < properties.Count; ++i)
{
KeyValuePair<string, object> kvp = properties.ElementAt(i);
if (kvp.Key != "id")
this.request.AddParameter(kvp.Key, kvp.Value, ParameterType.GetOrPost);
else
this.request.AddParameter(kvp.Key, kvp.Value, ParameterType.UrlSegment);
}
var response = this.CallApi();
// ... other stuff
}
This code simply create the request and the correct parameters based on the dictionary that the method received from outside, then it calls the CallApi() method which is this
private IRestResponse CallApi()
{
var client = new RestClient(BaseUrl);
var response = client.Execute(this.request);
if(response.ErrorException != null)
{
// Response has some error!
// ... other stuff
}
if(response.StatusCode != System.Net.HttpStatusCode.OK)
{
// Response received something different from HTTP status code OK
// ... other stuff
}
return response;
}
CallApi works perfectly for every other call such as GET, POST, DELETE and even PATCH but when I try to use it with Update, and thus using PUT, the response received from client.Execute(this.request) is 405 Method Not Allowed.
After debugging a little bit I figured it out that the respone has a ResponseUri with only the host string instead of host/api/resource/id this seems to be caused by the
this.request = new RestRequest(resource + "/{id}", Method.PUT);
in fact if I remove the /{id} part, the RequestUri has the correct form of host/api/resource, of course without the id, which is wrong anyway because I need the id :-/
Does anyone know why this is happening?
The problem was at the backslash on new Instance. Just remove the backslash from /{id} and it works

HttpClient.PostAsJsonAsync never sees when the post is succeeding and responding

We are using an HttpClient to post json to a restful web service. In one instance, we are running into something that has us baffled. Using tools like postman, fiddler etc, we can post to an endpoint and see that it is working. When we do the same with HttpClient.PostAsJsonAsync, we can verify in the software we are posting to that it received the data just fine. However, our PostAsJsonAsync will always eventually time out rather than give us a response.
We have worked with the team that created the service we are consuming, plus our additional testing on our side, and we have not yet been able to truly time out that service.
Every time we do a post with HttpClient, we then can verify that the target software we post to does indeed get the data. Any time we do a post to that target software from any other tool, we always very quickly see a response with status code of 200. Something about HttpClient is failing to accept the response from this particular service. Does anyone have an idea what we can look at from here?
Here's the code (though it is so cookie cutter that I hardly feel it is needed)
public string PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
using (var client = new HttpClient())
{
if (timeoutMinutes > 0)
{
client.Timeout = new TimeSpan(0,timeoutMinutes,0);
}
var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
var response = client.PostAsJsonAsync(useUrl, o).Result;
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
return response.Content.ReadAsStringAsync().Result;
}
return "";
}
}
This:
var response = client.PostAsJsonAsync(useUrl, o).Result;
Is causing you code to deadlock. This is often the case when blocking on async API's, and that's why you're experiencing the "I don't see any response coming back" effect.
How is this causing a deadlock? The fact that you are executing this request in an environment that contains a synchronization context, perhaps one which belongs to the UI. It's executing the async request, and when the response arrives, it continues via an IO completion thread which attempts to post the continuation onto that same UI context, which is currently blocked by your .Result call.
If you want to make an HTTP request synchronously, use WebClient instead. If you want to take advantage of the async API properly, then await instead of block with .Result.
I had the same issue and this SO answer fixed it for me.
In a nutshell, you have to use the ConfigureAwait(false) extension to avoid the deadlock:
var response = await client.PostAsJsonAsync(useUrl, o).ConfigureAwait(false);
Is there a reason why you're not following the async await pattern? You're calling an async method, but not awaiting it. You didn't say if the code calling your REST service was a Windows Forms or ASP.NET application, but that .Result is probably causing you issues.
Can you restructure your method like this:
public async Task<string> PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
using (var client = new HttpClient())
{
if (timeoutMinutes > 0)
{
client.Timeout = new TimeSpan(0,timeoutMinutes,0);
}
var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
var response = await client.PostAsJsonAsync(useUrl, o);
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
return await response.Content.ReadAsStringAsync();
}
return "";
}
}
This is a slight modification to #Justin Helgerson's solution. There are 2 blocking .Result calls in your method; once you go async you should fix them both.
public async Task<string> PostDataAsync(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
using (var client = new HttpClient())
{
if (timeoutMinutes > 0)
{
client.Timeout = new TimeSpan(0,timeoutMinutes,0);
}
var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
var response = await client.PostAsJsonAsync(useUrl, o);
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
return await response.Content.ReadAsStringAsync();
}
return "";
}
}
Note I've also renamed the method to PostDataAsync in accordance with the TAP pattern.
System.Net.ServicePointManager.Expect100Continue = false;
That one line of code in our case fixed the problem. A developer from a different team offered that suggestion, and it works. I have yet to google it and read up on it enough to offer an explanation of what that is addressing.

Categories

Resources