Passing an *Awaitable* Anonymous Function as a Parameter - c#

Code first. This is what I'm trying to do. I'm close, but I think I just need to fix the way I've defined my parameter in the UpdateButton method.
private async void UpdateButton(Action<bool> post)
{
if (!await post())
ErrorBox.Text = "Error posting message.";
}
private void PostToTwitter()
{
UpdateButton(async () => await new TwitterAction().Post("Hello, world!"));
}
private void PostToFacebook()
{
UpdateButton(async () => await new FacebookAction().Post("Hello, world!"));
}
Unfortunately, the !await post() doesn't work because, "Type 'void' is not awaitable." So the question is, how do I define my parameter in this method to support an awaitable parameter?
Here's how the TwitterAction().Post() is defined...
public virtual async Task<bool> Post(string messageId){...}

private async void UpdateButton(Func<Task<bool>> post)
{
if (!await post())
ErrorBox.Text = "Error posting message.";
}
--EDIT--
UpdateButton(()=>Post("ss"));
private async void UpdateButton(Func<Task<bool>> post)
{
if (!await post())
this.Text = "Error posting message.";
}
public virtual async Task<bool> Post(string messageId)
{
return await Task.Factory.StartNew(() => true);
}

You need to pass this as a Task<bool>, not an Action<bool>.
This provides something that's "awaitable".
I believe this will work, given your current code:
private async Task UpdateButtonAsync(Task<bool> post)
{
if (!await post)
ErrorBox.Text = "Error posting message.";
}
// This will work if Post returns Task<bool> in the current API...
private void PostToTwitter()
{
UpdateButtonAsync(new TwitterAction().Post("Hello, world!"));
}
If you do not want to start the Task<bool> immediately, and need to keep it as passing a lambda, there is still no reason for the lambda to be async. In that case, you could use:
private async Task UpdateButtonAsync(Func<Task<bool>> post)
{
if (!await post())
ErrorBox.Text = "Error posting message.";
}
// This will work if Post returns Task<bool> in the current API...
private void PostToTwitter()
{
UpdateButtonAsync(() => new TwitterAction().Post("Hello, world!"));
}
This causes the lambda to return the Task<bool> (no async/await required, as Post already returns Task<bool>), and the update method to run the lambda.
Personally, I find the first option (above) simpler, and suspect it is more likely what you want. Given your API already returns Task<T>, you can just pass that around and await it directly.

Related

cannot convert void to an object in asp.netcore

I have written an api end point in asp.net core and getting error cannot convert void to an object
I am getting error in line.What I understand is SendEmailReminder method returns void but how do I handle that in the controller. If I remove await the error goes but then I get the warning that the method would be executed synchronously. Could somebody help
return Ok(await _counterpartyProposalService.SendEmailReminder());
Controller
[HttpPost]
[Route("sendEmailReminder")]
public async Task<IActionResult> SendEmailReminders()
{
return Ok(await _counterpartyProposalService.SendEmailReminder());
}
public async Task SendEmailReminder()
{
var stepCode = StepCodes.BasicInformation;
var command = _commandResolver(stepCode, null);
await command.ExecuteEmailReminder();
}
You can refactor your code in the following manner, assuming that your HTTP call is not returning any content. By doing this, you will return HTTP 204.
[HttpPost]
[Route("sendEmailReminder")]
public async Task<IActionResult> SendEmailReminders()
{
await _counterpartyProposalService.SendEmailReminder();
NoContent();
}
public async Task SendEmailReminder()
{
var stepCode = StepCodes.BasicInformation;
var command = _commandResolver(stepCode, null);
await command.ExecuteEmailReminder();
}
This is the signature of Ok method:
public virtual OkObjectResult Ok([ActionResultObjectValue] object value)
The reason you do not get the error, when you remove the await keyword is because Ok is taking the Task object as input.

Function as parameter in async method

