how to properly use HttpClient wrapped as a Class Libary - c#

In my C# app I need to have 2 distinct parts:
1) a Class Library, which wraps HttpClient, takes parameters, such as URI, and a JSON object to be POSTED, and invokes the POST method on an instance of HttpClient:
static async Task CreateCustomer()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://10.211.55.2:8080/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Accept", "application/json");
var customer = new Customer() { Name = "Gizmo", Address = "123 Widget lane" };
var response = await client.PostAsJsonAsync("/api/customer", customer);
var p = response;
}
}
2) A Windows Console app, which imports this Class Library, and invokes this CreateCustomer method, passing the actual parameter values for the URI and the Customer JSON object:
static async Task EnvokeCreateCustomer()
{
Customer customer = new Customer {Name="",Address="" };
var URI = "http://my_api:8080/Customer";
RestClient.Client restClient = new RestClient.Client();
restClient.CreateCustomer(URI, customer);
}
This code runs, but it is not event hitting my API, blows right passed it, and does nothing. Same issue with the GET API.
Is there a proven way to create such Class Libraries, which can be invoked by a Console app?

You don't await the method call:
await restClient.CreateCustomer(URI, customer);
Depending on the application host this may or may not make a noticeable difference. In a console application, where the application may simply do its thing and immediately terminate, it makes an enormous difference.
Not to mention any errors received in the process may go entirely unnoticed if the call is not awaited. So it's possible that there is a problem and it's trying to tell you what the problem is, but your code is simply ignoring it.
Surely there's a compiler warning pointing this out. Never ignore compiler warnings.
Side note: How does this code even compile? This:
restClient.CreateCustomer(URI, customer);
can't be calling this:
static async Task CreateCustomer()
If what you're showing us isn't your actual code, then all bets are off as far as answers go.

Related

The code after await operation is not executing

I'm writing a xamarin forms app and I'm using an API that I created. I've followed a tutorial to consume the Api but the code after the async operation never gets executed, it jumps out to the main function.
The code is exactly like the one in the tutorial I've been following. I didn't find any info since there is no error message.
private async void ChecarCredenciales(string username, string password)
{
HttpClient client = new HttpClient();
var url = "http://localhost:57008/api/operadores/" + username;
var response = await client.GetStringAsync(url).ConfigureAwait(false);
Lecturista = JsonConvert.DeserializeObject<Operadores>(response);
}
The JsonConvert.DeserializeObject never gets executed so the Lecturista variable never gets initialized.
Thanks in advance.
First as other already commented change your method to be async Task rather like private async Task ChecarCredenciales(string username, string password){
Second in your await block you are saying to continue on a Threadpool thread context rather on the same synchronization context by doing ConfigureAwait(false);. I would suggest you continue on the same context since on the next step you are requiring the resultant data
var response = await client.GetStringAsync(url);
Lecturista = JsonConvert.DeserializeObject<Operadores>(response);

HTTP Client with Unity, application hangs

I have a pretty basic script in my Unity game which is trying to submit form data in POST to a server. But unity seems to freeze/hang indefinitely. I am confused why this is happening and so i don't know how to solve the problem.
I made my code loosely following this article:
https://learn.microsoft.com/en-us/dotnet/csharp/tutorials/console-webapiclient#making-web-requests
My server does receive the request and does write one back. But because unity is frozen its not really usable at the moment.
My class looks like this:
public class HTTPManager : MonoBehaviour
{
private static HttpClient client = new HttpClient();
private void Awake()
{
client.BaseAddress = new Uri("http://localhost:8080/");
ProcessRepositories().Wait();
}
private async Task ProcessRepositories()
{
client.DefaultRequestHeaders.Accept.Clear();
FormUrlEncodedContent content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("u", "test")
});
//this goes to http://localhost:8080/hello with POST u=test
HttpResponseMessage result = await client.PostAsync("hello",content);
Debug.Log("Is Success: "+result.IsSuccessStatusCode);
Debug.Log("Status code: "+result.StatusCode);
Debug.Log("Reason Phrase: "+result.ReasonPhrase);
Debug.Log("Headers: "+result.Headers);
Debug.Log("Content: "+result.Content);
Debug.Log("Request Message: "+result.RequestMessage);
Debug.Log("Version: "+result.Version);
}
}
Whats causing the hanging issue??
ProcessRepositories().Wait();
is blocking on async code and it is causing a deadlock. Stephen Clearly has a whole series of posts on this.
Either make all the code async all the way up or schedule continuations on your Task.
EDIT: It seems that Awake is a Unity method. For this you have 4 options:
1) Remove async Task from ProcessRepositories(). Remove the await in the method body and make your calls to your server synchronous. This will cause jitters and it not a recommended solution in a game environment.
2) Remove .Wait() from ProcessRepositories(). This will cause your code to async post to server but you won't be able to do anything with the the response. This is fine if you don't care about the response.
3.) If you do care about the response, you can schedule Continuations on ProcessRepositories(). This is a type of "callback" that will run when your Task has RanToCompletion or it errored out. To achieve this, change ProcessRepositories() to ProcessRepositories().ContinueWith(task=>
{
// in here you can access task.Result to get your response
}) and change your ProcessRepositories method to return the HttpResponseMessage result
i.e return await client.PostAsync("hello",content);
4) Use ConfigureAwait(false) as mentioned below but that will return the result on a different context and seeing that this Unity, you probably want the result on the UI thread, so just watch out for that.
Don't use HttpClient with unity, use the class WWW and unity's built in coroutine features, yield return it and it will wait for the download to complete.
public class HTTPManager : MonoBehaviour
{
private IEnumerator Awake()
{
return ProcessRepositories();
}
private IEnumerator ProcessRepositories()
{
var form = new WWWForm();
form.AddField("u", "test");
var www = new WWW("http://localhost:8080/hello", form);
yield return www;
Debug.Log("responseHeaders: "+www.responseHeaders);
Debug.Log("text: "+www.text);
}
}

