Task Error when await in windows store application - c#

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.

Related

How to use await, async and Task in asynchronous programming

This is the first time I'm writing any asynchronous code. I am getting a compile error that says:
Cannot implicitly convert type void to int
while the function is returning an int.
public class Function
{
IAmazonS3 s3client = new AmazonS3Client(RegionEndpoint.USEast1);
public async Task<int> ListS3ObjectsAsync(string bucketName, IAmazonS3 client)
{
ListObjectsRequest request = new ListObjectsRequest();
request.BucketName = bucketName;
ListObjectsResponse response = await client.ListObjectsAsync(request);
do
{
if (response.IsTruncated)
request.Marker = response.NextMarker;
else
request = null;
} while (request != null);
var len = response.S3Objects.Count;
return len;
}
public void FunctionHandler(S3Event evnt, ILambdaContext context)
{
// Here I'm getting the compile error
int x = ListS3ObjectsAsync(evnt.Records?[0].S3.Bucket.Name, s3client).Wait();
}
}
Visual Studio screenshot:
Because ListS3ObjectsAsync method returns a Task<int>, which is an asynchronous representation of getting an int, so in order to get the result, you either need to await the task like this:
int x = await ListS3ObjectsAsync
But that will require you to make the FunctionHandler async aswell.
Or you can call .Result on the task like this
var task = ListS3ObjectsAsync
int x = task.Result
Note that this is a blocking operation and mixing async and non async code is bad practise.
.Wait method only waits for the task to complete, but does not return the Result
You shouldn't block on async code, so the best solution is to use await instead of Wait:
public void FunctionHandler(S3Event evnt, ILambdaContext context)
{
int x = await ListS3ObjectsAsync(evnt.Records?[0].S3.Bucket.Name, s3client);
}
The compiler will then tell you the next part of the solution: FunctionHandler must be made async and its return type changed to Task, i.e.:
public async Task FunctionHandlerAsync(S3Event evnt, ILambdaContext context)
{
int x = await ListS3ObjectsAsync(evnt.Records?[0].S3.Bucket.Name, s3client);
}
The "growth" of async like this is normal.

Async / Await Pattern. How to pass a await-able method to another method

In my application I need to call a method before all the API request. If a specific condition met then I need to execute set of statements in that method.
In order to generalize this I created a helper class something like this.
public class CertificateValidator {
readonly IDependencyService _serviceLocator;
public CertificateValidator(IDependencyService serviceLocator) {
_serviceLocator = serviceLocator;
}
public async Task <T> TryExecuteWithCertificateValidationAsync <T> (Task <T> operation) {
var service = _serviceLocator.Get <IDeviceService> ();
if (service.CertificateValidationRequired()) {
// My Code.
}
T actualResult = await operation;
return actualResult;
}
}
And In my viewmodel I have done something like this.
public CertificateValidator ValidateCertificate => new CertificateValidator(_serviceLocator);
var response = await ValidateCertificate
.TryExecuteWithCertificateValidationAsync(MyMethodAsync());
private async Task<RequestResult<Response>> MyMethodAsync()
{
// Some code
}
But when I implement like this the execution flow is
First MyMethodAsync() will be called.
And when it reaches the await method it the executes the
TryExecuteWithCertificateValidationAsync method and runs the remaining code there.
And then when it reaches T actualResult = await operation; return
actualResult; the control go back to MyMethodAsync() - await statement.
And my doubt here is,
I need to execute the TryExecuteWithCertificateValidationAsync completely and then followed by MyMethodAsync.
In short as I said early, I need to execute set of code before I call all my API calls. How I can achieve something similar using async an await.
Rather than passing a Task pass a function:
public async Task<T> TryExecuteWithCertificateValidationAsync<T>(Func<Task<T>> operation)
{
var service = _serviceLocator.Get<IDeviceService>();
if (service.CertificateValidationRequired())
{
// My Code.
}
T actualResult = await operation();
return actualResult;
}
var response = await ValidateCertificate
.TryExecuteWithCertificateValidationAsync(MyMethodAsync);
Update as per comment
If the method requires arguments, the types need to be prepended as additional generic arguments to Func:
private async Task<RequestResult<Response>> MyMethodAsync(int i)
{
// Some code
}
public async Task<T> TryExecuteWithCertificateValidationAsync<T>(Func<int, Task<T>> operation) // Add int as second generic argument
{
T actualResult = await operation(1); // Can now be called with an integer
return actualResult;
}

ASP.NET Web API async controller method and deadlock

Please help me to understand why this code cause a deadlock?
I have an asp.net web api application and I tried to make some controller method asynchronous.
[HttpPost]
[Authentication]
public async Task<SomeDTO> PostSomething([FromBody] SomeDTO someDTO)
{
return await _service.DoSomething(someDTO);
}
this is how looks the called service method:
public async Task<SomeDTO> DoSomething(SomeDTO someDTO)
{
...
var someTask = Task.Run(() =>
{
var entity = new SomeEntity(someDTO);
return _repository.Create(entity);
});
...
var result = await someTask;
...
}
And there is some globalhandler, that prints a response to a console.
public class AppGlobalHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var resp = base.SendAsync(request, cancellationToken);
Debug.WriteLine($"Response:{request.RequestUri}{Environment.NewLine}{resp?.ConfigureAwait(false).GetAwaiter().GetResult()?.Content?.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult()}");
return resp;
}
}
Looks like ConfigureAwait(false).GetAwaiter().GetResult()
blocks the caller thread, but I supposed that ConfigureAwait(false) should avoid this, isn't it?
ConfigureAwait(false) would not help you here because it must be all the way down in the call stack (see more here) not at place where you wait synchronously, i.e. it depends rather on the implementation of base.SendAsync. If it acquired a lock on current thread it's too late to do something about it. It is also not recommended in ASP.net pipeline to continue responding on other thread after all (see discussion here and post here).
Finally it is always a highly risky idea to wait synchronously in async context.
If you need to read content, why not doing it like that:
public class AppGlobalHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var resp = await base.SendAsync(request, cancellationToken);
var content = resp?.Content != null
? (await resp.Content.ReadAsStringAsync())
: string.Empty;
Debug.WriteLine($"Response:{request.RequestUri}{Environment.NewLine}{content}");
return resp;
}
}
I think you overlook async keyword in Task.Run() method.
public async Task<SomeDTO> DoSomething(SomeDTO someDTO)
{
var someTask = Task.Run( async () => //simply add this for async run
{
var entity = new SomeEntity(someDTO);
return _repository.Create(entity);
});
var result = await someTask;
}

Async and await may be elided?

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.

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);

Categories

Resources