'Extract a method' is one of the most important and frequently performed refactoring to keep code clean and readable. In many cases, we can apply it automatically and safely with all modern IDEs.
My question is what is the best approach to apply this to async methods in C# (and other languages with async keyward such as JavaScript, TypeScript etc.)
As an example, suppose we have a lengthy async method which can be logically grouped and decomposed into separate methods like below:
private async Task StartWriting()
{
if (IsCreatingNewDir)
{
SaveFile();
var writingSpec = _writingSpec.Model!;
if (!OkToStartWriting(writingSpec)) return;
await _jobQueue.EnterJob(writingSpec);
}
else
{
if (!OkToStartWritingFromExistingDir()) return;
try
{
await _jobQueue.EnterJobFromExistingJobDir(Path.GetDirectoryName(Path.GetDirectoryName(FilePath))!);
}
catch (InvalidOperationException ex)
{
DialogManager.ShowError(Localize("NoConversionResultInJobDir"));
Logger.LogError(ex, "Invalid job directory.");
}
}
}
If I just apply it with Visual studio (with resharper), each of the extracted fragments becomes also an async method.
public async Task StartWriting()
{
if (IsCreatingNewDir)
{
await StartWritingFromScratch();
}
else
{
await StartWritingFromExistingDir();
}
}
private async Task StartWritingFromScratch()
{
SaveFile();
var writingSpec = _writingSpec.Model!;
if (!OkToStartWriting(writingSpec)) return;
await _jobQueue.EnterJob(writingSpec);
}
private async Task StartWritingFromExistingDir()
{
if (!OkToStartWritingFromExistingDir()) return;
try
{
await _jobQueue.EnterJobFromExistingJobDir(Path.GetDirectoryName(Path.GetDirectoryName(FilePath))!);
}
catch (InvalidOperationException ex)
{
DialogManager.ShowError(Localize("NoConversionResultInJobDir"));
Logger.LogError(ex, "Invalid job directory.");
}
This is OK, as the logic is the same and async method can call another async method. However, considering that async method is really a syntactic sugar and it is converted to rather complex code under the hood, I wonder if it's additional overhead is legitimate just to keep code readable. I think that the original refactoring to normal methods, hidden assumption is that method call overhead is rather small and negligible.
Another option I can think of is to extract each fragment as a synchronous method returning a Task like this:
// Extract fragment as a regular synchronous method returning Task which is awaitable.
private Task StartWritingFromExistingDir()
{
if (!OkToStartWritingFromExistingDir()) return Task.CompletedTask;
try
{
return _jobQueue.EnterJobFromExistingJobDir(Path.GetDirectoryName(Path.GetDirectoryName(FilePath))!);
}
catch (InvalidOperationException ex)
{
DialogManager.ShowError(Localize("NoConversionResultInJobDir"));
Logger.LogError(ex, "Invalid job directory.");
return Task.CompletedTask;
}
}
The code looks a bit noisier as I have to return Task explicitly, but I think it performs better and in most cases easier to debug and test.
Is there a generally agreed known best practice for doing this refactoring to async methods?
If you are concerned about the additional overhead, modify the parent method like this:
public Task StartWriting()
{
if (IsReadOnly)
{
return StartWritingFromExistingDir();
}
else
{
return StartWritingFromScratch();
}
}
Now you are not creating any of the additional async overhead.
Related
We have a deadlock like behaviour in our production-environment and I wonder if we use SemaphoreSlim correctly.
In our restapi the code looks like this:
public async Task<IActionResult> CreateAsync([FromBody] SomeModel someModel)
{
var result = await _someClass.CreateArende(someModel);
return result;
}
public async Task<IActionResult> RegisterAsync([FromBody] SomeModel someModel)
{
var result = await _someClass.RegisterArende(someModel);
return result;
}
No SemphoreSlim in controller level of our API but in someClass looks like this:
public class SomeClass
{
protected static SemaphoreSlim _semphoreSlimCreateArende = new SemaphoreSlim(1, 1);
public async virtual Task<SomeResponseDto> CreateArende(SomeModel someModel)
{
try
{
await _semphoreSlimCreateArende.WaitAsync();
}
finally
{
try
{
_semphoreSlimCreateArende.Release();
}
catch (Exception)
{
}
}
return new SomeResponseDto()
{
...
};
}
public async virtual Task<SomeResponseDto> RegisterArende(SomeModel someModel)
{
try
{
await _semphoreSlimCreateArende.WaitAsync();
}
finally
{
try
{
_semphoreSlimCreateArende.Release();
}
catch (Exception)
{
}
}
return new SomeResponseDto()
{
...
};
}
}
Should the SemaphoreSlim be in the controller level instead? Or should I change the controllers actions to not be async?
This question is a little disjointed, however lets try to make sense of it a little
Firstly lets get the pattern right
try
{
await _semphoreSlimCreateArende.WaitAsync();
// do your sync work here
}
finally
{
// if this throws you are certainly doing something wrong
_semphoreSlimCreateArende.Release();
}
Secondly, you should have your keyboard taken away from you for this
catch (Exception)
{
}
Don't ever blindly eat exceptions, and if you are getting them on _semphoreSlimCreateArende.Release you have serious problems already and you have to work out why
Should the semaphoreslim be in the controller level instead?
Use them at the level that makes the most sense, i mean if you need to sync a piece of code sync it there, not 13 levels up.
Or should i change the controllers actions to not be async?
if you have asnyc work make your controller async and let it propagate down the stack to your async code
We have a deadlock like behaviour in our production-environment and i
wonder if we use semaphoreslim correctly.
Woah, are we talking DataBase Deadlocks, or Context DeadLocks. Either way this all sounds a little fishy
This question already has answers here:
Any difference between "await Task.Run(); return;" and "return Task.Run()"? [duplicate]
(4 answers)
Closed 8 years ago.
Is there any difference between the methods below? Is one preferable over the other?
public static async Task SendAsync1(string to, string subject, string htmlBody) {
// ...
await smtp.SendMailAsync(message);
// No return statement
}
public static Task SendAsync2(string to, string subject, string htmlBody) {
// ...
return smtp.SendMailAsync(message);
}
This method will be called from MVC controller methods; for example:
public async Task<ActionResult> RegisterUser(RegisterViewModel model)
{
// ...
await Mailer.SendAsync(user.Email, subject, body);
return View(model);
}
There are 2 practical differences:
The second option will not create the state machine mecanism that allows for async-await usage. That will have a minor positive effect on performance.
The exception handling would be a little different. When you mark a method as async any exceptions are stored in the returned task (both from the asynchronous part and the synchronous one) and thrown only when the task is awaited (or waited). When it's not async, the exceptions from the synchronous parts act just like in any other method.
My suggestion: Use the second one for the added performance boost but keep an eye out for exceptions and bugs.
An example that shows the difference:
public static async Task Test()
{
Task pending = Task.FromResult(true);
try
{
pending = SendAsync1();
}
catch (Exception)
{
Console.WriteLine("1-sync");
}
try
{
await pending;
}
catch (Exception)
{
Console.WriteLine("1-async");
}
pending = Task.FromResult(true);
try
{
pending = SendAsync2();
}
catch (Exception)
{
Console.WriteLine("2-sync");
}
try
{
await pending;
}
catch (Exception)
{
Console.WriteLine("2-async");
}
}
public static async Task SendAsync1()
{
throw new Exception("Sync Exception");
await Task.Delay(10);
}
public static Task SendAsync2()
{
throw new Exception("Sync Exception");
return Task.Delay(10);
}
Output:
1-async
2-sync
First of all, I don't think that the code in your example compiles. You need to remove the 'async' keyword from SendAsync2.
If you do that, then these methods can be used interchangeably, so no, there is no difference in this case. I would prefer the one without async/await.
However, there are cases where it would seem that there is no difference, but the difference lies in the details. Consider for example this code:
async Task<X> Get()
{
using (something)
{
return await GetX();
}
}
If you were to change this to:
Task<X> Get()
{
using (something)
{
return GetX();
}
}
then the using block no longer protects the execution encapsulated in x, and something will be disposed earlier than it would in the first case. Important for example when something is a Entity Framework context.
The same goes for return await inside try blocks.
Your first method which awaits will cause the compiler to create a state machine, since once the await keyword is hit the method will return to the caller, and once the awaited part is completed it has to resume from the point where it left off.
But, since you aren't doing anything after awaiting (there is no continuation), there is no need for that state machine.
The second method is preferred in this case, and you can omit the async keyword from it since you are not awaiting anything
I've been banging my head against a wall for two days now, and frankly I'm annoyed with myself because I just can't seem to get it.
I'm in a webapi context. During this request I need to send some data to one of our other systems, this system is slow to return, due to heavy calculations and multiple database saves etc etc. I need to log the result of this operation, regardless of whether it is successful or not. But I don't want to wait around for it to finish.
I've read that I should be async await all the way from top to bottom. I would have to convert numerous methods if I decided to do this, as I'm already 3 or 4 methods deep, which I fear would branch out even more.
What are my options here? If I go async await all the way down, what do I do with the methods higher up the stack, like my WebApi controllers?
Here is my code, I've tried to thin it down as much as I can. Right now I'm using Task.Result() in the method PushResult(). Which to my understanding is blocking the async? This code works in that the request gets sent. But the TestLog is always last, not first. Therefore not async.
//I'm in a public service and referenced twice
private void MyEndProcess()
{
// other stuff
_vendorPushService.PushResult(); // This could take a while and I have to wait for it!
_logService.PostLog(LogType.TestLog, "Test");
}
//I'm referenced above and somewhere else in the code base
public void PushResult()
{
ExternalResultModel externalResultModel = _resultService.GetExternalResultModel();
PushedResultModel pushedResult = new PushedResultModel();
try
{
pushedResult = _vendorRequestService.PushResultAsync(externalResultModel).Result;
}
catch (Exception ex)
{
pushedResult.Success = false;
}
if (pushedResult.Success)
{
_logService.PostLog(LogType.SuccessLog, pushedResult.Message);
}
else
{
_logService.PostLog(LogType.FailedLog, pushedResult.Message);
}
}
public async Task<PushedResultModel> PushResultAsync(ExternalResultModel externalResultModel)
{
// setup the requestMessage
HttpResponseMessage responseMessage = await _httpRequestService
.SendRequest(requestMessage)
.ConfigureAwait(false);
return new PushedResultModel
{
Success = responseMessage.IsSuccessStatusCode,
Message = await responseMessage.Content.ReadAsStringAsync()
};
}
public class HttpRequestService : IHttpRequestService
{
private readonly HttpClient _httpClient;
public HttpRequestService(IHttpClientAccessor httpClientAccessor)
{
_httpClient = httpClientAccessor.HttpClient;
}
public async Task<HttpResponseMessage> SendRequest(HttpRequestMessage requestMessage)
{
HttpResponseMessage httpResponseMessage = await _httpClient.SendAsync(requestMessage).ConfigureAwait(false);
return httpResponseMessage;
}
}
You should implement async await all the way from top to bottom.
If I go async await all the way down, what do I do with the methods higher up the stack, like my WebApi controllers?
Just make your controller actions async like this:
[RoutePrefix("api")]
public class PresidentsController : ApiController
{
[Route("presidents")]
public async Task<IHttpActionResult> GetPresidents()
{
await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);
return Ok();
}
}
It's easiest way to implement async methods. Even if it will add some work to change everything to async it will benefit in future, because You will avoid many problem with async code.
If you absolutly HAVE to use async method in synchronous methods make it block in ONE place, like this:
public void MySyncMethod()
{
try
{
this.MyAsyncMethod().Wait();
}
catch (Exception exception)
{
//omited
}
}
private async Task MyAsyncMethod()
{
await AsyncLogic().ConfigureAwait(false);
}
But i don't recommend it. You should just use async await all the way to controller action.
In your comment you said you want to process a task in the background and not make the client calling your API wait. To do that, you don't really need to use async/await.
Try this:
private void MyEndProcess()
{
// other stuff
Task.Run(_vendorPushService.PushResult()).ConfigureAwait(false); //fire and forget
_logService.PostLog(LogType.TestLog, "Test");
}
The Task.Run will start the task, and the ConfigureAwait(false) tells it that it does not need to resume on the same context that we're currently on (meaning that the context can close before the task is finished - i.e. the response can be sent back without waiting for the task to finish).
You will get a compiler warning that you're not awaiting Task.Run, but that's what you want.
Keep in mind that when you do this, HttpContext.Current will not be available inside PushResult.
Before/without Task<>s, I'm using a wrapper object like the below to encapsulate the result of an I/O operation that could fail, without propagating exceptions up the call stack:
public class FetchResult<T>
{
public readonly bool Success;
public readonly T Item;
public FetchResult(bool success, T item)
{
this.Success = success;
this.Item = item;
}
}
I'd use it like this:
var userResult = Get("robert.paulson#fightclub.com");
if(!userResult.Success)
// abort, or something
...
public FetchResult<User> Get(string email)
{
try
{
// go to database here, and get the User
return new FetchResult(true, new User());
}
catch
{
// log exception
return new FetchResult(false, null);
}
}
This works great for me as a model, as it allows me to effectively manage exceptions without using try/catch as program control flow and gives me easy and fine-grained graceful service degredation.
However, with the advent of Task<>, I could very easily end up with:
public Task<FetchResult<User>> GetAsync(string email)
which seems to be getting out of hand.
Seeing as I'm migrating to async everywhere anyway, I'm contemplating just doing:
public Task<User> GetAsync(string email)
which id have expected to allow me to do something like:
var userTask = GetAsync("robert.paulson#fightclub.com");
await userTask;
if(userTask.IsFaulted) // (*) - see below
// abort, or something
However if my GetAsync method returns:
return Task<User>.FromException(new Exception());
what is actually returned after the await (where the (*) comment is) seems to be a Completed Task, whos result is a Task<User> which is faulted.
Why am I getting a nested task in this case, and is there some syntactic sugar I'm missing to make this whole affair tidier?
There are two methods in Task library FromException() and FromException<TResult>() both are available via Task and Task<TResult>.
public static Task FromException(Exception exception)
{
return FromException<VoidTaskResult>(exception);
}
public static Task<TResult> FromException<TResult>(Exception exception)
{
...
...
}
If you call Task<TResult>.FromException() or Task.FromException() there's no different in these two calls.
Your method signature is: public Task<User> GetAsync(string email)
Now if you try to use Task<User>.FromException(new Exception()) this will return Task<VoidTaskResult> and which is ofcourse is not of type Task<User>. Which means you might be getting compiler error.
This compile time error would be gone if you use Task<User>.FromException<User>(new Exception()); or Task.FromException<User>(new Exception());
You're getting Task<Task<VoidTaskResult>> as specified in comments means there's something more in your method code which is not mentioned in your sample code.
For more internal details about Task methods in .Net source code see here
Update:
After looking at your code found couple of issues.
i) Return type as Task is avoiding the compilation error that I mentioned earlier in my answer.
ii) You're returning a Task with in a Async method without awaiting means the complete task object will be wrapped in Another Task type.
See below example that I tweaked to to show the problem. See even the return type is changed from Task of type Object to Program there's still no error. This is Because of Object which is base of any custom type in C#. So doing below is allowed:
static async Task<object> GetAsync()
{
try
{
throw new Exception();
}
catch (Exception e)
{
return Task.FromException<Program>(e);
}
}
Now change the return type of method to Task<Program> you'll get an error or more of warning.
Now the correct version to fix the problem would be to await the Task so that only Program type remain as result which will be automatically returned as Task<Program>.
Correct version:
static async Task<Program> GetAsync()
{
try
{
throw new Exception();
}
catch (Exception e)
{
return await Task.FromException<Program>(e);
}
}
Now you won't see any Nested tasks anymore. This is internals of how await works. If you really want know why it happens like this then try to analyze the IL generated of all the above 3 versions of the program using IL spy and you'll get the idea. Cheers!!!
Kind of unusual, but you can explore the fact that the Task.WhenAny method does not throw exception (see Is there a way to Wait for a TPL Task without in throwing an exception?) like this
var userTask = GetAsync("robert.paulson#fightclub.com");
await Task.WaitAny(userTask);
if(userTask.IsFaulted) // (*) - see below
// abort, or something
Task.IsFaulted means that the Task completed due to an unhandled exception. So I don't think you could set it in a different way than to let the exception go uncaught.
public async Task<User> GetAsync(string email)
{
// go to database here, and get the User
return new User();
}
Or catch, log, and rethrow:
public async Task<User> GetAsync(string email)
{
try
{
// go to database here, and get the User
return new User();
}
catch
{
// log exception
throw;
}
}
I believe you are saying that your GetAsync is returning a nested task because you have something like this:
public async Task GetAsync(string email)
{
// .... somewhere in the code
return Task.FromException(new Exception());
}
But when you declare a method using the async keyword, C# magic takes care of wrapping its contents inside a Task. So in this case you actually end up having a task which returns another task - Task<Task<T>>. It would return Task<T> if you removed the async keyword but then obviously you end up with a standard synchronous method.
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