Should I worry about This async method lacks 'await' operators and will run synchronously warning
The async keyword is merely an implementation detail of a method; it isn’t part of the method signature. If a particular method implementation or override has nothing to await, then just omit the async keyword and return a completed task using Task.FromResult<TResult>:
public Task<string> Foo() // public async Task<string> Foo()
{ // {
Baz(); // Baz();
return Task.FromResult("Hello"); // return "Hello";
} // }
If your method return type is Task instead of Task<TResult>, then return Task.CompletedTask:
public Task Bar() // public async Task Bar()
{ // {
Baz(); // Baz();
return Task.CompletedTask; //
} // }
Note: Task.CompletedTask was added in .NET Framework 4.6. If you’re targeting .NET Framework 4.5.2 or earlier, then you can instead return a completed task of any type and value. Task.FromResult(0)
seems to be a popular choice:
public Task Bar() // public async Task Bar()
{ // {
Baz(); // Baz();
return Task.FromResult(0); //
} // }
Dealing with Exceptions
An exception thrown by a non-async method propagates immediately up the call stack, but an exception thrown by an async method is stored in the returned Task object and propagates only when the Task is awaited. This makes a big difference if someone calls your method and then does something else before awaiting the Task:
Task<string> task = Foo(); // If Foo is async and throws an exception,
DoSomethingElse(); // then this line will be executed,
string result = await task; // and the exception will be rethrown here.
If you need to preserve this behavior for a non-async method, then wrap the entire method within a try...catch statement. Pass any unhandled exception to Task.FromException, and return the result:
public Task<string> Foo() // public async Task<string> Foo()
{ // {
try //
{ //
Baz(); // might throw // Baz();
return Task.FromResult("Hello"); // return "Hello";
} //
catch (Exception ex) //
{ //
return Task.FromException<string>(ex); //
} //
} // }
public Task Bar() // public async Task Bar()
{ // {
try //
{ //
Baz(); // might throw // Baz();
return Task.CompletedTask; //
} //
catch (Exception ex) //
{ //
return Task.FromException(ex); //
} //
} // }
The generic argument to Task.FromException must match the return type of the method.
Reducing Boilerplate Code
You can use the following helper class to automatically call Task.FromResult and Task.FromException for you:
public static class TaskHelper
{
public static Task FromResultOf(Action action)
{
try
{
action();
return Task.CompletedTask;
}
catch (Exception ex)
{
return Task.FromException(ex);
}
}
public static Task<T> FromResultOf<T>(Func<T> func)
{
try
{
return Task.FromResult(func());
}
catch (Exception ex)
{
return Task.FromException<T>(ex);
}
}
}
Sample usage:
public Task<string> Foo() // public async Task<string> Foo()
{ // {
return TaskHelper.FromResultOf( //
() => //
{ //
Baz(); // Baz();
return "Hello"; // return "Hello";
}); //
} // }
public Task Bar() // public async Task Bar()
{ // {
return TaskHelper.FromResultOf( //
() => //
{ //
Baz(); // Baz();
}); //
} // }
This async method lacks 'await' operators and will run synchronously
The async
keyword, by itself, doesn't really do much. Remove it from your code and your code will act exactly the same.
What does async
do?
- It changes what's valid inside of the method, specifically it allows you to use the
await
keyword - In turn, it means that the body of the method will be transformed, based on the
await
s that are present in the body of the method. - And if the method returns a value, the method is also transformed to wrap the return value in a
Task
.
However, if you a) Don't have any await
s in your method body and b) are void
returning, then nothing special will be achieved. The compiler warning does try to be clear about this - an async
method without any await
s just plain doesn't make sense. await
s are the more important part of this feature.
c# async await strange warning CS1998: This async method lacks 'await' operators
Your await
is within a lambda expression, which is another function entirely to your StartSearchAsync
method.
In fact you should not be passing an async
delegate to List<T>.ForEach
, as that converts the delegate to async void
, which is undesirable because the calling method cannot wait for the delegates to complete.
A better option would be to use Enumerable.Select
, in combination with Task.WhenAll
:
public async Task<List<T1>> StartSearchAsync()
{
....other code
var tasks = searchRequests.Select(SinglePageSearch);
var results = await Task.WhenAll(tasks);
foreach (result in results) products.AddRange(result);
return products;
}
Using this approach, Task.WhenAll
enumerates the Task
s generated by Select
, and creates another Task
that completes when each SinglePageSearch
has completed.
Now StartSearchAsync
can await
their completion.
And if products
is simply an empty list being used to amalgamate the results, you can simplify further:
public async Task<List<T1>> StartSearchAsync()
{
....other code
var results = await Task.WhenAll(searchRequests.Select(SinglePageSearch));
return results.SelectMany(x => x).ToList();
}
Async method lacks await operators warning when the await is in a function passed to an async lambda expresion
First, I recommend using Polly. It's widely used, extensively tested, and has native support for asynchronous as well as synchronous usage.
But if you want to keep using your own, you can add a synchronous equivalent:
public async Task RetryAsync(Func<Task> _action, int _ms = 1000, int _counter = 3);
public void Retry(Action _action, int _ms = 1000, int _counter = 3);
which can be called as such:
Retry(() => {
_newID = myDBFunction();
}, 300);
If you want to always put synchronous code on a thread pool, you can add an overload for that, to:
public async Task RetryAsync(Func<Task> _action, int _ms = 1000, int _counter = 3);
public async Task RetryAsync(Action _action, int _ms = 1000, int _counter = 3) =>
await RetryAsync(() => Task.Run(_action), _ms, _counter);
which can be called as such:
await RetryAsync(() => {
_newID = myDBFunction();
}, 300);
Usage of Task.WaitAll without any 'await' operators causing warning CS1998 This async method lacks 'await' operators and will run synchronously
will it really make any part of the code to run synchronously, just because the lack of an 'await' operator?
Yes. The Main
method will run synchronously. This won't really matter because it's the Main
method, but if you want to asynchronously wait for the tasks to complete, use await Task.WhenAll
instead of Task.WaitAll
. The asynchronous approach has an additional benefit in that it doesn't wrap exceptions in AggregateException
.
On a side note, use await
instead of ContinueWith
.
In ViewComponent: This async method lacks 'await' operators and will run synchronously
You don't use any asynchronous call in the method (there is no await
), hence the warning. ViewComponent
has 2 methods InvokeAsync
and Invoke
. You should use the synchonous version (Invoke
) of the ViewComponent
when there is no asynchrounous calls in the implementation:
public class GenericReportViewComponent : ViewComponent
{
public IViewComponentResult Invoke(GenericReportViewModel model)
{
return View(model);
}
}
Here's the documentation section about synchronous work: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-2.2#perform-synchronous-work
How do I supress the warning about This async method lacks 'await' operators and will run synchronously when the interface I implement is async?
Ideally you do not want to remove the async
keyword, and instead use the asynchronous counterparts of your underlying APIs, so that your code can be non-blocking whenever it is not CPU-bound. For example, as mentioned in comments, you can use connection.OpenAsync()
instead of connection.Open()
:
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context,
CancellationToken cancellationToken)
{
using (SqlConnection connection =
new SqlConnection(_configuration.GetConnectionString("PwdrsConnectionRoot")))
{
try
{
await connection.OpenAsync();
}
catch (SqlException)
{
return HealthCheckResult.Healthy();
}
}
return HealthCheckResult.Healthy();
}
However, if you really want to just remove the async
keyword and leave your implementation alone, then you'll need to explicitly wrap the return values and exceptions with Task
:
private HealthCheckResult CheckHealthImpl(HealthCheckContext context,
CancellationToken cancellationToken)
{
using (SqlConnection connection =
new SqlConnection(_configuration.GetConnectionString("PwdrsConnectionRoot")))
{
try
{
connection.Open();
}
catch (SqlException)
{
return HealthCheckResult.Healthy();
}
}
return HealthCheckResult.Healthy();
}
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context,
CancellationToken cancellationToken = default)
{
try
{
return Task.FromResult(CheckHealthImpl(context, cancellationToken));
}
catch (Exception e)
{
return Task.FromException(e);
}
}
That should properly implement the interface, and preserve the equivalent behavior to your prior async
function.
Suppress warning CS1998: This async method lacks 'await'
I've got an interface with some async functions.
Methods returning Task
, I believe. async
is an implementation detail, so it can't be applied to interface methods.
Some of the classes that implements the interface does not have anything to await, and some might just throw.
In these cases, you can take advantage of the fact that async
is an implementation detail.
If you have nothing to await
, then you can just return Task.FromResult
:
public Task<int> Success() // note: no "async"
{
... // non-awaiting code
int result = ...;
return Task.FromResult(result);
}
In the case of throwing NotImplementedException
, the procedure is a bit more wordy:
public Task<int> Fail() // note: no "async"
{
var tcs = new TaskCompletionSource<int>();
tcs.SetException(new NotImplementedException());
return tcs.Task;
}
If you have a lot of methods throwing NotImplementedException
(which itself may indicate that some design-level refactoring would be good), then you could wrap up the wordiness into a helper class:
public static class TaskConstants<TResult>
{
static TaskConstants()
{
var tcs = new TaskCompletionSource<TResult>();
tcs.SetException(new NotImplementedException());
NotImplemented = tcs.Task;
}
public static Task<TResult> NotImplemented { get; private set; }
}
public Task<int> Fail() // note: no "async"
{
return TaskConstants<int>.NotImplemented;
}
The helper class also reduces garbage that the GC would otherwise have to collect, since each method with the same return type can share its Task
and NotImplementedException
objects.
I have several other "task constant" type examples in my AsyncEx library.
Related Topics
Manual Editing of *.Designer.Cs File
How to Create a Button That Can Send Keys to a Conrol Without Losing Focus - Virtual Keyboard
Xml Deserialization of Collection Property with Code Defaults
How to Group by on 2 Child Entities and Get Total of Both This Child Entities
Dependency Injection Type-Selection
Encoding Space Character in Xml Name
In-Use Files Not Updated by Msi-Installer (Visual Studio Installer Project)
Good Introduction to the .Net Reactive Framework
ASP.NET Web Application Message Box
How to Get the Index of the Highest Value in an Array Using Linq
Using SQLdataadapter to Insert a Row
Efficient Cartesian Product Algorithm