I have the following:
public override Task OnConnected() {
HandleConnectionAsync(Context).Wait();
return base.OnConnected();
}
In following the guidance around "don't block a hub method", I'm trying to await my HandleConnectionAsync call, but if I use async, I end up with the following:
public override async Task OnConnected() {
await HandleConnectionAsync(Context);
await base.OnConnected();
}
But then I'm not returning anything. What's the right way to do this?
But then I'm not returning anything. What's the right way to do this?
You don't need to return anything. async Task is the asynchronous equivalent of (synchronous) void. Task means there's no return value, so your code is already correct.
Put another way: async will construct the returned Task/Task<T> for you. So if your method does not have async (as in your first example), you need to return a task; but if your method does have async (as in your second example), then you don't.
If you await HandleConnectionAsync(Context); the method won´t return until that part finishes.
If you don´t want to "block" the hub method, just remote the Wait() part:
public override Task OnConnected()
{
HandleConnectionAsync(Context);
base.OnConnected();
}
That way the method will return immediately before HandleConnectionAsync finishes.
Related
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.
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.
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.
Consider the following method:
private async Task<Task<Response>> SendAsync(string data)
{
this.Tcs = new TaskCompletionSource<Response>();
await this.Stream.WriteAsync(...);
await this.Stream.FlushAsync();
return this.Tcs.Task;
}
I have an async method, which I expect to return Task<Response>. But since I want to return TaskCompletionSource<Response> (which gets set elsewhere, so I can't await it here), I have to actually return Task<Task<Response>> instead.
In the calling code, I have two ways of dealing with it while hiding this ugliness from the outside of the class. Assuming the response is not important and can be ignored, I can simply return a Task:
public Task GetAsync(string key)
{
return this.SendAsync("GET " + key);
}
On the other hand, if I want the response, I have to use this ugly await await to make it work:
public async Task<Response> GetAsync(string key)
{
return await await this.SendAsync("GET " + key);
}
Is there a better way of dealing with this, i.e. returning the Task<Response> from SendAsync() without exposing a Task<Task<Response>> outside the class, and at the same time not using the await await?
I'm not sure why you need to use a TaskCompletionSource inside an async method. Usually you either do the one or the other.
But if you must then forget returning the TaskCompletionSource.Task. Simply await the task like you do the rest of the async methods (WriteAsync and FlushAsync) and change the method to return Task<Response>:
private async Task<Response> SendAsync(string data)
{
this.Tcs = new TaskCompletionSource<Response>();
await this.Stream.WriteAsync(...);
await this.Stream.FlushAsync();
return await this.Tcs.Task;
}
That way the async method returns a task that gets completed when there's a Response so you only need to await SendAsync("...") once.
The answer by #i3arnon is a good solution, however another solution is to use the Unwrap extension method.
The TaskExtensions.Unwrap method is designed for converting a Task<Task<TResult>> into a Task<TResult> and can be used as follows:
public Task<Response> GetAsync(string key)
{
return this.SendAsync("GET " + key).Unwrap();
}
Any result, exception or cancellation will be propagated correctly to the resulting Task<TResult>.
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;