Async and await may be elided? - c#

I have this simple code :
public async Task<string> GetAsync()
{
var httpClient = new HttpClient();
return await httpClient.GetStringAsync("...");
}
However Resharper says :
This warning is gone when I use a variable :
public async Task<string> GetAsync()
{
var httpClient = new HttpClient();
var st = await httpClient.GetStringAsync("...");
return st;
}
I already know the danger when doing
using (var httpClient = new HttpClient())
return httpClient.GetStringAsync("...");
(Task will be canceled)
But that's not my case here since I'm using await ( and not using using).
Question:
Why does Resharper warn me?

Your method "can" be rewritten as follows:
public Task<string> GetAsync()
{
var httpClient = new HttpClient();
return httpClient.GetStringAsync("...");
}
thus avoiding the overhead of compiling an async method and then doing a costly control flow switch with await. The functionality is still the same. That's what R# is telling you about - you can omit the async/await and avoid an unnecessary overhead.
However, I put the "can" in quotes, as your code is smelly, because first of all, HttpClient is an IDisposable, so you should dispose of it after usage. Then the async/await will be necessary:
public async Task<string> GetAsync()
{
using(var httpClient = new HttpClient())
{
return await httpClient.GetStringAsync("...");
}
}
since this will be translated into an equivalent of
public async Task<string> GetAsync()
{
var httpClient = new HttpClient();
var result = await httpClient.GetStringAsync("...");
httpClient.Dispose();
return result;
}
This one you absolutely should fix. Secondly, a thing to consider is that creating HttpClients can silently destabilise your app, as HttpClients should be reused. See this blog post and this SE Stack Exchange post.

Related

Get & Post in ASP.NET Blazor

With the help of a few samples available on the internet, I am able to develop a ASP.NET Core Hosted Blazor Application.
But While Calling an api as follow
private async Task Refresh()
{
li.Clear();
li = await Http.GetJsonAsync<SampleModel[]>("/api/Sample/GetList");
StateHasChanged();
}
private async Task Save()
{
await Http.SendJsonAsync(HttpMethod.Post, "api/Sample/Add", obj);
await Refresh();
}
In the line below:
await Http.SendJsonAsync(HttpMethod.Post, "api/Sample/Add", obj);
How can I check status code of this HTTP call?
If there occurs any problem in API call than I want to display a message.
But when I do:
HttpResponseMessage resp = await Http.SendJsonAsync(HttpMethod.Post, "api/Sample/Add", obj);
Then it says:
can not cast void to HttpResponse Message
I am using below methods:
GetJsonAsync() // For HttpGet
SendJsonAsync() // For HttpPost And Put
DeleteAsync() // For HttpDelete
How can I verify the status code here ?
The thing is that you are using blazor's HttpClientJsonExtensions extensions,
Which internally usually calls
public static Task SendJsonAsync(this HttpClient httpClient, HttpMethod method, string requestUri, object content)
=> httpClient.SendJsonAsync<IgnoreResponse>(method, requestUri, content);
public static async Task<T> SendJsonAsync<T>(this HttpClient httpClient, HttpMethod method, string requestUri, object content)
{
var requestJson = JsonUtil.Serialize(content);
var response = await httpClient.SendAsync(new HttpRequestMessage(method, requestUri)
{
Content = new StringContent(requestJson, Encoding.UTF8, "application/json")
});
if (typeof(T) == typeof(IgnoreResponse))
{
return default;
}
else
{
var responseJson = await response.Content.ReadAsStringAsync();
return JsonUtil.Deserialize<T>(responseJson);
}
}
The GET requests use HttpContext.GetStringAsync internally
public static async Task<T> GetJsonAsync<T>(this HttpClient httpClient, string requestUri)
{
var responseJson = await httpClient.GetStringAsync(requestUri);
return JsonUtil.Deserialize<T>(responseJson);
}
while the normal HttpClient API still exists and can be used just as in those extension methods.
Those extension methods simply wrap the default HttpClient calls.
If you desire to have access to response status you would need to write your own wrappers that expose the desired functionality or just use the default API
Try this:
var response = await Http.SendJsonAsync <HttpResponseMessage>(HttpMethod.Post, "api/Sample/Add", obj);

Parallel Invoke with AwaitAsync in WebApi blocking

