Yes, I know there are other questions to cover what this warning means and how to solve it, however, I have a question about best practices regarding async programming.
I have a service layer which handles data transfer between the data layer and the presentation layer. This service contains several methods which query the database, and return the result.
I have been trying to use async programming wherever possible. An example:
public async Task<SiteTemplateResource[]> GetResources(int siteTemplateId, string extension)
{
return await Database.FindBy<SiteTemplateResource>(str => str.SiteTemplateId == siteTemplateId && str.HashedFile.EndsWith(extension)).ToArrayAsync();
}
My problem with this is, I'm not actually awaiting anything, other than to the ToArrayAsync call, which I don't really need.
Should I go ahead and use async/await for this? And how would I for example await anything for this function:
public async Task<int> SiteTemplateBySiteIdAsync(int siteId)
{
return Database.First<SiteSiteTemplate>(sst => sst.SiteId == siteId).SiteTemplateId;
}
I don't await anything in that function, but I also don't need to call ToArrayAsync, so how do I avoid the warning "method lacks 'await' operator" in above case?
Thanks in advance.
If you have nothing to await in a method that needs to be async (for whatever reason), you can use Task.FromResult, which can be awaited:
public async Task<int> SiteTemplateBySiteIdAsync(int siteId)
{
return await Task.FromResult(Database.First<SiteSiteTemplate>(sst => sst.SiteId == siteId).SiteTemplateId);
}
If you don't need the async method, you can simply more the async Task<int> and replace it for int.
Asynchornous api does not necessary need async\await keywords. First you should ask yourself if anything you call inside your method use IO and have asynchronous version of that IO api. In your case you try to access database, that is IO, your library has asynchronous version (ToArrayAsync), so all makes sense. Now check if you do anything else after calling that asynchronous api. If yes - use async\await. If not - just return the result back to the caller:
public Task<SiteTemplateResource[]> GetResources(int siteTemplateId, string extension)
{
return Database.FindBy<SiteTemplateResource>(str => str.SiteTemplateId == siteTemplateId && str.HashedFile.EndsWith(extension)).ToArrayAsync();
}
In the second case you also try to access database, but you think that there is no async api to do that. Most likely that is not true, because if you have ToArrayAsync - it's very likely all database access methods have async version and so you should have FirstAsync. Then your method becomes:
public async Task<int> SiteTemplateBySiteIdAsync(int siteId)
{
var result = await Database.FirstAsync<SiteSiteTemplate>(sst => sst.SiteId == siteId);
return result.SiteTemplateId;
}
Here you do something after calling FirstAsync, so you need to use async\await keywords.
async/await are needed only if you want to process the results of an already asynchronous operation in the method itself. They don't make the method or the call asynchronous. If you don't need to process the Task result, you can just return it:
public Task<SiteTemplateResource[]> GetResources(int siteTemplateId, string extension)
{
return Database.FindBy<SiteTemplateResource>(str =>
str.SiteTemplateId == siteTemplateId
&& str.HashedFile.EndsWith(extension))
.ToArrayAsync();
}
or, using an expression bodied method
public Task<SiteTemplateResource[]> GetResources(int siteTemplateId, string extension)=>
Database.FindBy<SiteTemplateResource>(str =>
str.SiteTemplateId == siteTemplateId
&& str.HashedFile.EndsWith(extension))
.ToArrayAsync();
You can avoid async/await in the second case as well and still keep it asynchronous, if you use Where,Select and FirstAsync:
public Task<int> SiteTemplateBySiteIdAsync(int siteId)=>
Database.Where(sst => sst.SiteId == siteId)
.Select(it=>it.SiteTemplateId)
.FirstAsync();
}
This has the added advantage of returning only the ID from the database. If you didn't use Select, the provider would have to read the entire object
Maybe you can change your code like bellow:
public int SiteTemplateBySiteIdAsync(int siteId)
{
return Database.First<SiteSiteTemplate>(sst => sst.SiteId == siteId).SiteTemplateId;
}
Have a nice day!
Related
Is there any scenario where writing method like this:
public async Task<SomeResult> DoSomethingAsync()
{
// Some synchronous code might or might not be here... //
return await DoAnotherThingAsync();
}
instead of this:
public Task<SomeResult> DoSomethingAsync()
{
// Some synchronous code might or might not be here... //
return DoAnotherThingAsync();
}
would make sense?
Why use return await construct when you can directly return Task<T> from the inner DoAnotherThingAsync() invocation?
I see code with return await in so many places, I think I might have missed something. But as far as I understand, not using async/await keywords in this case and directly returning the Task would be functionally equivalent. Why add additional overhead of additional await layer?
There is one sneaky case when return in normal method and return await in async method behave differently: when combined with using (or, more generally, any return await in a try block).
Consider these two versions of a method:
Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return foo.DoAnotherThingAsync();
}
}
async Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return await foo.DoAnotherThingAsync();
}
}
The first method will Dispose() the Foo object as soon as the DoAnotherThingAsync() method returns, which is likely long before it actually completes. This means the first version is probably buggy (because Foo is disposed too soon), while the second version will work fine.
If you don't need async (i.e., you can return the Task directly), then don't use async.
There are some situations where return await is useful, like if you have two asynchronous operations to do:
var intermediate = await FirstAsync();
return await SecondAwait(intermediate);
For more on async performance, see Stephen Toub's MSDN article and video on the topic.
Update: I've written a blog post that goes into much more detail.
The only reason you'd want to do it is if there is some other await in the earlier code, or if you're in some way manipulating the result before returning it. Another way in which that might be happening is through a try/catch that changes how exceptions are handled. If you aren't doing any of that then you're right, there's no reason to add the overhead of making the method async.
Another case you may need to await the result is this one:
async Task<IFoo> GetIFooAsync()
{
return await GetFooAsync();
}
async Task<Foo> GetFooAsync()
{
var foo = await CreateFooAsync();
await foo.InitializeAsync();
return foo;
}
In this case, GetIFooAsync() must await the result of GetFooAsync because the type of T is different between the two methods and Task<Foo> is not directly assignable to Task<IFoo>. But if you await the result, it just becomes Foo which is directly assignable to IFoo. Then the async method just repackages the result inside Task<IFoo> and away you go.
If you won't use return await you could ruin your stack trace while debugging or when it's printed in the logs on exceptions.
When you return the task, the method fulfilled its purpose and it's out of the call stack.
When you use return await you're leaving it in the call stack.
For example:
Call stack when using await:
A awaiting the task from B => B awaiting the task from C
Call stack when not using await:
A awaiting the task from C, which B has returned.
Making the otherwise simple "thunk" method async creates an async state machine in memory whereas the non-async one doesn't. While that can often point folks at using the non-async version because it's more efficient (which is true) it also means that in the event of a hang, you have no evidence that that method is involved in the "return/continuation stack" which sometimes makes it more difficult to understand the hang.
So yes, when perf isn't critical (and it usually isn't) I'll throw async on all these thunk methods so that I have the async state machine to help me diagnose hangs later, and also to help ensure that if those thunk methods ever evolve over time, they'll be sure to return faulted tasks instead of throw.
This also confuses me and I feel that the previous answers overlooked your actual question:
Why use return await construct when you can directly return Task from the inner DoAnotherThingAsync() invocation?
Well sometimes you actually want a Task<SomeType>, but most time you actually want an instance of SomeType, that is, the result from the task.
From your code:
async Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return await foo.DoAnotherThingAsync();
}
}
A person unfamiliar with the syntax (me, for example) might think that this method should return a Task<SomeResult>, but since it is marked with async, it means that its actual return type is SomeResult.
If you just use return foo.DoAnotherThingAsync(), you'd be returning a Task, which wouldn't compile. The correct way is to return the result of the task, so the return await.
Another reason for why you may want to return await: The await syntax lets you avoid hitting a mismatch between Task<T> and ValueTask<T> types. For example, the code below works even though SubTask method returns Task<T> but its caller returns ValueTask<T>.
async Task<T> SubTask()
{
...
}
async ValueTask<T> DoSomething()
{
await UnimportantTask();
return await SubTask();
}
If you skip await on the DoSomething() line, you'll get a compiler error CS0029:
Cannot implicitly convert type 'System.Threading.Tasks.Task<BlaBla>' to 'System.Threading.Tasks.ValueTask<BlaBla>'.
You'll get CS0030 too, if you try to explicitly typecast it.
This is .NET Framework, by the way. I can totally foresee a comment saying "that's fixed in .NET hypothetical_version", I haven't tested it. :)
Another problem with non-await method is sometimes you cannot implicitly cast the return type, especially with Task<IEnumerable<T>>:
async Task<List<string>> GetListAsync(string foo) => new();
// This method works
async Task<IEnumerable<string>> GetMyList() => await GetListAsync("myFoo");
// This won't work
Task<IEnumerable<string>> GetMyListNoAsync() => GetListAsync("myFoo");
The error:
Cannot implicitly convert type 'System.Threading.Tasks.Task<System.Collections.Generic.List>' to 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable>'
Imagine this is a method performing a DB query and returning a result, which in case of null is replaced with a default value (Null object pattern).
public ResultObj Get()
{
var result = dbContext.GetSomeResult();
return result ?? ResultObj.NullValue;
}
Imagine this DB query is a long-running process, so I would use async/await to execute this process in a separate thread. Suppose that the dbContext.GetSomeResultAsync() method is available.
How can be this method converted in an asynchronous one so that I can write something like this?
var resultTask = GetAsync();
var otherResultTask = GetSomethingElseAsync();
Task.WaitAll(resultTask, otherResultTask);
var myResult = resultTask.Result;
var myOtherResult = otherResultTask.Result;
I tried this solution.
public async Task<ResultObj> GetAsync()
{
var result = await dbContext.GetSomeResultAsync();
return result ?? ResultObj.NullValue;
}
First, I'm wondering why this code compiles: why can I return ResultObj when Task<ResultObj> is expected?
Second, this code predictably results in a deadlock, as clearly explained by the great number of resources about async deadlocks anti-patterns. The deadlock can be prevented by using .ConfigureAwait(false) method after the async call. Is this the right way to go? Are there any hidden drawbacks in this case? Is it a general rule?
I also tried this.
public async Task<ResultObj> GetAsync()
{
return await Task.Run(() => {
var result = dbContext.GetSomeResult();
return result ?? ResultObj.NullValue;
});
}
This results in a deadlock, too. This time I cannot even figure out why.
Edit: possible solution
Finally, after having read this, I found a solution to my problem.
My generic query wrapper method is like this.
public async Task<ResultObj> GetAsync()
{
var result = await dbContext.GetSomeResultAsync();
return result ?? ResultObj.NullValue;
}
On calling method, I use this pattern.
public async Task<CollectedResults> CollectAsync()
{
var resultTask = GetAsync();
var otherResultTask = GetSomethingElseAsync();
//here both queries are being executed.
//...in the while, optionally, here some other synchronous actions
//then, await results
var result = await resultTask;
var otherResult = await otherResultTask;
//here process collected results and return
return new CollectedResults(...);
}
It is worth mentioning that the above code, wrapped in a domain class, is called by a Controller action. In order for this to work I had to make async the methods all the way up, until Controller action, which now appears as follows.
public async Task<CollectedResults> Get()
{
return await resultsCollector.CollectAsync();
}
This way, deadlock doesn't happen anymore and execution time greatly improves with respect to the synchronous version.
I don't know if this is the canonical way of executing parallel queries. But it works and I don't see particular pitfalls in the code.
First of all, regarding :
so I would use async/await to execute this process in a separate thread.
There is no new thread created when we use async and await
Secondly:
why can I return ResultObj when Task is expected?
the Task<TResult> as return type of method tells that it returns a Task of type TResult but we need to return object of type that TResult back from it so the method can be awaited and when using Task<TResult> as reutrn type we should be using async and await to do the work.
Lastly:
this code predictably results in a deadlock
You are using async keyword with method signatures and also await the next async method call being done from within the method. So apparently it looks like the code in first example you have posted shouldn't be deadlocked, if the method GetSomeResultAsync you are consuming is really a async method and is properly implemented.
I suggest to study more about the async await before getting in to it, following is a good article to start with:
https://blog.stephencleary.com/2012/02/async-and-await.html
This question already has answers here:
How does Task<int> become an int?
(2 answers)
Closed 7 years ago.
I've got code very similar to this (I've simplified the code a bit to demonstrate the essence of the behavior I'm trying to figure out).
public async System.Threading.Tasks.Task<bool> IsNumberOdd(int numToTest)
{
if (numToTest % 2 == 0)
{
return false;
}
else
{
return true;
}
}
If I leave off the async keyword, I get a complaint about not being able to cast a bool to a Task<bool>. I'm assuming there's some syntactic sugar involved here. Looking at the IL (I'm not super familiar with IL) it seems as if the async keyword is causing the task to be run and then the return value is the result of the task. Am I understanding this correctly?
By the way, if this is a dupe or if there's some blog posting that discusses this, feel free to point me to it and close this up. I'm not trying to pad my rep; I'm trying to understand what's going on with this code.
EDIT:
For all those who were asking "why is this method async?"--because I was trying to build a small and simple code example to demonstrate the question. I should have also added an example of the calling code but I was trying to keep the code as small and simple as I could.
I'm assuming there's some syntactic sugar involved here
Not exactly "syntactic sugar". The compiler is generating a state-machine as the method was marked as async. That is why you can return a Task<bool> without explicitly creating a Task for the return value.
If I leave off the async keyword, I get a complaint about not being
able to cast a bool to a Task<bool>.
The async modifier is what triggers the compiler to create the state machine. If you remove it, you'll need to create the Task yourself. If for any reason you want to create a Task<T> but you're actually running synchronously, Task.FromResult is your friend.
I see no reason why this method is marked async.
it seems as if the async keyword is causing the task to be run and then the return value is the result of the task
Correct.
There is nothing in this method that would benefit from it being async. However:
If I leave off the async keyword, I get a complaint about not being able to cast a bool to a Task<bool>
Would be happening in the caller. Without seeing that code one can only comment generally that you can either:
Change the caller to not assume it is getting a waitable return.
Change the function to return bool, but on the caller use Task.FromResult(IsNumberOdd(value)).
It's not about the async. Its about the Task.
your returning a bool and the return value of your function is Task
public Task<bool> DoSomething()
{
return false;
}
will also not compile.
if your not doing any thing asynchronous you shouldn't return a Task.
If you need to run something asynchronously , here are a few options which i hope will make the usage of async/await clearer.
public class Sample
{
public async void RunSample()
{
// return a task. later obtain a result if some fashion
Task<bool> task = DoSomethingAsync();
bool res1 = task.Result;
// await a task which is created for you by re-wrapping the result.
bool res2 = await AwaitSomethingAsync();
// await a task which is created for you by rewrapping the result due to await.
bool res3 = await DoSomethingAsync2();
// await a task.
bool res4 = await DoSomethingAsync();
}
public async Task<bool> DoSomethingAsync2()
{
return false;
}
public Task<bool> DoSomethingAsync()
{
return Task<bool>.Run(() => { return false; });
}
public async Task<bool> AwaitSomethingAsync()
{
bool res = await Task<bool>.Run(() => { return false; });
return res; // re-wraps it in a Task
}
}
In my data access layer I'm attempting to create methods with return types of Task.
I cannot get the return type from the entity framework to return Task<List<MYtype>>
public static Task<List<ILeaf>> GetLeafs(int doorID)
{
using (var db = new StorefrontSystemEntities())
{
return db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
};
}
Is the only way to make this run correctly is to format the code like so:
public async static Task<List<ILeaf>> GetLeafs(int doorID)
{
return await Task.Run(() =>
{
using (var db = new StorefrontSystemEntities())
{
return db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
};
});
}
The reason I was asking is because I would like to give the option to run async, or am I not understanding this correctly?
If I can just return a Task then on the calling end I could give the option to await if I wanted to run async, but if i wanted to run synchronously I would just call the method as normal.
If I'm returning a Task do I always have to include the async keyword in the method signature?
Am I thinking about this the wrong way? If I've got a return type of Task then the method has the option of being called async or synchronously?
But, if I have async and Task in the method signature then the method runs async no matter what?
Thanks!
So to answer the literal question asked, you can just do this:
public static Task<List<ILeaf>> GetLeafs(int doorID)
{
return Task.Run(() =>
{
using (var db = new StorefrontSystemEntities())
{
return db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
};
});
}
That said, note that this isn't a particularly useful method. The idea of leveraging asynchronous programming is that you don't want to have a thread pool thread sitting there doing nothing but waiting on this IO operation. Ideally you'd leverage IO that is inherently asynchronous in nature; a method that itself naturally returns a task.
You aren't really providing value to consumers of your code by wrapping the blocking IO in a call to Task.Run. If they need that operation to be run in a background thread they can do so on their own, and then they'll know more precisely that it's not a naively asynchronous operation.
See Should I expose asynchronous wrappers for synchronous methods? for more information on the subject.
public static async Task<List<ILeaf>> GetLeafs(int doorID)
{
using (var db = new StorefrontSystemEntities())
{
var result = db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
return await Task.FromResult(result);
}
}
When working on data APIs which use async rest calls (I am using RestSharp.Portable), what is the best way to handle return values? Since async function can only return a Task or Task ... but the caller has no way to getting back to the return value ... how would the API return data back to the caller? Global properties?
From what I have read so far, it appears that callback functions are the only way to interact with Response Data?
Take the following method for example; previously I was not using async Rest library and was able to return a value but after converting it to use RestSharp.Portable, I dont see a way to return the value:
public async Task<EntityResourceDescriptor> GetEntityDescriptor(string entityType)
{
TaskCompletionSource<EntityResourceDescriptor> tcs = new TaskCompletionSource<EntityResourceDescriptor>();
var req = new RestRequest("/qcbin/rest/domains/{domain}/projects/{project}/customization/entities/{entityType}");
AddDomainAndProject(req);
req.AddParameter("entityType", entityType, ParameterType.UrlSegment);
client.ExecuteAsync<EntityResourceDescriptor>(req, (res) =>
{
if (res.ResponseStatus == ResponseStatus.Error)
{
tcs.TrySetException(res.ErrorException);
}
else
{
tcs.SetResult(res.Data);
}
}
);
return tcs.Task;
}
Here all I can do is return Task but the caller still has no way to get to the response data or am I missing something obvious? Can the caller subscribe to an event which gets fired at Task.Completed etc.?
I am very fuzzy on this async concept. Are there any examples of writing Portable data APIs?
I think you'll really need to take a step back and read about how to use the async and await keywords. Among other things, you'll need to understand some of the compiler magic that happens behind the scenes when coding async methods.
Here is a good place to start: Asynchronous Programming with Async and Await.
More to your question, the Return Types and Parameters section has this to say:
You specify Task<TResult> as the return type if the method contains a Return (Visual Basic) or return (C#) statement that specifies an operand of type TResult.
It then gives the following code example:
// Signature specifies Task<TResult>
async Task<int> TaskOfTResult_MethodAsync()
{
int hours;
// . . .
// Return statement specifies an integer result.
return hours;
}
Notice how despite the method return type of Task<int>, the return statement simply returns an int, not a Task<int>. That's basically because there is some compiler magic going on that makes this legal only in async methods.
Without wanting to get into all the details, you should also know that the caller of the async method is normally expected to do so using the await keyword, which knows how to deal with the Task or Task<TResult> return values and automatically unwraps the actual expected return value for you in a transparent manner (more compiler magic behind the scenes).
So for the above example, here is one way to call it:
int intValue = await TaskOfTResult_MethodAsync(); // Task<int> is automatically unwrapped to an int by the await keyword when the async method completes.
Or, if you wish to start the async method, perform some other work in the meantime, and then wait for the async method to complete, this can be done like this:
Task<int> t = TaskOfTResult_MethodAsync();
// perform other work here
int intValue = await t; // wait for TaskOfTResult_MethodAsync to complete before continuing.
Hopefully this gives you a general idea of how to pass values back from an async method.
For your specific example, I am not familiar with RestSharp (never used it). But from what little I read, I think you'll want to use client.ExecuteTaskAsync<T>(request) instead of client.ExecuteAsync<T>(request, callback) to better fit in the async-await model.
I'm thinking your method would instead look something like this:
public async Task<EntityResourceDescriptor> GetEntityDescriptor(string entityType)
{
var req = new RestRequest("/qcbin/rest/domains/{domain}/projects/{project}/customization/entities/{entityType}");
AddDomainAndProject(req);
req.AddParameter("entityType", entityType, ParameterType.UrlSegment);
var res = await client.ExecuteTaskAsync<EntityResourceDescriptor>(req);
if (res.ResponseStatus == ResponseStatus.Error)
{
throw new Exception("rethrowing", res.ErrorException);
}
else
{
return res.Data;
}
}
Your calling code would then look like this:
EntityResourceDescriptor erd = await GetEntityDescriptor("entityType");
I hope you manage to get this working. But again, make sure to read the documentation about the async-await style of programming. It's very neat once you wrap your head around the compiler magic that is done for you. But it's so easy to get lost if you don't take the time to really understand how it works.