Any issue with this C# method (.Net Framework 4.8) with not having await? I am using ReadAsStringAsync() with no await. Caller of RetrieveContent() method can't call it asynchronously. So, I need to avoid making it async method. This is a Windows Console app that can also be installed as a Windows Service- with an endpoint listening for requests. It is supposed to do Synchronous processing- one request at a time.
public string RetrieveContent()
{
return new HttpClient().GetAsync("https://www.google.com").Result.Content.ReadAsStringAsync().Result;
}
OR
public string RetrieveContent()
{
var response = new HttpClient().GetAsync("https://www.google.com").Result;
return response.Content.ReadAsStringAsync().Result;
}
Updates:
I can change like this. Thus, caller to this method doesn't need an information from Async method. Will this cause a dead-lock too?
public void RetrieveContent() //this is just logging content
{
var response = new HttpClient().GetAsync("https://www.google.com").Result;
if (response.StatusCode == HttpStatusCode.OK)
_logger.LogInformation($"content: {response.Content.ReadAsStringAsync().Result} "); //_logger is logging to local disk I/O
else
_logger.LogError($"HttpStatusCode: {response.StatusCode} ");
}
'''
Calling Result from synchronous code blocks is considered unsafe and may cause deadlocks because the task might depend on other incomplete tasks. Instead, you should usually be striving to make caller methods async as much as possible. In this specific case, however, it may be okay with a Task.Run wrapper.
See this question for more details: What's the "right way" to use HttpClient synchronously?
Related
I'm calling an async method (LoginAsync) for Authorization.
UserObject = clienAuthenticationService.LoginAsync(sUser).Result;
if (UserObject != null)
{
// Proceed for further code;
}
else
{
// Show Error message of failed authentication;
}
As this is third party service, I need output of LoginAsync before I go to next line (If block).
Current code is working fine for me and I know it waits until LoginAsync is executed.
However, I'm getting recommendation to Replace this use of 'Task.Result' with 'await'.
Question : I'm not sure if my case is relevant for await, since I need kind of Synchronous execution of async method. Can someone please confirm if recommendation given to me is irrelevant in my case or there is way to call async method synchronously with await ?
EDIT : After comments, I modified my code to add await instead of .Result. Still, unable to read response from async method. Below is new code
public static async Task<bool> CallJimService(LoginUserClass sUser)
{
var result = clientJIMServiceCall.LoginAsync(sUser).ConfigureAwait(false);
LoginUserClass loginUserDetails = await result;
if (loginUserDetails != null && loginUserDetails.UserProperties != null && loginUserDetails.UserProperties.LoggedIn)
{
return true;
}
else
{
return false;
}
}
public static Boolean ValidateUserCredentails(string pstrUserName, string pstrPassWord)
{
LoginUserClass sUser = new LoginUserClass();
sUser.UserName = pstrUserName;
sUser.Password = pstrPassWord;
return CallJimService(sUser).Result; // Here I want to avoid using .Result.
}
Also, I don't want to change ValidateUserCredentails() to async. How Can I get through this?
The LoginAsync method is marked async, and returns a Task. This method is expected to have an asynchronous implementation. You cannot execute this method synchronously, because this method does not have a synchronous implementation. If the class you are using would provide a synchronous implementation of the Login operation, they would have to expose a Login method.
There is no guarantee that calling this method asynchronously will result in an asynchronous operation. Asynchronous methods may return synchronously if the state needs them to. For instance, AsyncLogin may return synchronously if you already have logged in. However, unless doing something extremely specific, there must be at least one execution path in the method that requires some asynchronous operation.
Recommendation given to you is not irrelevant.
You should not block on an async operation, especially using Task.Result. Asynchronous operations does not involve multithreading, and awaiting on a Task.Result may provoke a deadlock of your application, because your thread will be waiting on the Result and will not be able to respond to the async operation signaling completion.
You'd rather await the LoginAsync method asynchronously, making your method async as well.
If you are forced to call the LoginAsync method from a synchronous context, the correct implementation will depend on what exactly you are trying to achieve and what the LoginAsync method does.
If you are able to use await (that is if you are in an async method already), then use await.
UserObject = await clienAuthenticationService.LoginAsync(sUser);
Using await helps the code run synchronous(that is it preserves flow of control).
I will try to explain async usage through the following example, which has asynchronous execution flow, but synchronous control flow -
Following code runs out of sync (asynchronous that is) -
// Authenticate the user, but don't wait here while authenticating.
// Async part could be - Checking database for user details. (Network IO operation)
var UserAuthTask = LoginAsync();
// Prepare a layout or something to show when authentication fails. Don't show yet.
// Again, don't wait while preparing.
// Async part could be - Reading a render template file. (File IO operation)
var AuthFailScreen = PrepareFailScreenAsync();
// Similar to failure screen.
var AuthSuccessScreen = PrepareSuccessScreenAsync();
Now, we use await to synchronize the flow to our liking -
var UserAuthResult = await UserAuthTask;
if (UserAuthResult.Success)
{
var SuccessScreen = await AuthSuccessScreen;
SuccessScreen.Show();
}
else
{
var FailScreen = await AuthFailScreen;
FailScreen.Show();
}
You could await each of the tasks before, like var UserAuthTask = await LoginAsync();, but then you would lose the benefit of doing multiple things which could've been done while authenticating.
I am not sure about exception handling, but mix and match of async and sync code will likely cause issues.
Please correct me if I am wrong at any point. Thanks.
I used quote marks around "right way" because I'm already well aware that the right way to use an asynchronous API is to simply let the asynchronous behavior propagate throughout the entire call chain. That's not an option here.
I'm dealing with a very large and complicated system designed specifically to do batch processing synchronously in a loop.
The reason why suddenly I'm using HttpClient is because prior to now all data for the batch processing was gathered from a SQL database, and now we're adding a Web API call to the mix.
Yes, we're calling a Web API in a synchronously executing loop. I know. Rewriting the whole thing to be async just isn't an option. This is actually what we want to do. (We're minimizing the number of API calls as much as possible)
I actually did try to propagate the async behavior up the call chain, but then I found myself 50 files deep in changes, still with hundreds of compiler errors to resolve, and lost all hope. I am defeated.
So then, back to the question, given Microsoft's recommendation to never use WebRequest for new development and to instead use HttpClient, which offers only an asynchronous API, what am I to do?
Here is some pseudo-code of what I'm doing...
foreach (var thingToProcess in thingsToProcess)
{
thingToProcess.ProcessStuff(); // This makes an API call
}
How do I implement ProcessStuff()?
My first implementation looked like this
public void ProcessStuff()
{
var apiResponse = myHttpClient // this is an instance of HttpClient
.GetAsync(someUrl)
.Result;
// do some stuff with the apiResponse
}
I was told however, that calling .Result in this manner can result in deadlocks when it's called from something like ASP.NET due to the synchronization context.
Guess what, this batch process will be kicked off from an ASP.NET controller. Yes, again, I know, this is silly. When it runs from ASP.NET it's only "batch processing" one item instead of the whole batch, but I digress, it still gets called from ASP.NET and thus I'm concerned about deadlocks.
So what's the "right way" to handle this?
Try the following:
var task = Task.Run(() => myHttpClient.GetAsync(someUrl));
task.Wait();
var response = task.Result;
Use it only when you cannot use an async method.
This method is completely deadlock free as mentioned on the MSDN blog:
ASP.Net–Do not use Task .Result in main context.
For anyone coming across this now, .NET 5.0 has added a synchronous Send method to HttpClient. https://github.com/dotnet/runtime/pull/34948
You can therefore use this instead of SendAsync. For example
public string GetValue()
{
var client = new HttpClient();
var webRequest = new HttpRequestMessage(HttpMethod.Post, "http://your-api.com")
{
Content = new StringContent("{ 'some': 'value' }", Encoding.UTF8, "application/json")
};
var response = client.Send(webRequest);
using var reader = new StreamReader(response.Content.ReadAsStream());
return reader.ReadToEnd();
}
This code is just a simplified example, it's not production ready.
You could also look at using Nito.AsyncEx, which is a nuget package. I've heard of issues with using Task.Run() and this this addresses that. Here's a link to the api docs:
http://dotnetapis.com/pkg/Nito.AsyncEx/4.0.1/net45/doc/Nito.AsyncEx.AsyncContext
And here's an example for using an async method in a console app:
https://blog.stephencleary.com/2012/02/async-console-programs.html
I've looked around and followed a few tutorials on how to set this up and I'm having no luck. I'm building a cross platform app using Xamarin. I have a portable class library to handle all my business logic and web service calls.
The issue I'm having is when I run the code within the method below it works without an issue however if I run it as shown below as a task it takes a long time. I believe its deadlocked but as I'm new to this I can't understand why. I want my Api calls to be in the PCL so I can share it between each platfrom.
public async Task<LoginResponse> Login(string userName, string password)
{
HttpClient client = new HttpClient();
string baseUrl = "http://someURLhere/";
client.BaseAddress = new Uri(baseUrl);
string authData = string.Format("/IOSLogin?Username={0}&Password={1}&languageSettingOnDevice={2}", userName, password, "en");
var uri = new Uri(string.Format("{0}{1}", baseUrl, authData));
var response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
LoginResponse jsonResponse = JsonConvert.DeserializeObject<LoginResponse>(content);
jsonResponse.loginSuccesfull = true;
return jsonResponse;
}
else
{
return new LoginResponse() { loginSuccesfull = false };
}
}
In the project for the ios version, on a button event I use this code to run the task shown above.
Core.Service.AtmisService service = new Core.Service.AtmisService();
LoginResponse loginTask = service.Login(userName.Text, password.Text).Result;
I thought that by setting it up this way when I use .Result at the end of call to the task it would execute this task and return the result. I have added breakpoints and it enters the login method and gets as far as this var response = await client.GetAsync(uri); and then it simply does nothing. Any ideas on what I am doing wrong. Thank you for any help.
Referencing this article Async/Await - Best Practices in Asynchronous Programming
“Async all the way” means that you shouldn’t mix synchronous and
asynchronous code without carefully considering the consequences. In
particular, it’s usually a bad idea to block on async code by calling
Task.Wait or Task.Result. This is an especially common problem for
programmers who are “dipping their toes” into asynchronous
programming, converting just a small part of their application and
wrapping it in a synchronous API so the rest of the application is
isolated from the changes. Unfortunately, they run into problems with
deadlocks. After answering many async-related questions on the MSDN
forums, Stack Overflow and e-mail, I can say this is by far the
most-asked question by async newcomers once they learn the basics:
“Why does my partially async code deadlock?”
Don’t mix blocking and async code. You should go Async all the way. Your deadlock is because the .Result is blocking.
you want to do...
LoginResponse loginTask = await service.Login(userName.Text, password.Text);
To summarize this second guideline, you should avoid mixing async and
blocking code. Mixed async and blocking code can cause deadlocks,
more-complex error handling and unexpected blocking of context
threads. The exception to this guideline is the Main method for
console applications, or—if you’re an advanced user—managing a
partially asynchronous codebase.
In Your case using a button EventHandler you would do something like this:
private async void myButtonItem_Clicked(object sender, EventArgs e)
{
Core.Service.AtmisService service = new Core.Service.AtmisService();
LoginResponse loginTask = await service.Login(userName.Text, password.Text).ConfigureAwait(false);
//The rest of the code in this method may run in a different thread than the one that invoked the method. If you have ui code after this then avoid using ConfigureAwait(false)
}
You can find more information on avoiding deadlocks here.
Lets say im within an ASP.NET application, WCF or web API, part of this applications job to is contact a 3rd party over the way. Id like to do this asynchronously or rather non blocking so that the thread pool doesnt get starved. However i dont want to change all my code in the service only the bit that makes the web call.
Here is some code i have written:
public string GetSomeData()
{
Task<string> stuff = CallApiAsync();
return stuff.result; //does this block here?
}
private async Task<string> CallApiasync()
{
using (var httpClient = new HttpClient())
{
string response = await httpClient.GetStringAsync(Util.EndPoint).ConfigureAwait(false);
return response;
}
}
I thought the idea was as follows but please correct any misconceptions.
The caller of CallApi can call the method and when it hits await there is a Task created which represents some work to be done asynchronously but that will take some time. At this point the thread reaches an await returns to the thread pool to do something else ie handle a different request. Once the Task completes the await line wakes up and the code continues from there as if it was synchronous.
If this is the case why do i need to return a Task from my apimethod. The caller seems to have to call stuff.Result which implies that the task may not have finished and calling result could block ? Note i don't want to make the calling method async too as then the method that calls that would need to be async etc etc.
What is the order of event here in my code?
One other question is why did i need to set configureAwait to false? otherwise everything hangs.
Id like to do this asynchronously or rather non blocking so that the thread pool doesnt get starved. However i dont want to change all my code in the service only the bit that makes the web call.
That's not possible. In order to be truly asynchronous, you must allow async to "grow" through the code as far as it needs to. What you're trying to do is block on an asynchronous call, which won't give you any benefit (you're freeing up a thread by using async, but then you're turning around and consuming a thread by using Result).
At this point the thread reaches an await returns to the thread pool to do something else ie handle a different request.
Not quite. When an async method hits an await, it returns an incomplete Task to its caller. If the caller, in turn, awaits that task, then it returns an incomplete Task to its caller, etc. When the ASP.NET runtime receives an incomplete Task from your action/service method/whatever, then it releases the thread to the thread pool.
So, you do have to go "async all the way" to see the real benefit of async.
I have an async intro on my blog if you want a more gentle introduction, as well as an MSDN article on async best practices (one of which is: async all the way). I also have a blog post that describes the deadlock you were seeing.
The compiler handles a lot of the magic behind the async pattern for you, but syntactically, you have to tell it what you want it to do by providing a method prototype that says "ok, this is an asynchronous operation that can be awaited."
For this to happen, your method must return a Task or Task<T>.
Any Task can be awaited.
You should be VERY careful when using .Result and .Wait(), as they can block in some very unexpected circumstances, because the runtime may decide to execute your method synchronously.
You should say:
await CallApiAsync();
or, to actually take advantage of it:
Task stuff = CallApiAsync();
//More code that can happen independetly of "stuff"
await stuff;
In order to do that, your GetSomeData() function must also be marked as async, but it doesn't have to, itself, return a Task.
Finished copy of a working async version of your code:
public async string GetSomeData()
{
Task stuff = CallApiAsync();
return await stuff;
}
private async Task<string> CallApiasync()
{
using (var httpClient = new HttpClient())
{
string response = await httpClient.GetStringAsync(Util.EndPoint).ConfigureAwait(false);
return response;
}
}
Honestly, if that's all the CallApiAsync function is ever going to do, you may as well inline it, though.
I am trying to conduct an HTTP call to another server from within an ASP.NET application run on IIS 8.5.
To get started, I took some hints from an article by Microsoft, Call a Web API From a .NET Client (C#).
I could easily see a pattern of how they make HTTP calls there; to show just one shortened example:
static async Task<Product> GetProductAsync(string path)
{
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
// retrieve response payload
... = await response.Content.ReadAsAsync<...>();
}
// do something with data
}
Easy enough, I thought, so I quickly wrote a similar method for my application (note that the ReadAsAsync extension method appears to require an additional library, so I chose one of the built-in, more abstract, but otherwise presumeably analogous methods):
private async Task<MyInfo> RetrieveMyInfoAsync(String url)
{
var response = await HttpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<MyInfo>(responseBody);
}
Unfortunately, calling this method will cause my application to hang. When debugging, it turns out that the await call to GetAsync never returns.
After searching around for a bit, I stumbled over a remotely similar issue, in whose comments section I found a very interesting suggestion by Mr. B:
Remove all the async stuff and make sure it works.
So I gave it a try:
private Task<MyInfo> RetrieveMyInfoAsync(String url)
{
return HttpClient.GetAsync(url).ContinueWith(response =>
{
response.Result.EnsureSuccessStatusCode();
return response.Result.Content.ReadAsStringAsync();
}).ContinueWith(str => JsonConvert.DeserializeObject<MyInfo>(str.Result.Result));
}
Somewhat surprisingly (to me), this works. GetAsync returns the expected response from the other server within less than a second.
Now, working with AngularJS at the same time, I am a bit disappointed by things like response.Result.Content and str.Result.Result. In AngularJS, I'd expect the above call to be simply something like:
$http.get(url).then(function (response) {
return response.data;
});
Even if we discount the automatic JSON deserialization that's happening in JavaScript, the AngularJS code is still easier as e.g. response is not wrapped into a promise or anything like that, nor will I end up with a structure like Task<Task<...>> when returning another promise from within the continuation function.
Therefore, I am not very happy with having to use this ContinuesWith syntax rather than the more readable async-await pattern, if the latter just worked.
What am I doing wrong in the async-await variant of my C# HTTP call?
So judging by the fact that ConfigureAwait(false) helped with your issue, please, read these from Stephen Cleary's blog:
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
The guy's pretty much an async expert (he wrote the Concurrency in C# Cookbook book), so whatever I can say he probably explains better. Basically you're blocking the ASP.NET thread somewhere, maybe not using await all the way but rather Wait, Result or GetResult(). You should be able to diagnoze the issue yourself using that blog.
What ConfigureAwait(false) does is it does not capture the current context, so the HTTP request gets performed (correctly) somewhere else than on the ASP.NET context, preventing a deadlock.
EDIT:
GetAwaiter().GetResult() is what's causing the issue, judging by your comment. If you changed that to await and the calling method to async you'd probably fix everything.
Since C# 7.0 and async Task Main() method support there's really no reason to block instead of using await in your application code, ever.