I call a method containing a function:
public void DoMagicStuff(Func<T> anyfunction) {
// do lots of magic stuff
}
This works:
public void DoNonAsyncStuff() {
DoMagicStuff(()=> {
AnotherFunction();
}
}
While this does not:
public async Task<CustomClass> DoAsynStuff() {
DoMagicStuff(()=> {
return await DoSomethingDifferent();
}
}
"The await operator can only be used in async functions"
How do I make this work for async methods?
If you intend to pass asynchronous delegates to DoMagicStuff, then you need to overload that with an asynchronous version:
public void DoMagicStuff(Func<T> anyfunction)
{
// do lots of magic stuff
T t = anyfunction();
}
public async Task DoMagicStuff(Func<Task> asyncfunction)
{
// do lots of magic stuff
T t = await asyncfunction();
}
This allows you to call await for the asyncfunction.
Any common logic can always be refactored into another method.
With regard to your question, await can only be used in a function that has been declared async, which your lambda hasn't.
It should be like this:
public async Task<CustomClass> DoAsynStuff()
{
await DoMagicStuff(async () =>
{
return await DoSomethingDifferent();
});
}
And in fact, because DoSomethingDifferent already returns a Task, the lambda is superfluous:
public async Task<CustomClass> DoAsynStuff()
{
await DoMagicStuff(DoSomethingDifferent);
}

await operator not stopping continuation of other method calls

I have three methods that look like below
private async Task checkPhotoLibraryAccess()
{
PHPhotoLibrary.RequestAuthorization(status =>
{
switch (status)
{
//stuff here
}
}
}
private async Task checkDeviceAuthorizationStatus()
{
var status = AVCaptureDevice.GetAuthorizationStatus(AVMediaType.Video);
switch (status)
{
//stuff here
}
}
private void displayAppBar()
{
AppBar.IsVisible = true;
}
I would like the execution of the first two methods to complete before calling the third. I have researched the issue and have found ways of doing so using the await operator and Wait() method. However my implementations has not worked. Here is my code below.
Attempt 1
private async void MyMethod()
{
await checkPhotoLibraryAccess();
await checkDeviceAuthorizationStatus();
displayAppBar(); //THIS IS CALLED BEFORE COMPLETION OF TWO ABOVE
}
Attempt 2
private async void MyMethod()
{
checkPhotoLibraryAccess().Wait();
checkDeviceAuthorizationStatus().Wait();
displayAppBar(); //SAME ISSUE
}
Any suggestions on how to get this to work?
To get a third method to be executed based on the completion of two other methods you use the WhenAll method of the Task class.
var t1 = CheckPhotoLibraryAccess();
var t2 = CheckDeviceAuthorization();
await Task.WhenAll(t1, t2).ContinueWith(t => DisplayAppBar());
#Yacoub Massad and #SLaks reminded me that in order for await to work on a method call, the method needs to contain an await operator.
So I changed my PhotoLibraryAccess method to contain an await operator and placed its method call right before the DisplayAppBar call.
private async Task checkPhotoLibraryAccess()
{
var status = await PHPhotoLibrary.RequestAuthorizationAsync();
//stuff here
}
And then ...
private async void MyMethod()
{
checkDeviceAuthorizationStatus(); //Removed async Task stuff
await checkPhotoLibraryAccess();
displayButtons(); //IT WORKS
}

c# Can a "task method" also be an "async" method?

I'm trying to get the hand of the new async CTP stuff and I'm probably confusing myself here..
I can have this "task method", with no problem:
public static Task<String> LongTaskAAsync() {
return Task.Run(() => {
return("AAA");
});
}
But what if I need the task to execute another task, can I mark it as "async" and use "await"? I tried this:
public async static Task<String> LongTaskAAsync() {
await Task.Delay(2000);
return Task.Run(() => {
return("AAA");
});
}
But then mysteriously get this compiler error: Since this is an async method, the return expression must be of type 'string' rather than Task<string>
What am I missing here?
You may want to read my async/await intro post.
Return values from async methods are wrapped in a Task<TResult>. Likewise, await unwraps those return values:
public static async Task<String> LongTaskAAsync() {
await Task.Delay(2000);
return await Task.Run(() => {
return("AAA");
});
}
The reasoning behind this is described in my Async "Why Do the Keywords Work That Way" Unofficial FAQ.
P.S. You can also use Task.FromResult for simple tests like this.
Edit: If you want to create and return the Task object itself, then the method should not be async. One somewhat common pattern is to have a public non-async method that calls the async portion only if necessary.
For example, some kind of asynchronous cache - if the object is in the cache, then return it immediately; otherwise, asynchronously create it, add it to the cache, and return it (this is example code - not thread-safe):
public static Task<MyClass> GetAsync(int key)
{
if (cache.Contains(key))
return Task.FromResult(cache[key]);
return CreateAndAddAsync(key);
}
private static async Task<MyClass> CreateAndAddAsync(int key)
{
var result = await CreateAsync(key);
cache.Add(key, result);
return result;
}
Can a “task method” also be an “async” method?
Yes it can be, by simply changing the method signature to public async static Task<Task<String>> LongTaskAAsync() since that is, what it will return.
If you use the async keyword, the runtime will wrap the type you return into a task, to enable asynchronousness. Say if you return a string, the runtime will wrap that into a Task<string>. int will go Task<int> and Task<string> will go Task<Task<string>>. See this console app to clearify:
public class Program
{
public static void Main(string[] args)
{
// start the main procedure asynchron
Task.Run(() => DoIt()).Wait();
}
// for async support since the static main method can't be async
public static async void DoIt()
{
Program p = new Program();
// use the methods
string s = await p.GetString();
int i = await p.GetInt();
Task<string> tsk = await p.GetTaskOfString();
// just to prove the task works:
// C# 5
string resultFromReturnedTask = await tsk;
// C# 4
string resultFromReturnedTask2 = tsk.Result;
}
public async Task<string> GetString()
{
return "string";
}
public async Task<int> GetInt()
{
return 6;
}
public async Task<Task<string>> GetTaskOfString()
{
return Task.Run(() => "string");
}
}

How to work with HttpTaskAsyncHandler

public class FooHandler : HttpTaskAsyncHandler
{
public override async Task ProcessRequestAsync(HttpContext context)
{
return await new AdRequest().ProcessRequest();
// getting error here. "Return type of async type is void"
}
}
public class FooRequest
{
public async Task<String> ProcessRequest()
{
//return await "foo"; obviously nothing to wait here
}
}
I want to make a async handler and just want to return a string. How can i get this working? and is there a concise reference to work with Async methods and Tasks?
A few points:
You can await any Task, not just ones returned from async methods.
async methods wrap their returned value into a Task<TResult>; if there is no return value, they wrap the return itself into a Task.
There are several convenience methods available, e.g., Task.FromResult, if you don't need the overhead of an async method.
Only make a method async if you have to use await in it. If you don't need to make the method async, don't.
You may find my async/await intro helpful.
public class FooHandler : HttpTaskAsyncHandler
{
public override Task ProcessRequestAsync(HttpContext context)
{
return new AdRequest().ProcessRequest();
}
}
public class AdRequest
{
public Task<String> ProcessRequest()
{
return Task.FromResult("foo");
}
}
You shouldn't "return" the Task, the compiler will do it implicitly as it is an async function:
public override async Task ProcessRequestAsync(HttpContext context)
{
await new AdRequest().ProcessRequest();
}
public async Task<String> ProcessRequest()
{
return "foo";
}
This is another way, closer to what you were trying to do: (without async/await)
public override Task ProcessRequestAsync(HttpContext context)
{
return new AdRequest().ProcessRequest();
}
public Task<String> ProcessRequest()
{
return Task.Return("foo");
}
A general reference to async is here
Essentially adding the async modifier to a method, makes it return a Task implicitly. If you return an int, it will turn it into a Task<int>. await does the opposite, turning a Task<int> into an int.
This is a truly asynchronous method:
public Task<string> ProcessRequest()
{
var textFile = File.OpenText("file.txt");
var readTask = textFile.ReadToEndAsync();
readTask.ContinueWith(previousTask => textFile.Dispose());
return readTask;
}
If you run this method with a large file or a file on a slow drive the execution will return to caller long before file reading ends. In Stephen Cleary's example the caller will get back control only when the result ("foo") is finished calculating.
Dispose must be in ContinueWith because the method execution will return to caller before file reading is complete so file can't be closed in ProcessRequest method.
One can of course start their own task.
public Task<string> ProcessRequest(CancellationToken cancellationToken)
{
var readTask = Task.Run(() =>
{
using (var textFile = File.OpenText("file.txt"))
{
var text = textFile.ReadToEnd();
cancellationToken.ThrowIfCancellationRequested();
var processedText = text.Replace("foo", "bar");
return processedText;
}
});
return readTask;
}
It is a good practice to have a CancellationToken and periodically check if cancellation was requested to allow long running operarions to be cancelled.
Edit 1
As #Stephen Cleary highlighted the first sample and this result in approximately or maybe exactly the same CIL:
public async Task<string> ProcessRequest()
{
using (var textFile = File.OpenText("file.txt"))
{
var s = await textFile.ReadToEndAsync();
return s;
}
}
Basically the compiler will transform the code following await textFile.ReadToEndAsync() into ContinueWith.
Each syntax has its benefits, my preference is that 1-2 lines (i.e. dispose and log) go into ContinueWith, more complex continuation uses await.

Categories