Passing an async Task as Action to method? - c#

I have a method used 100+ places that takes in an Action as parameter. I've now introduced a new method that requires awaits and had to be made async. What options do I have for passing that new async Task (previously void) action to the method?
// What I need (want) to do
MethodToBeCalled(DoSomething);
// Methods
void MethodToBeCalled(Action action)
{
// Do Something
}
async Task DoSomething()
{
await MethodX();
return Task.CompletedTask;
}
Tried using Func but didn't find a way to get it to work

You cannot; you would want a Func<Task> instead of Action, for example an overload:
await MethodToBeCalledAsync(DoSomething);
async Task MethodToBeCalledAsync(Func<Task> action)
{
// ...
await action();
// ...
}
Any attempt to do "sync over async" via .Wait(), .GetAwaiter().GetResult(), etc: is dangerous and defeats the entire point of the async Task method.

Related

Call chain for async/await ... await the awaitable or return the awaitable?

Given an async method:
public async Task<int> InnerAsync()
{
await Task.Delay(1000);
return 123;
}
And calling it through an intermediate method, should the intermediate method await the async method IntermediateA or merely return the Task IntermediateB?
public async Task<int> IntermediateA()
{
return await InnerAsync();
}
private Task<int> IntermediateB()
{
return InnerAsync();
}
As best I can tell with the debugger, both appear to work exactly the same, but it seems to me that IntermediateB should perform better by avoiding one more await entry in the state machine.
Is that right?
There is subtle differences in this two approaches. If you await failed task the exception will thrown in that method, but if you pass the task thought that method and then await it, the exception will be thrown in the consumer method. Another difference is more rare, in case of consumer awaiting the task and if it occurred with delay, the task can be finished at the await point and bypass the state machine.

How to await async method inside ExecutePostProcessingAsync

I use the code from http://arcware.net/upload-and-download-files-with-web-api-and-azure-blob-storage/ to upload blobs to azure. With the method ExecutePostProcessingAsync() I would like to call a method that resizes images and that uses async code.
The method i want to use it in looks(shrinked) like this:
public override Task ExecutePostProcessingAsync()
{
//some code
//I would like to await the image resizer method here before going any further
resizer.ScaleImage();
//Some more code here before returning
return base.ExecutePostProcessingAsync();
}
If i add async to the method like this: public override async Task ExecutePostProcessingAsync()
5+ errors will pop up with reference issues and also the error:
"is an async method that returns 'Task', a return keyword must not be followed by an object expression. Did you intend to return 'Task'?"
Questions:
Is there anyway to await an method inside this method? Any help or input appreciated, thanks!
The async keyword enables the use of the await keyword. With that said, the correct syntax is to not return the Task that represents the operation, but rather simply await it. Consider the following:
public override async Task ExecutePostProcessingAsync()
{
await resizer.ScaleImageAsync();
await base.ExecutePostProcessingAsync();
}
Notice how instead of trying to return the Task that represents the base execution, i.e.; base.ExecutePostProcessingAsync() we simply await instead.

Overriding an async method not adding async to method signature

I wonder why when I use visual studio to override RemoveLoginAsync()
it looks like this:
public override Task<IdentityResult> RemoveLoginAsync(string userId, UserLoginInfo login)
And not like:
public override async Task<IdentityResult> RemoveLoginAsync(string userId, UserLoginInfo login)
Shouldn't it be an awaitable Task using async?
Shouldn't it be an awaitable Task using async?
A Task is an awaitable. It implements the GetAwaiter pattern. Marking a method with async is simply a flag to the compiler which tells it to transform this method call to a state-machine. But, not all Task returning methods need to be marked as async. For example:
public Task DoSomethingAsync()
{
Console.WriteLine("Oh yay!");
return Task.CompletedTask;
}
In this example, I "faked" an asynchronous operation by returning Task.CompletedTask, I didn't actually need to await anything.
Another, more realistic example:
public Task SendWebRequestAsync()
{
var httpClient = new HttpClient();
return httpClient.GetAsync("http://www.google.com");
}
When I'm returning a Task rather than awaiting it, I'm deferring the awaiting on the task to the method higher up the callstack. This means that I don't allocate a state-machine and I'm also changing a bit the way the exception handling will work here. But, since this is a "tail async call", I don't have to await the operation and hence there's no need for the async modifier.

Is this the correct way to write asynchronous methods?