Http Client GetAsync await taking too long/not returning when called from controller [duplicate]

I was reading the following topic http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
and decided to write a common utility method in my library to do a GET on remote url via HTTPClient
public static async Task<T> GetAsync<T>(HttpGetObject getObject)
{
string baseUrl = getObject.BaseUrl;
string actionUrl = getObject.ActionRelativeUrl;
string acceptType = getObject.AcceptType;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(acceptType));
AddCustomHeadersToHttpClient(client, getObject);
// HTTP GET
HttpResponseMessage httpResponseMessage = await client.GetAsync(actionUrl).ConfigureAwait(false);
if (httpResponseMessage.IsSuccessStatusCode)
{
T response = await httpResponseMessage.Content.ReadAsAsync<T>().ConfigureAwait(false);
return response;
}
else
{
string message = httpResponseMessage.Content.ReadAsStringAsync().Result;
throw new Exception(message);
}
}
return default(T);
}
I know the "await httpResponseMessage.Content.ReadAsAsync().ConfigureAwait(false)" will prevent the deadlock in the above code
First:
My query is for "string message = httpResponseMessage.Content.ReadAsStringAsync().Result" line, will .Result can cause deadlock or not in that line?
Second:
If I call that code from UI like this:
public static object DoGet()
{
// Build getObject
var task = Utility.GetAsync(getObject);
task.Wait();
var response = task.Result;
return response;
}
Will that cause a deadlock?
Please note that I know to avoid all the mess with async-await, all the methods from UI to DAL must be async-await but I am not in position at this moment to change all that structure, my goal at this moment is to call HttpClient library and do a few GET operations.
So my questions is that will the above code can cause a deadlock?
Third:
Is task.Wait(); even needed in the above code?
In the general case, you should assume that yes, calling .Result or .Wait() on anything awaitable is dangerous and can deadlock (unless you are the library issuing the task, and you understand the full context). It is possible that it will work OK in some specific cases, but you should not rely on that behaviour, even if it works today.

Confusion with async/await web calls in order

