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>.
Related
I am working on an ASP.NET Core 2.2 application with Dapper. Virtually all methods follows the async/await pattern returning some sort of Task as a result.
Due to an issue we had with Dapper (I haven't personally investigated it, this part of the code I use as it is) but basically it boils down to the fact that if you want to execute in Transaction multiple async methods, which internally are calling other async methods and you may have several levels of nesting this way, you need to wrap all those method invocations within a single method which would be executed in a transaction.
The method that handles this is as follows:
public async Task<TOut> ExecuteInTransactionAsync<TOut>(
Delegate function,
params object[] parameters)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var result = await ((Task<TOut>)function.DynamicInvoke(parameters))
.ConfigureAwait(false);
scope.Complete();
return result;
}
}
So I have a very complex Entity which is saved by calling Save to a lot of smaller entities. This part of the code is working OK and looks like this:
public async SaveEntireEntity(EntityDTO entityDTO)
{
return await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task<dynamic>>(async dto => await SaveInTransaction(dto)),
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age });
}
And the SaveInTransaction method looks like:
private async Task<dynamic> SaveInTransaction(dynamic dto)
{
var entityId = await nameService.Add(dto.Name);
await addressService.Add(dto.Address);
await ageService.Add(dto.Age);
return entityId;
}
so this is simplified, but indeed I am calling a multiple services here, which on their part are calling multiple repositories and this works fine.
The Problem I have is when it comes to updating the same entity within a transaction. The whole purpose of showing the Save logic was to point out that at the end because I have this return entityId; I am able to chain everything together without any problems. However, as it is right now, by default our Update methods are not returning anything and this is where I can't figure out how to implement the Update logic.
Currently I have this:
public async Task UpdateEntireEntity(UpdateEntityDTO, entityDTO)
{
await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task<dynamic>>(async dto => await UpdateInTransaction(dto)),
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age });
}
And UpdateInTransaction looks like this:
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return await Task.FromResult<dynamic>(null);
}
This seems to work at least based on the several tests I made, however I really don't like this part:
return await Task.FromResult<dynamic>(null);
To me it seems like an ugly hack. The Update methods were thought not to return any value and this is just too artificial.
And even the worst part is that I can not figure out how implement the update method without having to return something.
One thing I've tried is to change the declaration of UpdateInTransaction to
private async Task UpdateInTransaction(dynamic dto)
and when I call the method I change it to:
await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task>( async dto => await UpdateInTransaction(dto)..
But I got the following exception:
AsyncStateMachineBox1[System.Threading.Tasks.VoidTaskResult,
<fully-qualified- name>.<<UpdateEntireEntity>b__0>d] to type
'System.Threading.Tasks.Task1[System.Threading.Tasks.Task]'
.
So basically that's it. Sorry for the long post. I would really appreciate some well explained answer.
I would avoid the use of Delegate since it isn't typed:
public async Task<TOut> ExecuteInTransactionAsync<TOut>(Func<Task<TOut>> function)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var result = await (function()).ConfigureAwait(false);
scope.Complete();
return result;
}
}
This signature would mean you'd need to capture parameters rather than pass them:
public async Task<dynamic> SaveEntireEntity(EntityDTO entityDTO)
{
return await _transactionProvider.ExecuteInTransactionAsync(
async () => await SaveInTransaction(
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age }));
}
Once you're using the strongly-typed Func<Task<T>> instead of Delegate in your method signature, you can create an overload for ExecuteInTransactionAsync as such:
public async Task ExecuteInTransactionAsync(Func<Task> function)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
await (function()).ConfigureAwait(false);
scope.Complete();
}
}
which can be used as such:
public async Task UpdateEntireEntity(UpdateEntityDTO entityDTO)
{
await _transactionProvider.ExecuteInTransactionAsync(
async () => await UpdateInTransaction(
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age }));
}
private async Task UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
}
You can change
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return await Task.FromResult<dynamic>(null);
}
to
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return null;
}
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.
I need to implement a custom Storage provider for aspnetidentity.
I had a good look round and i found quite a few.However they seem all wrong to me.
My understing is that if you have a method that ends with "async" than it should by asynchronous.
See example taken from somebody's code and this is scattered all over the place.
I find below very misleading since it's not Async at all from what I can see:
public Task<TUser> FindByIdAsync(int userId)
{
TUser result = userTable.GetUserById(userId) as TUser; //this is not async
if (result != null)
{
return Task.FromResult<TUser>(result);
}
return Task.FromResult<TUser>(null);
}
should this be coded like this?:
public async Task<TUser> FindByIdAsync(int userId)
{
TUser result = userTable.GetUserByIdAsync(userId) as TUser;
if (result != null)
{
return await Task.FromResult<TUser>(result);
}
return await Task.FromResult<TUser>(null);
}
Questions?
Is it correct to do "Task.FromResult"? What I mean is does "Task.FromResult actually turns into synchronous? what should it be?
What is the correct way to code the above? what about configureAwait(false)
should async be "All the way down including datalayer to avoid deadlocking"
any sample code /snippet would be appreciated
many thanks for any feedback
The code is not misleading. ASP.NET Identity framework has been designed to provide an asynchronous interface by returning a Task and indicating this by adding the Async suffix to the method name:
Task<TUser> FindByIdAsync(int userId)
However, the underlying provider may not have asynchronous methods. In that case you cannot create an asynchronous implementation but you still have to implement the interface and to do that will have use Task.FromResult exactly as it is done in your first code snippet.
Implementing an asynchronous method using synchronous code
public Task<TUser> FindByIdAsync(int userId)
{
TUser result = userTable.GetUserById(userId) as TUser;
return Task.FromResult<TUser>(result);
}
If your underlying provider supports asynchronous methods you should use async and await.
Implementing an asynchronous method using asynchronous code
public async Task<TUser> FindByIdAsync(int userId)
{
TUser result = (await userTable.GetUserByIdAsync(userId)) as TUser;
return result;
}
Note that Task.FromResult is not used. Task.FromResult is only needed when you have a TResult created by synchronous code and you have to convert it to Task<TResult> required by asynchronous code.
Sometimes your underlying provider can return the desired Task<TUser> without any further work. In that case you can remove the async and await and still provide an asynchronous implementation. This can result in slightly more efficient code:
public Task<TUser> FindByIdAsync(int userId)
{
Task<TUser> result = userTable.GetUserByIdAsync(userId);
return result;
}
The initial code is definitely not asynchronous. It looks like it was put that way to cope with an API design.
However the proposed change doesn't look async to me either. Task.FromResult just creates a completed task with a result, doesn't make anything asynchronous or executes any kind of awaitable code so you should not await on it.
In your case, assuming GetUserByIdAsync returns a Task<TUser>, and assuming the whole purpose of this code (as it seems) is to always return a completed task (never faulted or cancelled), this could be rewritten as:
public async Task<TUser> FindByIdAsync(int userId)
{
var tResult = userTable.GetUserByIdAsync(userId);
TUser result = null;
try
{
result = await tResult;
}
except
{
// Bad idea, but here goes to your first snippet
}
return Task.FromResult<TUser>(result);
}
Note: this is a bad idea as #PanagiotisKanavos commented, it's hiding a possibly faulted state and you won't ever know if your null result came the user not being found, or if there was an error condition: I'd avoid it.
If a faulted/cancelled state is valid, this could simply be:
public Task<TUser> FindByIdAsync(int userId)
{
return userTable.GetUserByIdAsync(userId);
}
An async method is a way for the compiler to build something that will return a promise our future. In the case of the .NET Framework and C#, that is a Task.
The await instruction takes any awaitable and Task just happens to be one. It doesn't know or care if the method/operations being invoked is really asynchronous or not.
Task.FromResult<T> returns a completed task and if you use it in an await instruction inside an async method it will be considered to have been completed synchronously and execution will continue.
So, using async and await with just calls to Task.FromResult<T> ends up just being a waste of CPU cycles and memory by the compiler generating code that will waste more CPU cycles and memory at run time.
Because an async method always returns a Task a decision was made to make it implicit to improve readability and give it some kind of sync feeling. The compile will wrap the return value in a Task. That's why you can't return Task.FromResult<TUser>(result) or Task.FromResult<TUser>(null) directly and are awaiting it to get the value.
So, the async equivalent of your synchronous code would be:
public async Task<TUser> FindByIdAsync(int userId)
{
var result = await userTable.GetUserByIdAsync(userId) as TUser;
if (result != null)
{
return result;
}
return null;
}
Or:
public async Task<TUser> FindByIdAsync(int userId)
{
return await userTable.GetUserByIdAsync(userId) as TUser;
}
I have an async function. There are multiple levels of function calls that all return a Task. At some point in this chain I must modify the value of the result. I would like to do this without interrupting the flow of the async functions. Observe:
[HttpGet]
[Route("GetWeb")]
public async Task<IHttpActionResult> GetResult([FromUri] string url)
{
var result = await GetPageText(url);
return Ok(result);
}
private Task<string> GetPageText(string url)
{
Task<string> data = GetDataAsync(url);
//here I would like to manipulate the data variable
return data;
}
In the function GetPageText how do I manipulate the data variable without interrupting the asynchronous flow. Is this possible?
You can't change a task's value, you need to create a new one. The async way of doing it is awaiting the original result and marking the method as async (that's only the case when you need the result of the original task):
private async Task<string> GetPageText(string url)
{
var result = await GetDataAsync(url);
return result + "bar";
}
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;