I'm currently trying to write async code and I have the feeling that my code is not too correct at all.
I have the following method:
public void Commit()
{
_context.SaveChangesToDatabase();
}
Don't judge the code here as this are only samples. Also, don't say that if I'm using Entity Framework, that they come packaged with Async methods already. I just want to understand the async concept here.
Let's say that the method SaveChangesToDatabase does takes seconds to complete.
Now, I don't want to wait for it so I create an async method:
public async Task CommitAsync()
{
await Task.Run(() => Commit());
}
Does this mean that if I have a method:
public void Method()
{
// Operation One:
CommitAsync();
// Operation Two.
}
Does this mean that my code on Operation two will be executed before CommitAsync() is even completed?
If not, please guide me in the right direction.
Update
Based on the remarks here that I'm ignoring my async method results, is this implementation better?
public Task<TaskResult> CommitAsync()
{
var task = new Task<TaskResult>(() =>
{
try { Commit(); }
catch (Exception ex)
{
return new TaskResult
{
Result = TaskExceutionResult.Failed,
Message = ex.Message
};
}
return new TaskResult { Result = TaskExceutionResult.Succeeded };
});
task.Start();
return task;
}
This does mean that I need to put the async modifier on the method that call this code so that I can await this which means continue with the current execution and return when this method has been completed.
Fire but don't forget
CommitAsync() returns a Task, but Method ignores the return value of CommitAsync completely -- so yes, the code will not wait but simply go on with what's after that. This is bad, because, if Commit() throws an exception, you will never see it. Ideally, every task should be waited on somewhere by someone, so you can at least see if it fails.
Let's say that you have no async alternative to SaveChangesToDatabase, but you'd like to use it in an async context anyway. You can use Task.Run to create a "fake-asynchronous" method, but this is not recommended (see below):
public Task CommitAsync() {
return Task.Run(() => Commit());
}
And then, assuming Method is doing something interesting with async (which the below code does not do since it's the only asynchronous operation in there):
public async Task MethodAsync() {
// Operation One:
await CommitAsync();
// Operation Two.
}
Assuming you do not want to wait, but you do want to do something if the task failed, you can use a separate method:
public void Method() {
// Operation One:
var _ = TryCommitAsync();
// Operation Two.
}
private async Task TryCommitAsync()
{
try
{
await CommitAsync();
}
catch (Exception ex)
{
Console.WriteLine(
"Committing failed in the background: {0}",
ex.Message
);
}
}
Getting back results
Let's suppose .Commit() does return something (like the number of records affected); a similar "fake-asynchronous" wrapper (again, not recommended - see below) would look like this:
public Task<int> CommitAsync() {
return Task.Run(() => Commit());
}
If you want this result, you can await the task immediately:
public async Task MethodAsync() {
// Operation One:
int recordsAffected = await CommitAsync();
// Operation Two.
}
Or, if you don't need it immediately, use await when you do:
public async Task MethodAsync() {
// Operation One:
Task<int> commit = CommitAsync();
// Operation Two.
// At this point I'd really like to know how many records were committed.
int recordsAffected = await commit;
}
Async: don't fake it
In general, you don't want to write wrappers like CommitAsync() because they mislead callers into thinking code will be asynchronous when it isn't really, which brings few benefits other than not blocking (which is still useful in UI code, but not as good as true asynchronous code which doesn't need to use worker threads for everything). In other words, you should use Task.Run in the invocation of a method, not as the implementation of a method.
So don't, as a habit, write wrappers like CommitAsync for every synchronous method you have -- instead you want to make a true CommitAsync that uses the async support of the underlying libraries/frameworks (SqlCommand.ExecuteReaderAsync(), etcetera.)
If you have no choice and must use Task.Run, then the appropriate usage would look more like:
// This method is in the UI layer.
public async Task MethodAsync() {
// Operation One:
// Commit() is a method in the DA layer.
await Task.Run(() => Commit());
// Operation Two.
}
Here
http://channel9.msdn.com/events/TechEd/NorthAmerica/2013/DEV-B318#fbid=
is a good explanation on how to work with async, and why you should avoid "async over sync", which is what you are doing now with
public Task CommitAsync() {
return Task.Run(() => Commit());
}
There are some scenarios where you can benefit from it, but if you are going to provide this as part of a library is NOT a good idea to make this.
If this code is ONLY and ONLY going to be used by your app, and you are sure what you are doing and dont have a wawy to call async methods inside your async method, just do it

Get result from async method

I have this method in my service:
public virtual async Task<User> FindByIdAsync(string userId)
{
this.ThrowIfDisposed();
if (userId == null)
{
throw new ArgumentNullException("userId");
}
return await this.repository.FindByIdAsync(userId);
}
and then in a view I have this code:
using (var service = new UserService(new CompanyService(), User.Identity.GetUserId()))
{
var user = service.FindByIdAsync(id);
}
but the user is the Task and not the User. I tried adding await to the service call, but I can't use await unless the current method is async.
How can I access the User class?
The best solution is to make the calling method async and then use await, as Bas Brekelmans pointed out.
When you make a method async, you should change the return type (if it is void, change it to Task; otherwise, change it from T to Task<T>) and add an Async suffix to the method name. If the return type cannot be Task because it's an event handler, then you can use async void instead.
If the calling method is a constructor, you can use one of these techniques from my blog. It the calling method is a property getter, you can use one of these techniques from my blog.
Using this in async methods without special thread-locked object is dangerous
If you cannot use await, use a code like following.
Task<User> task = TaskFindByIdAsync();
task.Wait(); //Blocks thread and waits until task is completed
User resultUser = task.Result;

Categories