I have code:
public async Task DeleteColorSchemeAsync(ColorScheme colorScheme)
{
if (colorScheme == null)
throw new ArgumentNullException(nameof(colorScheme));
if (colorScheme.IsDefault)
throw new SettingIsDefaultException();
_dbContext.ColorSchemes.Remove(colorScheme);
await _dbContext.SaveChangesAsync();
}
One code analyzer recommends me to split this method to 2 methods:
Split this method into two, one handling parameters check and the other handling the asynchronous code
Am I correct, when I split this code in the following way?
public async Task DeleteColorSchemeAsync(ColorScheme colorScheme)
{
if (colorScheme == null)
throw new ArgumentNullException(nameof(colorScheme));
if (colorScheme.IsDefault)
throw new SettingIsDefaultException();
await DeleteColorSchemeInternalAsync(colorScheme);
}
private async Task DeleteColorSchemeInternalAsync(ColorScheme colorScheme)
{
_dbContext.ColorSchemes.Remove(colorScheme);
await _dbContext.SaveChangesAsync();
}
What is different for the compiler? It sees two async methods, what is different from my first variant?
used code tool analyzator: sonarqube
Assuming you wanted to follow the code analysis advice, I would not make the first method async. Instead, it can just do the parameter validation, and then return the result of calling the second:
public Task DeleteColorSchemeAsync(ColorScheme colorScheme)
{
if (colorScheme == null)
throw new ArgumentNullException(nameof(colorScheme));
if (colorScheme.IsDefault)
throw new SettingIsDefaultException();
return DeleteColorSchemeInternalAsync(colorScheme);
}
private async Task DeleteColorSchemeInternalAsync(ColorScheme colorScheme)
{
_dbContext.ColorSchemes.Remove(colorScheme);
await _dbContext.SaveChangesAsync();
}
All that said, in my opinion there's not really a strong justification to split the method like that. The SonarQube's rule, Parameter validation in "async"/"await" methods should be wrapped is IMHO overly cautious.
The compiler uses the same kind of transformation on async methods as it does for iterator methods. With an iterator method, there is value in doing parameter validation in a separate method, because otherwise it won't be done until the caller tries to get the first element in the sequence (i.e. when the compiler-generated MoveNext() method is called).
But for async methods, all of the code in the method up to the first await statement, including any parameter validation, will be executed on the initial call to the method.
The SonarQube rule appears to be based on a concern that until the Task is observed, any exception generated in the async method won't be observed. Which is true. But the typical calling sequence of an async method is to await the returned Task, which will observe the exception immediately on completion, which of course occurs when the exception is generated, and will happen synchronously (i.e. the thread won't be yielded).
I admit that this is not hard-and-fast. For example, one might initiate some number of async calls, and then use e.g. Task.WhenAll() to observe their completions. Without immediate parameter validation, you would wind up starting all of the tasks before realizing that one of the calls was invalid. And this does violate the general principle of "fail-fast" (which is what the SonarQube rule is about).
But, on the other hand, parameter validation failures are almost always due to user code incorrectness. I.e. they don't happen because of data input problems, but rather because the code was written incorrectly. "Fail-fast" is a bit of a luxury in that context; what's more important, to me anyway, is that the code be written in a natural, easy-to-follow way, and I'd argue that keeping everything in one method achieves that goal better.
So in this case, the advice being given by SonarQube isn't necessary to follow. You can just leave your async method as a single method, the way you had it originally without harming the code. Even more so than the iterator method scenario (which has similar arguments pro and con), there is IMHO just as much reason to leave the validation in the async method as to remove it to a wrapper method.
But if you do choose to follow SonarQube's advice, the example I provided above is IMHO a better approach than what you have (and indeed, is more in line with the detailed advice on SonarQube's documentation).
I will note that in fact, there's an even simpler way to express the code:
public Task DeleteColorSchemeAsync(ColorScheme colorScheme)
{
if (colorScheme == null)
throw new ArgumentNullException(nameof(colorScheme));
if (colorScheme.IsDefault)
throw new SettingIsDefaultException();
_dbContext.ColorSchemes.Remove(colorScheme);
return _dbContext.SaveChangesAsync();
}
I.e. don't make the implementation async at all. Your code doesn't need async because there's only one await and it occurs at the very end of the method. Since your code doesn't actually need control returned to it, there's not actually any need to make it async. Just do all the synchronous stuff you need to do (including parameter validation), and then return the Task you'd otherwise have awaited.
And, I'll note as well, this approach addresses both the code analysis warning, and keeps the implementation simple, as a single method with parameter validation built-in. Best of both worlds. :)
Am I correct, when I split this code in the following way?
No. The correct way to split them would be like this:
public Task DeleteColorSchemeAsync(ColorScheme colorScheme)
{
if (colorScheme == null)
throw new ArgumentNullException(nameof(colorScheme));
if (colorScheme.IsDefault)
throw new SettingIsDefaultException();
return DeleteColorSchemeInternalAsync(colorScheme);
}
private async Task DeleteColorSchemeInternalAsync(ColorScheme colorScheme)
{
_dbContext.ColorSchemes.Remove(colorScheme);
await _dbContext.SaveChangesAsync();
}
(note that the entry method is not async in this case).
Or like this, using the newer local functions:
public Task DeleteColorSchemeAsync(ColorScheme colorScheme)
{
if (colorScheme == null)
throw new ArgumentNullException(nameof(colorScheme));
if (colorScheme.IsDefault)
throw new SettingIsDefaultException();
return DeleteColorSchemeAsync();
async Task DeleteColorSchemeAsync()
{
_dbContext.ColorSchemes.Remove(colorScheme);
await _dbContext.SaveChangesAsync();
}
}
The reason this rule exists is to make sure you throw as soon as possible on usage exceptions. If you don't split the logic and leave validation inside the async method, the exception will only be thrown when someone awaits your returned task, which may not happen immediately depending on usage.
One very common flow where throwing early would be beneficial, is when you want to fire multiple tasks concurrently and await for their completion. Since on this flow your await action happens after the tasks are fired, you'll get an exception that is potentially very far from the actual point of the call, making it unnecessarily harder to debug.
The accepted answer also proposes returning the task directly in cases where you have only one async operation to do and that is the result value, however that introduces significant problems when debugging code, since your method is omitted from the stacktrace, making it harder to navigate in the entire flow. Here is a video that discusses this problem in more depth:
https://youtu.be/Q2zDatDVnO0?t=327
Returning the task directly without awaiting it should only be done for extremely simple "relay"-type methods, where there is very little relevant logic in the parent method.
I'd advise following the rule at all times.
Related
Section 10.2 within Concurrency in .NET provides the following listing for an Otherwise task combinator:
public static Task<T> Otherwise<T>(this Task<T> task, Func<Task<T>> orTask) =>
task.ContinueWith(async innerTask =>
{
if (innerTask.Status == TaskStatus.Faulted) return await orTask();
return await Task.FromResult<T>(innerTask.Result);
}).Unwrap();
(Confusingly, within the printed book, Otherwise is marked as async which fails to compile; however, not in the GH listing which compiles without issue)
My "understanding" is that if the anonymous continuation is called, it would suggest that the supplied innerTask has completed by that point, successfully or otherwise.
Assuming successful, it would also suggest that innerTask.Result would already be determined with no synchronous waiting required upon calling that member property.
On the mild assumption that above is sensible... What possible benefit is there from using return await Task.FromResult<T>(innerTask.Result) as opposed to just return innerTask.Result? (the latter of which also compiles).
Unless I'm missing something (quite likely)... It feels overly verbose.
Update:
Thank you to everyone who has contributed; I never anticipated this would get as much feedback as it has!
At one point, I was concerned about a situation where innerTask.Result could raise an exception and how that would be dealt with by the 2x return approaches above.
From my own testing since, I can see that if innerTask was cancelled and, hence innerTask.Status == TaskStatus.Cancelled, the combinator implementation as given would permit the accessing of innerTask.Result which would then raise an AggregateException.
However, there is no difference in how this (or any other exception I imagine) would be treated by either return approach from within an async function.
Given this, and the information provided, it appears as though the former approach offers nothing over and above the latter. If anything, it (IMHO) obscurs the intention and has sent me down a (albeit illuminating) rabbit hole.
What possible benefit is there from using return await Task.FromResult<T>(innerTask.Result) as opposed to just return innerTask.Result?
Absolutely zero benefit. That's the kind of code that your end up writing when you are struggling with a concept that you don't fully understand, and you reach to a version that compiles and works correctly. Your code might end up decorated with some useless cargo, which nonetheless is not harmful, so it might survive multiple code reviews and revisions.
Here is a better way to write the Otherwise extension method:
public static Task<T> Otherwise<T>(this Task<T> task, Func<Task<T>> onErrorTaskFactory)
{
return task.ContinueWith(innerTask =>
{
if (innerTask.IsFaulted) return onErrorTaskFactory();
return innerTask;
}, default, TaskContinuationOptions.DenyChildAttach |
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default).Unwrap();
}
Notice that the continuation is not async, and it returns the innerTask, not its result. With this version you get these benefits:
In case the onErrorTaskFactory() returns a Task that also fails, and it contains more that one exceptions (think of passing a lambda that return Task.WhenAll()), all the errors will be propagated, not just the first one.
In case the innerTask is canceled, the cancellation will be propagated without an additional internal try/catch. Throwing and catching exceptions in C# is quite expensive.
The code complies with the CA2008 guideline ("Do not create tasks without passing a TaskScheduler").
The onErrorTaskFactory will be invoked synchronously on the thread that completed the innerTask, avoiding a thread-switch.
These benefits are not ground-breaking. I would evaluate the original implementation in the book as quite decent. It doesn't have any terrible bugs or inefficiencies.
public async Task GetLiveCandleStick(string param)
{
await Clients.All.SendAsync("ReceiveMessage", param);
}
Please consider the above code.
Almost all of the tutorial await Clients.xxx.SendAsync methods. However, I find that it works fine even I take away the await keyword. Then what is the point of using await? (I have seen a thread explaned that await is not meant to "wait until client receive the message...")
Thanks in advance.
By omitting the await keyword, the method would become fire-and-forget; this is almost never the right thing to do, as you would have no way of knowing that the Task had completed.
Another issue is exception handling. If an exception occurs when you call SendAsync, it is placed on the Task rather than being thrown directly, and would simply be garbage collected without using await.
Having said this, if your GetLiveCandleStick method is a simple wrapper as you suggest, it would be slightly more efficient to simply return the Task from SendAsync rather than create a new one using async:
public Task GetLiveCandleStick(string param)
{
return Clients.All.SendAsync("ReceiveMessage", param);
}
In this case only, you don't need to use await - nothing else is happening after SendAsync so there's no need to await. Awaiting on GetLiveCandleStick would behave the same as awaiting on SendAsync. You could convert this method to :
public Task GetLiveCandleStick(string param)=> Clients.All.SendAsync("ReceiveMessage", param);
Tutorials use await because quite often there is code after SendAsync, that should be executed after SignalR enqueues the message.
You may want to add error handling in case SignalR throws for example, or ensure a Begin message is enqueued after an End message in a tight loop. Having an await even for a single statement method can be useful for debugging too.
Finally, good tutorials shouldn't introduce unrelated concepts as this can easily lead to confusion. A SignalR tutorial isn't the best place for explaining the await state machine, or when await can be skipped. Unfortunately, too many examples in learn.microsoft.com try to put everything into a single page, resulting in quite a bit of confusion.
The keyword "await" is for async methods. It's smarter than "wait", it's async wait!
This means that wait the return of message during exec the code until the result is necessary used. So You don't have to use Thread.Wait in a line of code, but the compiler place the wait in the right position. In this case the method that call the await is async, so the wait of Clients.All.SendAsync is out of function.
I admit that there is probably something basic I'm not grasping here, but in the below code, why whould I have to await two times the same query?
I'm looking up a person by his email address, which is a database lookup. I call my private function GetByEmailQueryAsync which returns a record from the database if found. I use await for this call, so I'm sure that a result (if found) is returned.
Why do I have to put the await keyword again in the function calling GetByEmailQueryAsync? And then again in all functions calling GetByEmail. The callers of this function should not care that this function performs some asynchronous task, in my opinion.
Again, I'm probably missing something basic here.
public async Task<Person> GetByEmail(string emailAddress)
{
return await GetByEmailQueryAsync(emailAddress);
}
private async Task<Person> GetByEmailQueryAsync(string emailAddress)
{
return await DbContext.Set<Person>.SingleOrDefaultAsync(x => x.EmailAddress == emailAddress);
}
This is a pretty basic example of what I mean, but I hope you get the gist.
You don't need to await both.
As your GetByEmail method is simply calling GetByEmailQueryAsync, this would work just as well:
public Task<Person> GetByEmail(string emailAddress)
{
return GetByEmailQueryAsync(emailAddress);
}
In fact by not using await twice, it means only one Task is required, rather than two.
Why do I have to put the await keyword again in the function calling GetByEmailQueryAsync? And then again in all functions calling GetByEmail. The callers of this function should not care that this function performs some asynchronous task, in my opinion.
While it would be nice to treat asynchronous code as an implementation detail, that is not possible to do in the C# language.
As a general rule, any method calling an asynchronous method should consume it with await, and the calling method itself is also an asynchronous method. So its callers should consume it with await, and themselves be asynchronous methods, etc. This "growth" of async/await through the code base is natural, and it is proper to go async all the way.
In trivial cases, it is possible to elide async/await, but even in that case the calling method is still asynchronous.
I have a large scale C# solution with 40-ish modules.
I'm trying to convert a service used solution-wide from synchronous to asynchronous.
the problem is I can't find a way to do so without changing the signature of the method.
I've tried wrapping said asynchronous desired operation with Task but that requires changing the method signature.
I've tried changing the caller to block itself while the method is operating but that screwed my system pretty good because it's a very long calling-chain and changing each of the members in the chain to block itself is a serious issue.
public SomeClass Foo()
{
// Synchronous Code
}
Turn this into:
public SomeClass Foo()
{
//Asynchronous code
}
whilst all callers stay the same
public void DifferentModule()
{
var class = Foo();
}
Any implementation that fundamentally changes something from sync to async is going to involve a signature change. Any other approach is simply not going to work well. Fundamentally: async and sync demand different APIs, which means: different signatures. This is unavoidable, and frankly "How to convert synchronous method to asynchronous without changing it's signature?" is an unsolvable problem (and more probably: the wrong question). I'm sorry if it seems like I'm not answering the question there, but... sometimes the answer is "you can't, and anyone who says you can is tempting you down a very bad path".
In the async/Task<T> sense, the most common way to do this without breaking compatibility is to add a new / separate method, so you have
SomeReturnType Foo();
and
Task<SomeReturnType> FooAsync(); // or ValueTask<T> if often actually synchoronous
nothing that Foo and FooAsync here probably have similar but different implementations - one designed to exploit async, one that works purely synchronously. It is not a good idea to spoof one by calling the other - both "sync over async" (the synchronous version calling the async version) and "async over sync" (the async version calling the sync version) are anti-patterns, and should be avoided (the first is much more harmful than the second).
If you really don't want to do this, you could also do things like adding a FooCompleted callback event (or similar), but : this is still fundamentally a signature change, and the caller will still have to use the API differently. By the time you've done that - you might as well have made it easy for the consumer by adding the Task<T> API instead.
The common pattern is to add an Async to the method name and wrap the return type in a Task. So:
public SomeClass Foo()
{
// Synchronous Code
}
becomes:
public Task<SomeClass> FooAsync()
{
// Asynchronous Code
}
You'll end up with two versions of the method, but it will allow you to gradually migrate your code over to the async approach, and it won't break the existing code whilst you're doing the migration.
If you desperately need to do this, it can be achieved by wrapping the Synchronous code that needs to become Asynchronous in a Task this can be done like this:
public SomeClass Foo()
{
Task t = Task.Run(() =>
{
// Do stuff, code in here will run asynchronously
}
t.Wait();
// or if you need a return value: var result = t.Wait();
return someClass;
// or return result
}
Code you write inside the Task.Run(() => ...) will run asynchronously
Short explanation: with Task t = Task.Run(() => ...) we start a new Task, the "weird" parameter is a Lambda expression, basically we're passing a anonymous Method into the Run method which will get executed by the Task
We then wait for the task to finish with t.Wait();. The Wait method can return a value, you can return a value from an anonymous method just like from any method, with the return keyword
Note: This can, but should not be done. See Sean's answer for more
A few posts on stack overflow have suggested the following:
Any async method where you have a single await expression awaiting a Task or Task < T >, right at the end of the method with no further processing, would be better off being written without using async/await.
Architecture for async/await
Await or Return
Is this advice just for particular circumstances? On a web server, isn't one of the main reasons to use async/await, being that while awaiting something like the UpdateDataAsync method below, the Thread will return to the ThreadPool, allowing the server to work on other requests?
Should SaveDataAsync await that DB update call given it's the last call in the method?
public async Task WorkWithDataAsync(Data data)
{
ManipulateData(data);
await SaveDataAsync(data);
await SendDataSomewhereAsync(data);
}
public async Task SaveDataAsync(Data data)
{
FixData(data);
await DBConnection.UpdateDataAsync(data);
}
Also, given you don't know where SaveDataAsync will be used, making it synchronous would hurt a method like WorkWithDataAsync would it not?
Removing the await and just returning the Task doesn't make the method synchronous. await is a tool that makes it easier to make a method asynchronous. It's not the only way to make a method asynchronous. It's there because it allows you to add continuations to task much more easily than you could without it, but in the method that you've shown you're not actually leveraging the await keyword to accomplish anything and as such you can remove it and have the code simply function identically.
(Note that technically the semantics of exceptions will have been slightly changed by removing async; thrown exceptions will be thrown from the method, not wrapped in the returned Task, if it matters to you. As far as any caller is concerned, this is the only observable difference.)
Writing these methods without the async-await keywords doesn't make them synchronous.
The idea is to return the task directly instead of having the overhead of generating the state machine.
The actual difference is about exception handling. An async method encapsulates exceptions inside the returned task while a simple task returning method doesn't.
If for example FixData throws an exception it will be captured in an async method but directly thrown in a simple task returning one. Both options would be equally asynchronous.