I have a Web API service that is used to retrieve and update a specific set of data (MyDataSet objects), and I am running into some confusion in using async/await when performing the following events:
Update MyDataSet with new values
Get MyDataSet (but only after the new values have been updated)
In my client, I have something similar to the following:
Harmony.cs
private async Task<string> GetDataSet(string request)
{
using(var httpClient = new HttpClient())
{
httpClient.baseAddress = theBaseAddress;
HttpResponseMessage response = await httpClient.GetAsync(request);
response.EnsureSuccessStatusCode();
return response.Content.ReadAsStringAsync().Result;
}
}
private async Task PostDataSet<T>(string request, T data)
{
using (var httpClient = new HttpClient())
{
client.BaseAddress = new Uri(theBaseAddress);
HttpResponseMessage response = await client.PostAsJsonAsync<T>(request, data);
response.EnsureSuccessStatusCode();
}
}
internal MyDataSet GetMyDataSetById(int id)
{
string request = String.Format("api/MyDataSet/GetById/{0}", id);
return JsonConvert.DeserializeObject<MyDataSet>(GetDataSet(request).Result);
}
internal void UpdateDataSet(MyDataSet data)
{
PostDataSet("api/MyDataSet/Update", data);
}
HarmonyScheduler.cs
internal void ScheduleDataSet()
{
MyDataSet data = ...
harmony.UpdateDataSet(data);
MyDataSet data2 = harmony.GetMyDataSetById(data.Id);
}
There is a compiler warning in Harmony.cs UpdateDataSet because the call is not awaited and execution will continue before the call is completed. This is affecting the program execution, because data2 is being retrieved before the update is taking place.
If I were to make UpdateDataSet async and add an await to it, then it just moves things up the stack a level, and now HarmonyScheduler gets the warning about not being awaited.
How do I wait for the update to be complete before retrieving data2, so that I will have the updated values in the data2 object?
How do I wait for the update to be complete before retrieving data2,
so that I will have the updated values in the data2 object?
The thing I see many people don't comprehend is the fact that using the TAP with async-await will infect your code like a plague.
What do I mean by that?
Using the TAP will cause async to bubble up all the way to the top of your call stack, that is why they say async method go "all the way". That is the recommendation for using the pattern. Usually, that means that if you want to introduce an asynchronous API, you'll have to provide it along side a separate synchronous API. Most people try to mix and match between the two, but that causes a whole lot of trouble (and many SO questions).
In order to make things work properly, you'll have to turn UpdateDataSet and GetMyDataSetById to be async as well. The outcome should look like this:
private readonly HttpClient httpClient = new HttpClient();
private async Task<string> GetDataSetAsync(string request)
{
httpClient.BaseAddress = theBaseAddress;
HttpResponseMessage response = await httpClient.GetAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
private async Task PostDataSetAsync<T>(string request, T data)
{
client.BaseAddress = new Uri(theBaseAddress);
HttpResponseMessage response = await client.PostAsJsonAsync<T>(request, data);
response.EnsureSuccessStatusCode();
}
internal async Task<MyDataSet> GetMyDataSetByIdAsync(int id)
{
string request = String.Format("api/MyDataSet/GetById/{0}", id);
return JsonConvert.DeserializeObject<MyDataSet>(await GetDataSetAsync(request));
}
internal Task UpdateDataSetAsync(MyDataSet data)
{
return PostDataSetAsync("api/MyDataSet/Update", data);
}
Note - HttpClient is meant to be reused instead of a disposable, single call object. I would encapsulate as a class level field and reuse it.
If you want to expose a synchronous API, do so using a HTTP library that exposes a synchronous API, such as WebClient.
Always wait on the tasks right before you need its results.
Its always better to wait on a task if it contains an await in its body.
Warning : Do not use .Wait() or .Result
You would understand the concept better if you go through the control flow as explained Control Flow in Async Programs.
So in your case I would make all the functions accessing the async methods GetDataSet(string request) and PostDataSet<T>(string request, T data) with return type Task as awaitable.
Since you dont seem to expect any result back from the PostDataSet function you could just wait for it to complete.
PostDataSet("api/MyDataSet/Update", data).Wait();

HttpClient GetAsync hanging

I have an identical method in two of my WP8 apps. Given the same url and same device, the method works on one app, but not the other. In the failing app, GetAsync is hanging after it is called. No time out, no exception.
Here is the method in question.
private async Task<Byte[]> DownloadData(string uri)
{
byte[] myDataBuffer = null;
var newUri = new Uri(uri, UriKind.Absolute);
var myWebClient = new HttpClient();
var response = await myWebClient.GetAsync(newUri);
if (response.Content.Headers.ContentType.MediaType == "text/plain"
|| response.Content.Headers.ContentLength < 200)
{
throw new Exception(await response.Content.ReadAsStringAsync());
}
myDataBuffer = await response.Content.ReadAsByteArrayAsync();
return myDataBuffer;
}
This happens every time on one particular app, but not the other. Same device. Has anybody ever experienced this behavior? The url is valid, the code is identical. Is there a project setting somewhere that might affect this? I'm using the HttpClient in another portion of the failing app and it works there.
I can change the code to use a HttpWebRequest and that works fine. Just not the HttpClient.
I just now discovered that if I copy the method into my button_click handler, it works there too. Is there a problem having this method inside a separate class? That seems odd to me.
update
What seems to be breaking it is multiple layers of async methods calling it. Within the class I have
public override byte[] GetImageData(string imageUri)
{
return GetImageDataAsync(imageUri).Result;
}
public async Task<byte[]> GetImageDataAsync(string imageUri)
{
return await DownloadData(imageUri);
}
from my button_click handler, I'm calling GetImageData(uri). If I change that to await GetImageDataAsync(uri) it works.
Is Result not the correct property to reference in GetImageData?
Here's a test url "http://www.rei.com/pix/common/REI_logo.gif"
Calling Result or Wait can cause deadlocks, as I explain on my blog.
The proper way to solve this is to use await. I assume that there's some reason you want to synchronously block, but it's better to use await and find a way to make it work in your code.

Categories