Sorry for the name of my post but I am going to try to explain my problem.
I am building a client library to request an external API and I try to figure out how to make the methods of my library safe-threaded.
Basically the main class of my library looks like this :
public class MyCompanyApiClient
{
private readonly HttpClient _httpClient;
public MyCompanyApiClient(string baseUrl)
{
_httpClient = new HttpClient() {BaseAddress = new Uri(baseUrl)};
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<MyClassB> PostData(int id, MyClassA dataToPost)
{
var request = new HttpRequestMessage(HttpMethod.Post, $"objects/{id}");
request.Content = new StringContent(JsonConvert.SerializeObject(dataToPost), Encoding.UTF8,
"application/json");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var stringContent = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<MyClassB>(stringContent);
}
public async Task<MyClassA > GetById(int id)
{
...
}
}
I'd like to ensure that any instance members of my client class are safe-threaded.
For the moment I plan to wrap the code inside each method into a Task.Run:
public async Task<MyClassB> PostData(int id, MyClassA dataToPost)
{
return await Task.Run(async () =>
{
var request = new HttpRequestMessage(HttpMethod.Post, $"objects/{id}");
request.Content = new StringContent(JsonConvert.SerializeObject(dataToPost), Encoding.UTF8,
"application/json");
var response = await _httpClient.SendAsync(request);
var stringContent = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<MyClassB>(stringContent);
});
}
By the way I don't even know if it is going to ensure this method to be safe-threaded.
Any help aprreciated ^^
Thread-safe doesn't mean multi-threading.
It means that some code is aware that it'll be used in multi-threaded cases, and they won't get corrupted, won't produce deadlocks and other threading-related issues.
Sometimes there's code that it's thread-safe per se, while sometimes you need to use thread-synchronization approaches like monitors, mutexes, reset events, semaphores and others, to protect critical code sections from being executed by one, two or n threads at once in order to avoid, again, deadlocks, corruptions and, basically, unexpected behaviors.
In your case, it seems like you consider thread-safe launching your PostDataas a thread in the thread pool. This is a bad choice, you don't need a new thread for this.
Related
I am facing an issue regarding not getting response from GetAsync API of HttpClient in MVC Applications(Target Framework - .Net Framework 4.7) whereas getting response in web services and console applications with same snippet. Here I have attached code snippet which I am trying to execute.
public void Get()
{
var response = Gettasks().Result;
}
public static async Task<HttpResponseMessage> GetTasks()
{
var response = new HttpResponseMessage();
try
{
using (var client = new HttpClient())
{
response = await client.GetAsync("https://www.google.com");
}
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
return response;
}
I am getting stuck on response = await client.GetAsync("https://www.google.com"); this line and not getting any response after executing this statement.
If anyone can please suggest solution for this or provide fix/solution which works for you.
You're seeing a deadlock because the code is blocking on an asynchronous method.
The best fix is to remove the blocking:
public async Task Get()
{
var response = await Gettasks();
}
This deadlock happens because await captures a context, and ASP.NET (pre-Core) has a context that only allows one thread at a time, and the code blocks a thread (.Result) in that context, which prevents GetTasks from completing.
Both the context and the blocking are necessary to see this kind of deadlock. In the other scenarios, there is no context, so that is why the deadlock does not occur. Since ASP.NET (pre-Core) has a context, the proper solution here is to remove the blocking.
Not sure whether you have tried following which is working for me.
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(Environment.GetEnvironmentVariable("BaseAddress"));
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var requestUri = Environment.GetEnvironmentVariable("Uri");
HttpResponseMessage response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
}
}
I have an IO bound method that hangs for a split second while fetching data. I've attempted to convert the method to an async method but am having issues with this.
I've included below the non-async version of the code, and my attempt at making it async.
//non async method
public double GetBaseline()
{
var Client = new RestClient();
IRestResponse response;
Client.BaseUrl = new Uri("https://apiv2.bitcoinaverage.com/indices/global/ticker/short?crypto=BTC&fiat=USD");
CryptoAverage BTCAvg;
var request = new RestRequest();
response = Client.Execute(request);
BTCAvg = JsonConvert.DeserializeObject<CryptoAverage>(response.Content);
return Math.Round(BTCAvg.BTCUSD.Last, 2);
}
//async method
public async double GetBaselineAsync()
{
var Client = new RestClient();
IRestResponse response;
Client.BaseUrl = new Uri("https://apiv2.bitcoinaverage.com/indices/global/ticker/short?crypto=BTC&fiat=USD");
CryptoAverage BTCAvg;
var request = new RestRequest();
response = await Client.ExecuteAsync(request);
BTCAvg = JsonConvert.DeserializeObject<CryptoAverage>(response.Content);
return Math.Round(BTCAvg.BTCUSD.Last, 2);
}
There are two issues that I know of with the above code. The first line requires some some of Task keyword but I'm unsure how to code it. I've tried a number of things here without success.
Secondly, ExecuteAsync takes a 2nd argument but I'm unsure what. I've seen some examples of this, but they seem overly complicated for what I'm trying to do?
Appreciate any help you guys can offer!
If you want to use the Async Await pattern, you need to declare the method appropriately
public async Task<double> GetBaselineAsync()
{
var Client = new RestClient();
IRestResponse response;
Client.BaseUrl = new Uri("https://apiv2.bitcoinaverage.com/indices/global/ticker/short?crypto=BTC&fiat=USD");
CryptoAverage BTCAvg;
var request = new RestRequest();
response = await Client.ExecuteAsync(request);
BTCAvg = JsonConvert.DeserializeObject<CryptoAverage>(response.Content);
return Math.Round(BTCAvg.BTCUSD.Last, 2);
}
Usage
await GetBaselineAsync();
Yes.. You will have to let your async propagate through your code like a virus, or not use it at all.
Secondly, if ExecuteAsync is taking 2 seconds, its not because of .Net, there is not reason why the compiler would make your code pause for 2 seconds because of an await (even if you aren't using it correctly) Its the the call to the internet
If the library you use supports both sync and async methods(last usually with Async suffix) you should always use async ones. Async will create separate threads in your code in order to have better performance. And it will run concurrently when it needs. Async methods should almost in every case return Task or generic Task<>. If you want to call an asynchronous method in the synchronous method (in case of method signature doesn't allow you to use await keyword) you need to use .GetAwaiter().GetResult() upon a method which returns Task(in this case it will block the thread and won't run concurrently). Google around it worse it to spend time on it. Async await pattern was a huge step up of C# as language
EDIT: The solution was to change the declaration to;
public async Task<double> GetBaselineAsync()
And change ExecuteAsync to ExecuteTaskAsync. Full code;
public async Task<double> GetBaselineAsync()
{
var Client = new RestClient();
IRestResponse response;
Client.BaseUrl = new Uri("https://apiv2.bitcoinaverage.com/indices/global/ticker/short?crypto=BTC&fiat=USD");
CryptoAverage BTCAvg;
var request = new RestRequest();
response = await Client.ExecuteTaskAsync(request);
BTCAvg = JsonConvert.DeserializeObject<CryptoAverage>(response.Content);
return Math.Round(BTCAvg.BTCUSD.Last, 2);
}
I have one test app where code similar to the following is working but similar code appears to be failing in another app:
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var user = GetUser().GetAwaiter().GetResult();
}
private async Task<User> GetUser()
{
var client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
client.BaseAddress = new Uri(baseUrl);
client.Timeout = Timeout.InfiniteTimeSpan;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var request = new UserSearchRequest
{
DomainName = "my-corp-domain\my-user-id"
};
var response = await client.PostAsJsonAsync("api/v1/users/search", request);
var users = (await response.Content.ReadAsAsync<List<User>>());
return users.FirstOrDefault();
}
In the problem app, PostAsJsonAsync gets called but never returns. Any idea what the issue might be or how to debug?
Disclaimer: Executing an asynchronous method inside a synchronous method often leads to deadlocks and performance issues. A fully asynchronous call path, or even a fully synchronous path, is preferred. If you absolutely must block on async methods, read on.
I've had similar cases where HttpClient requests never return, and the answer was usually deadlock. #Eser provided a link to another question that describes the deadlock process well. To summarize it, the call to GetResult() has blocked the thread. At the same time, PostAsJsonAsync is waiting for that same thread to unlock so it can finish processing, thus creating deadlock.
An async/await example that causes a deadlock
One possibility is to use ConfigureAwait(false). This tells PostAsJsonAsync that it can finish processing on a different context, rather than waiting for the original context to unlock. The GetUser() function would then look like this:
private async Task<User> GetUser()
{
var client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
client.BaseAddress = new Uri(baseUrl);
client.Timeout = Timeout.InfiniteTimeSpan;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var request = new UserSearchRequest
{
DomainName = "my-corp-domain\my-user-id"
};
var response = await client.PostAsJsonAsync("api/v1/users/search", request).ConfigureAwait(false);
var users = await response.Content.ReadAsAsync<List<User>>().ConfigureAwait(false);
return users.FirstOrDefault();
}
Another solution that I have used in the past is to wrap the synchronous execution inside Task.Run. This pushes the start of the async method into a different context, so the two methods won't try to block on the same one. The AuthorizeCore method would then look like this:
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var user = Task.Run(() => GetUser()).GetAwaiter().GetResult();
}
For more information on this method, see Should I expose synchronous wrappers for asynchronous methods?
I emphasize again that neither is a perfect solution. By performing "sync over async" operations, you lose all benefits of asynchronous functionality while introducing a higher chance of deadlocks and potentially worse performance. I encourage using async all the way up whenever possible. When it's not, sticking with the "old" synchronous methods is not the worst option.
Hello I dont get the difference between the following two asnyc functions, could someone explain it to me? Both of them doesnt return IRestResponse, so I cant access StatusCode field. Do I have to cast here?
public async Task<IRestResponse> Post<T>(string Ressource, T ObjTOPost) where T : new()
{
return await Task.Factory.StartNew(() =>
{
var client = new RestClient("test.com");
var request = new RestRequest(Ressource, Method.POST);
var response = client.Execute(request);
return response;
});
}
And this:
public async Task<IRestResponse> Post<T>(string Ressource, T ObjTOPost) where T : new()
{
var client = new RestClient("test.com");
var request = new RestRequest(Ressource, Method.POST);
var response = await client.ExecuteTaskAsync<T>(request);
return response;
}
Both of them doesnt return IRestResponse, so I cant access StatusCode field.
They return a Task<IRestResponse>. You can get the interface by awaiting the task, e.g.
var task = Post(resource, objectToPost);
IRestResponse response = await task;
Or in one line (more common):
var response = await Post(resource, objectToPost);
Difference between these two async functions
The second example is far more straightforward. The first example spins up an additional task and passes its awaitable back to the caller, whereas the second example awaits the RestClient directly. I see no reason to use the structure in the first example.
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.