How to use await, async and Task in asynchronous programming - c#

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.

Related

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

Http Async Post in c#,Raspberry Pi ,data not post

The HTTP async method not working and the data never post when I run this in raspberry pi. The distance monitoring method still running but just the data doesn't post Codes
IUltrasonicRangerSensor sensor = DeviceFactory.Build.UltraSonicSensor(Pin.DigitalPin8);
private int distance = 200;
int count = 0;
ILed ledRed = DeviceFactory.Build.Led(Pin.DigitalPin5);
ILed ledGreen = DeviceFactory.Build.Led(Pin.DigitalPin6);
private void Sleep(int NoOfMs)
{
Task.Delay(NoOfMs).Wait();
}
private async void startDistanceMonitoring()
{
await Task.Delay(100);
int distanceRead = 200;
while (true)
{
Sleep(1000);
count++;
distanceRead = sensor.MeasureInCentimeters();
if (distanceRead < 200 && distanceRead > 0)
distance = distanceRead;
await sendtoapi();
}
}
private async Task sendtoapi()
{
using (var client = new HttpClient())
{
var values = new Dictionary<string, string>
{
{ "userName", "qwee" }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("https://google.com", content);
Sleep(10000);
var responseString = await response.Content.ReadAsStringAsync();
}
}
public void Run(IBackgroundTaskInstance taskInstance)
{
startDistanceMonitoring();
Sleep(300);
Debug.WriteLine("count = " + count + " ,distance=" + distance);
while (true)
{
if (distance >= 150)
{
Debug.WriteLine("EMPTY LOT");
Sleep(1000);
ledGreen.ChangeState(SensorStatus.On);
ledRed.ChangeState(SensorStatus.Off);
}
}
}
When you do async/await you basically want to make all(most) of your methods work in an async/await manner. At the moment your mixing async and non async method calls. This is called blocking in an async context and it should be avoided, not least of which because it can lead to deadlocks. I'd suggest you have a read though Async/Await - Best Practices in Asynchronous Programming
In general (and to simplify the problem somewhat) all your methods should have the signature
public async Task method()
{
}
and all your methods should be called:
await method();
Here are a couple of things your doing wrong
private async void startDistanceMonitoring()
Never use async void (these are for async event handlers only)
private void Sleep(int NoOfMs)
{
Task.Delay(NoOfMs).Wait();
}
this is blocking, this should be
private async Task Sleep(int NoOfMs)
{
await Task.Delay(NoOfMs);
}
When you call:
startDistanceMonitoring();
startDistanceMonitoring is an async method, yet your not awaiting it. So your program may very well terminate before it's completed. This should be:
await startDistanceMonitoring();
You do this incorrectly all over this block of code. Always call async methods with an await.
Your entry method isn't async, public void Run(IBackgroundTaskInstance taskInstance) should be public async Task Run(IBackgroundTaskInstance taskInstance)

Chaining async methods

I'm attempting to chain together a few async methods I've created and I believe there is some fundamental misunderstanding on my part about how this works
Here's a representation of my code:
public async Task<bool> LoadFoo()
{
return await Foo.ReadAsync("bar").ContinueWith((bar) =>
{
Foo.ReadAsync("baz").ContinueWith((baz) =>
{
Foo.ReadAsync("qux").ContinueWith((qux) =>
{
return true;
});
return true;
});
return true;
});
}
public void LoadEverything()
{
LoadFoo().ContinueWith((blah) =>
{
OtherLoadMethod();
});
}
Now I was expecting when LoadEverything() was called that all of the ReadAsync methods in LoadFoo ("bar", "baz" and "qux") would run and complete, and after they all completed then the .ContinueWith in LoadEverything would run so that OtherLoadMethod() wouldn't execute until the "bar", "baz" and "qux" ReadAsync methods finished.
What I am actually seeing is that LoadFoo gets called and then OtherLoadMethod starts to run before getting to the final completion in LoadFoo (the ContinueWith of the "qux" ReadAsync).
Can someone help clear up my misunderstanding here? Why wouldn't the execution of OtherLoadMethod wait until ReadAsync("qux") finishes and returns true?
Why wouldn't execution of OtherLoadMethod wait until ReadAsync("qux") finishes and returns true?
Because that's how await works. The continuations you register are just that: continuations. They are not executed synchronously in the current method. You are telling the framework that when the current task completes, the continuation should be executed. The Task object returned by ContinueWith() allows you to observe the completion if and when it happens. There would be no need to even return a Task object, if the ContinueWith() method blocked until the continuation was executed.
Likewise, the Task<bool> returned by your LoadFoo() method represents the overall completion of the method, including the await...ContinueWith() that you're returning. The method returns prior to completion of the continuation, and callers are expected to use the returned task if they need to wait for the continuation to complete.
All that said, I don't understand why you're using ContinueWith() in the first place. You obviously have access to await, which is the modern, idiomatic way to handle continuations. IMHO, your code should look something like this (it's not clear why you're returning Task<bool> instead of Task, since the return value is only ever true, but I assume you can figure that part out yourself):
public async Task<bool> LoadFoo()
{
await Foo.ReadAsync("bar");
await Foo.ReadAsync("baz");
await Foo.ReadAsync("qux");
return true;
}
public async Task LoadEverything()
{
await LoadFoo();
await OtherLoadMethod();
}
You can also use Unwrap:
public async Task<bool> LoadFoo()
{
await Foo.ReadAsync("bar")
.ContinueWith(_ => Foo.ReadAsync("baz")).Unwrap()
.ContinueWith(_ => Foo.ReadAsync("qux")).Unwrap();
return true;
}
public async Task LoadEverything()
{
await LoadFoo().ContinueWith(_ => OtherLoadMethod()).Unwrap();
}
Did not expect the top solution in search engine was fixing a misunderstanding but not actually the solution of the topic itself.
Chaining call can make great context focus when developing, async is good, and it is better if you know what u r doing.
Code:
//thanks for TheodorZoulias's review and input
public static class TaskHelper
{
public static async Task<TOutput> ThenAsync<TInput, TOutput>(
this Task<TInput> inputTask,
Func<TInput, Task<TOutput>> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
var output = await continuationFunction(input).ConfigureAwait(continueOnCapturedContext);
return output;
}
public static async Task<TOutput> ThenAsync<TInput, TOutput>(
this Task<TInput> inputTask,
Func<TInput, TOutput> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
var output = continuationFunction(input);
return output;
}
public static async Task<TInput> ThenAsync<TInput>(
this Task<TInput> inputTask,
Action<TInput> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
continuationFunction(input);
return input;
}
public static async Task<TInput> ThenAsync<TInput>(
this Task<TInput> inputTask,
Func<TInput, Task> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
await continuationFunction(input).ConfigureAwait(continueOnCapturedContext);
return input;
}
public static async Task<TOutput> ThenAsync<TOutput>(
this Task inputTask,
Func<Task<TOutput>> continuationFunction,
bool continueOnCapturedContext= true)
{
await inputTask.ConfigureAwait(continueOnCapturedContext);
var output = await continuationFunction().ConfigureAwait(continueOnCapturedContext);
return output;
}
public static async Task ThenAsync(
this Task inputTask,
Action continuationFunction,
bool continueOnCapturedContext= true)
{
await inputTask.ConfigureAwait(continueOnCapturedContext);
continuationFunction();
}
}

Using async/await with Dispatcher.BeginInvoke()

I have a method with some code that does an await operation:
public async Task DoSomething()
{
var x = await ...;
}
I need that code to run on the Dispatcher thread. Now, Dispatcher.BeginInvoke() is awaitable, but I can't mark the lambda as async in order to run the await from inside it, like this:
public async Task DoSomething()
{
App.Current.Dispatcher.BeginInvoke(async () =>
{
var x = await ...;
}
);
}
On the inner async, I get the error:
Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type.
How can I work with async from within Dispatcher.BeginInvoke()?
The other answer may have introduced an obscure bug. This code:
public async Task DoSomething()
{
App.Current.Dispatcher.Invoke(async () =>
{
var x = await ...;
});
}
uses the Dispatcher.Invoke(Action callback) override form of Dispatcher.Invoke, which accepts an async void lambda in this particular case. This may lead to quite unexpected behavior, as it usually happens with async void methods.
You are probably looking for something like this:
public async Task<int> DoSomethingWithUIAsync()
{
await Task.Delay(100);
this.Title = "Hello!";
return 42;
}
public async Task DoSomething()
{
var x = await Application.Current.Dispatcher.Invoke<Task<int>>(
DoSomethingWithUIAsync);
Debug.Print(x.ToString()); // prints 42
}
In this case, Dispatch.Invoke<Task<int>> accepts a Func<Task<int>> argument and returns the corresponding Task<int> which is awaitable. If you don't need to return anything from DoSomethingWithUIAsync, simply use Task instead of Task<int>.
Alternatively, use one of Dispatcher.InvokeAsync methods.
I think you can use below code and then depends of place use it with async and await or without to fire and forget:
public static Task FromUiThreadAsync(Action action)
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
Dispatcher disp = GetUiDispatcher();
disp.Invoke(DispatcherPriority.Background, new Action(() =>
{
try
{
action();
tcs.SetResult(true);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}));
return tcs.Task;
}
Use Dispatcher.Invoke()
public async Task DoSomething()
{
App.Current.Dispatcher.Invoke(async () =>
{
var x = await ...;
});
}
(Edit: This answer is wrong, but I'll fix it soon)
Declare this
public async Task DoSomethingInUIThreadAsync(Func<Task> p)
{
await Application.Current.Dispatcher.Invoke(p);
}
Use like this
string someVar = "XXX";
DoSomethingInUIThreadAsync(()=>{
await Task.Run(()=> {
Thread.Sleep(10000);
Button1.Text = someVar;
});
});
DoSomethingInUIThreadAsync receives a delegate that returns a Task, Application.Current.Dispatcher.Invoke accepts a Func callback that can be awaited.

Categories

Resources