How to change a value in a Task - c#

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";
}

Related

Why is task executing code before it finishes?

I was looking to make a settings method that executes the given settings and than execute the passed function/task. So instead of me typing a settings method each time
pubic void SomeMethod()
{
SettingsMethod()
//code
MainMethod()
}
public void SomeMethod2()
{
SettingsMethod()
/code...
MainMethod()
}
i wanted to do something like this:
public async static Task<T> ConfigureSettings<T>(Task<T> apiCallMethod, string localHost,int port, string riotToken)
{
client.BaseAddress = new Uri("https://"+localHost + ":"+port);
Console.WriteLine(client.BaseAddress);
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", riotToken);
return await apiCallMethod;
}
public async static Task<string> GetSummonerId()
{
HttpResponseMessage response = await client.GetAsync("/lol-login/v1/session");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
And be able to call it like this:
string summonerId = LeagueApiProcessor.ConfigureSettings(LeagueApiProcessor.GetSummonerId(), LeagueAccount.LocalHost, LeagueAccount.LocalHostPort, LeagueAccount.RiotToken).Result;
As i tried to debug the code, the
HttpResponseMessage response = await client.GetAsync("/lol-login/v1/session");
is executing much earlier than the
client.BaseAddress = new Uri("https://"+localHost + ":"+port);
Console.WriteLine(client.BaseAddress);
and that is making it crash each time.
I've tried changing the return types, but that just breaks my code even more. What would be the best approach to solve this, again this was my attempt to make a SettingsMethod() execute every time before the "MainMethod()" without having to type it in each function.
Rather than accept an already running Task<T>, accept a Func that will start the Task<T> and return it when you call it. This can be as simple as:
public async static Task<T> ConfigureSettings<T>(Func<Task<T>> apiCallMethod, string localHost,int port, string riotToken)
{
//...
return await apiCallMethod();
}
And:
LeagueApiProcessor.ConfigureSettings(LeagueApiProcessor.GetSummonerId, ...
Notice that we're not invoking GetSummonerId when creating the arguments to ConfigureSettings, we're instead implicitly converting it to a delegate that is called at the end of ConfigureSettings instead.
For more complex examples (say, when you need to pass arguments to the second method), you may need to pass a lambda instead:
LeagueApiProcessor.ConfigureSettings(() => CallSomeTaskReturningMethod(arg1,arg2), ...

If i add async keyword to a method which which should return a Task it wrap the return value in Task?

if write this function without async and await as this example i get error that i should return Task not User object
public Task<User> Register(User user, string password)
{
byte[] passwordhash,passwordsalt;
CreatePassword(password,out passwordhash,out passwordsalt);
return user;
}
but if write this function with async and await as this example it work correctly, so i want to know if add async keyword to any method it should wrap the returned value to a Task automaticily
public async Task<User> Register(User user, string password)
{
byte[] passwordhash,passwordsalt;
CreatePassword(password,out passwordhash,out passwordsalt);
await _Context.Users.AddAsync(user);
await _Context.SaveChangesAsync();
return user;
}
if add async keyword to any method it should wrap the returned value to a Task automaticily
Yes. One way of thinking about this is that async wraps the returned value (or exception) into a Task (or task-like). And await "unwraps" that returned value (or exception).

Calling multiple async methods within other method without returning result

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;
}

How do I hide Task of Task?

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>.

C# Tasks get result or catch exception

I have:
public static async Task<string> httpRequest(HttpWebRequest request)
I would like to do this:
string rez1;
static void test()
{
Task.Factory.StartNew(() => {
//How can I get result like rez1= httpRequest((HttpWebRequest)HttpWebRequest.Create("google.com")));
//or catch WebException here.
});
}
How can I do it?
Thanks
You have it mixed up a little bit. When your methods signature is:
public static async Task<string> httpRequest(HttpWebRequest request)
That means "this method is invoked asynchronously, i will call it and it will return imminently with a promise to finish in the future".
You should change your method to look like this:
Edit
Fixed the code according to the comments made.
public static Task<string> httpRequest(HttpWebRequest request)
{
return Task.Factory.Startnew(() = > {
return HttpWebRequest.Create("google.com")
}
}
When your method is marked as async, that means the caller might think it is "pure" async, which means no threads execute behind the scenes. If you do fire up a new thread (as you are doing here, by using a Thread Pool thread) you should explicitly comment your method and tell your invoker that he will be firing up a new thread.
You can save yourself firing up a new Task if you're using .NET 4.5 and have access to the new HttpClient class.
You can change your method to look like this:
public static async Task<string> httpRequest(HttpWebRequest request)
{
var httpClient = new HttpClient();
var response = await httpClient.GetAsync("http://www.google.com")
var stringResult = await response.Content.ReadAsStringAsync();
return stringResult;
}

Categories