I've a webApi operation which executes 2 operations in || which internally invokes HttpClient sendAsync. If I apply debuggers and execute call, it works and returns. If I remove debuggers, both the async calls still work (checked in Fiddler) but caller of WebApi operation doesn't gets any response (using AdvanceRest chrome plugin). From the other threads, possibly I'm not using async/await correctly and related to ASP.NET synchronizationContext
//**WEB API Controller***
class SomeController
{
public HttpResponseMessage Get()
{
Client someClient = new Client();
aResponse = new aResponse();
bResponse = new bResponse();
Parallel.Invoke(
() => {aResponse = someClient.a()},
() => {bResponse = someClient.b()});
var response = {a=aResponse, b=bResponse};
return Response.Create(OK, response}
}
class SomeClient
{
AResponse a()
{
var clientResponse = ClientMgr.Execute("url");
return new AResponse {HttpClientResponse = clientResponse.Result}
}
BResponse b()
{
var clientResponse = ClientMgr.Execute("url");
return new BResponse {HttpClientResponse = clientResponse.Result}
}
}
//Utility CLASS
public class ClientMgr
{
public static async Task<HttpResponseMessage> Execute(string url)
{
request = new HttpRequestMessage();
//....request fill
HttpClient client = new HttpClient();
var response = await client.SendAsync(request);
client.dispose();
return response;
}
}
public class AResponse
{
HttpResponseMessage HttpClientResponse {get;set;}
// Some other properties....
}
Why does operation returns response when I'm using breakpoints but as I soon as I remove them, it doesn't returns response?
Your problem (other than the fact that the code you posted doesn't compile) is that while you debug, the async operations actually complete. When you don't debug, they don't, and it returns a Task<YourResponse>, not the actual result of the Task.
In order for this to work, mark your method as async and use Task.WhenAll to asynchronously wait on both tasks:
[HttpGet]
public async Task<HttpResponseMessage> GetAsync()
{
Client someClient = new Client();
var aTask = someClient.AAsync();
var bTask = someClient.BAsync();
await Task.WhenAll(aTask, bTask);
var response = { a = aTask.Result, b = bTask.Result };
return Response.Create(OK, response}
}
Side note - You don't need to use Paralle.Invoke when you have IO bound operations. Those are redundant threads which will be blocked waiting for the IO's completion.

Async call with HttpClient in PCL

I have a PCl in which I want to make a async call usingg HttpClient. I coded like this
public static async Task<string> GetRequest(string url)
{
var httpClient = new HttpClient() { MaxResponseContentBufferSize = int.MaxValue };
HttpResponseMessage response = await httpClient.GetAsync(url);
return response.Content.ReadAsStringAsync().Result;
}
But await is showing error "cannot await System.net.http.httpresponsemessage" like message.
If I use code like this than everything goes well but not in async way
public static string GetRequest(string url)
{
var httpClient = new HttpClient() { MaxResponseContentBufferSize = int.MaxValue };
HttpResponseMessage response = httpClient.GetAsync(url).Result;
return response.Content.ReadAsStringAsync().Result;
}
I just want that this method executes in async way.
This is the screen shot:
Follow the TAP guidelines, don't forget to call EnsureSuccessStatusCode, dispose your resources, and replace all Results with awaits:
public static async Task<string> GetRequestAsync(string url)
{
using (var httpClient = new HttpClient() { MaxResponseContentBufferSize = int.MaxValue })
{
HttpResponseMessage response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
If your code doesn't need to do anything else, HttpClient has a GetStringAsync method that does this for you:
public static async Task<string> GetRequestAsync(string url)
{
using (var httpClient = new HttpClient() { MaxResponseContentBufferSize = int.MaxValue })
return await httpClient.GetStringAsync(url);
}
If you share your HttpClient instances, this can simplify to:
private static readonly HttpClient httpClient =
new HttpClient() { MaxResponseContentBufferSize = int.MaxValue };
public static Task<string> GetRequestAsync(string url)
{
return httpClient.GetStringAsync(url);
}
If you are using a PCL platform that supports .net4 then I suspect you need to install the Microsoft.bcl.Async nuget.

Task Error when await in windows store application

Hej, I have a method:
public static async Task<myClassl> GetData()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http:sasa.com");
HttpResponseMessage response = await client.GetAsync("api/GetData");
myClassl data = await response.Content.ReadAsAsync<myClassl>();
return data ;
}
And when I write
myClassl t = await DataGetter.GetData();
I have:
The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.
You need to flag your method async where you write:
// Add async to your calling method
private async Task SomeOtherMethod()
{
myClassl t = await DataGetter.GetData();
Any method that uses await internally must be an async method itself.

Async task does not end

I'm trying to start async task (on .NET 4.5) which downloads content of web page, but somehow this task never finishes.
My PageDownloader class:
using System.Net;
using System.Text;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System;
namespace ParserConsole.WebClient
{
public class PageDownloader
{
private System.Net.Http.HttpClient _client;
public PageDownloader()
: this(Encoding.UTF8) { }
private Encoding _encoding;
public PageDownloader(Encoding encoding)
{
_encoding = encoding;
_client = new HttpClient() { Timeout = TimeSpan.FromSeconds(10)};
}
private HttpRequestMessage _request;
private HttpResponseMessage _response;
private string _responseString;
public string GetPageData(string link)
{
_request = new HttpRequestMessage(HttpMethod.Get, link);
_request.Headers.Add("User-Agent", "Chrome/21.0.1180.89");
_request.Headers.Add("Accept", "text/html");
GetResponse().Wait();
GetStringFromResponse().Wait();
return _responseString;
}
private async Task<HttpResponseMessage> GetResponse() {
return _response = await _client.GetAsync(_request.RequestUri);
}
private async Task<string> GetStringFromResponse() {
return _responseString = await _response.Content.ReadAsStringAsync();
}
}
}
I start downloading page by calling
new PageDownloader().GetPageData(url);
When I'm trying to debug the code, everything is fine till GetResponse().Wait(). But somehow GetResponse() task never finishes - breakpoint on the next line is never reached. I get no exceptions, application continues running. Any suggestions?
This is a standard deadlock condition you get when you start an async operation and then block on the returned task.
Here is a blog post discussion the topic.
Basically, the await call ensures that the continuation it wires up of the task will run in the context you were originally in (which is very helpful) but because you are calling Wait in that same context it's blocking, so the continuation never runs, and that continuation needs to run for the wait to end. Classic deadlock.
As for the fix; usually it means you just shouldn't be doing a blocking wait on the async operation; it's contrary to the design of the whole system. You should, "async all the way up". In this case it would mean that GetPageData should return a Task<string> rather than a string, and rather than waiting on the other operations that return a task you should await on them.
Now, having said that, there are ways of doing a blocking wait on the async operations without deadlocking. While it can be done, it honestly defeats the purpose of using async/await in the first place. The primary advantage of using that system is that the main context isn't blocked; when you block on it that entire advantage goes away, and you might as well just use blocking code all the way through. async/await is really more of an all-or-nothing paradigm.
Here is how I would structure that class:
public class PageDownloader
{
private System.Net.Http.HttpClient _client;
private Encoding _encoding;
public PageDownloader()
: this(Encoding.UTF8) { }
public PageDownloader(Encoding encoding)
{
_encoding = encoding;
_client = new HttpClient() { Timeout = TimeSpan.FromSeconds(10) };
}
public async Task<string> GetPageData(string link)
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, link);
request.Headers.Add("User-Agent", "Chrome/21.0.1180.89");
request.Headers.Add("Accept", "text/html");
HttpResponseMessage response = await _client.GetAsync(request.RequestUri);
return await response.Content.ReadAsStringAsync(); ;
}
}
Why not just do this if you want to have a function like that.
public string GetPageData(string link)
{
_request = new HttpRequestMessage(HttpMethod.Get, link);
_request.Headers.Add("User-Agent", "Chrome/21.0.1180.89");
_request.Headers.Add("Accept", "text/html");
var readTask = _client.GetStringAsync(link);
readTask.Wait();
return readTask.Result;
}
It would be better to return the Task all the way back and handle it with async/await in the calling code.
public Task<string> GetPageData(string link)
{
_request = new HttpRequestMessage(HttpMethod.Get, link);
_request.Headers.Add("User-Agent", "Chrome/21.0.1180.89");
_request.Headers.Add("Accept", "text/html");
return _client.GetStringAsync(link);
}

Categories

Resources