Converting convenience methods that use Tasks - c#

I often write code that has convenience methods which basically wrap other methods. Here's a simple example:
public class WithoutAsync
{
public static ReadOnlyCollection<Response> GetResponses(IEnumerable<Request> fromRequests)
{
var ret = new List<Response>();
foreach (Request r in fromRequests)
{
ret.Add(new Response());
}
return ret.AsReadOnly();
}
//convenience method
public static Response GetResponse(Request fromRequest)
{
return GetResponses(new Request[] {fromRequest})[0];
}
}
Now I want to await long-running operations but I can't quite figure out how to retrofit this methodology for use with TPL:
public class WithAsync
{
public static async Task<ReadOnlyCollection<Response>> GetResponses(IEnumerable<Request> fromRequests)
{
var awaitableResponses = new List<Task<Response>>();
foreach (Request r in fromRequests)
{
awaitableResponses.Add(Task.Run<Response>(async () =>
{
await Task.Delay(10000); //simulate some long running async op.
return new Response();
}));
}
return new List<Response>(await Task.WhenAll(awaitableResponses)).AsReadOnly();
}
//convenience method
public static Task<Response> GetResponse(Request fromRequest)
{
return GetResponse(new Request[] { fromRequest });
}
}
The convenience method above obviously won't work because it's trying to return a Task<ReadOnlyCollection<Response>> when it really needs to return a Task<Response>.
This works:
//convenience method
public static Task<Response> GetResponse(Request fromRequest)
{
return new Task<Response>(new Func<Response>(() => GetResponse(new Request[] { fromRequest }).Result[0]));
}
but it seems really awkward, and more importantly, it blocks on .Result[0] which is potentially on a UI thread.
Is there any good way to accomplish what I'm trying to do?

You're trying to avoid making that "convenience method" async, but there's no reason to do that.
What you want is to call the other method, wait until there are responses and then get the first and only one. You can do that by making it async and using await:
async Task<Response> GetResponseAsync(Request fromRequest)
{
var responses = await GetResponsesAsync(new[] { fromRequest });
return responses.Single();
}
Although a better solution in this specific case is to switch things around and have the single GetResponse actually do that work of a single request, and have the multiple GetRsponses call it instead:
async Task<ReadOnlyCollection<Response>> GetResponsesAsync(IEnumerable<Request> fromRequests)
{
return (await Task.WhenAll(fromRequests.Select(GetResponse))).ToList().AsReadOnly();
}
async Task<Response> GetResponseAsync(Request fromRequest)
{
await Task.Delay(10000); //simulate some long running async op.
return new Response();
}
Notes:
I know it's an example, but there's probably no reason to use Task.Run instead of a simple async call.
The convention is to name async methods with an "Async" suffix (i.e. GetResponseAsync).
I've also pluralized the name of the method that returns a collection.

I'm still sticking with I3arnon's answer because it's a well-written, informative answer, but I'd like to submit my own answer because I realized that I was almost there. Here's the async convenience method I was struggling to find:
//convenience method
public static async Task<Response> GetResponse(Request fromRequest)
{
return (await GetResponses(new Request[] { fromRequest }))[0];
}

Related

Async / Await Pattern. How to pass a await-able method to another method

In my application I need to call a method before all the API request. If a specific condition met then I need to execute set of statements in that method.
In order to generalize this I created a helper class something like this.
public class CertificateValidator {
readonly IDependencyService _serviceLocator;
public CertificateValidator(IDependencyService serviceLocator) {
_serviceLocator = serviceLocator;
}
public async Task <T> TryExecuteWithCertificateValidationAsync <T> (Task <T> operation) {
var service = _serviceLocator.Get <IDeviceService> ();
if (service.CertificateValidationRequired()) {
// My Code.
}
T actualResult = await operation;
return actualResult;
}
}
And In my viewmodel I have done something like this.
public CertificateValidator ValidateCertificate => new CertificateValidator(_serviceLocator);
var response = await ValidateCertificate
.TryExecuteWithCertificateValidationAsync(MyMethodAsync());
private async Task<RequestResult<Response>> MyMethodAsync()
{
// Some code
}
But when I implement like this the execution flow is
First MyMethodAsync() will be called.
And when it reaches the await method it the executes the
TryExecuteWithCertificateValidationAsync method and runs the remaining code there.
And then when it reaches T actualResult = await operation; return
actualResult; the control go back to MyMethodAsync() - await statement.
And my doubt here is,
I need to execute the TryExecuteWithCertificateValidationAsync completely and then followed by MyMethodAsync.
In short as I said early, I need to execute set of code before I call all my API calls. How I can achieve something similar using async an await.
Rather than passing a Task pass a function:
public async Task<T> TryExecuteWithCertificateValidationAsync<T>(Func<Task<T>> operation)
{
var service = _serviceLocator.Get<IDeviceService>();
if (service.CertificateValidationRequired())
{
// My Code.
}
T actualResult = await operation();
return actualResult;
}
var response = await ValidateCertificate
.TryExecuteWithCertificateValidationAsync(MyMethodAsync);
Update as per comment
If the method requires arguments, the types need to be prepended as additional generic arguments to Func:
private async Task<RequestResult<Response>> MyMethodAsync(int i)
{
// Some code
}
public async Task<T> TryExecuteWithCertificateValidationAsync<T>(Func<int, Task<T>> operation) // Add int as second generic argument
{
T actualResult = await operation(1); // Can now be called with an integer
return actualResult;
}

Is it problematic to start a Task in the constructor?

In the Call asynchronous method in constructor? question is no answer that, starts the async Operation in the constructor and store the Task in a member and an awaits it before using the resource:
public class DeviceAccess
{
private readonly Task<Container> containerTask;
public DeviceAccess(Database database)
{
containerTask = GetContainer(database);
}
private async Task<Container> GetContainer(Database database)
{
var conatinerResponse = await database.CreateContainerIfNotExistsAsync("Device");
return conatinerResponse.Container;
}
public async Task<Device> GetDevice(string deviceId)
{
var container = await containerTask;
return await doSomething(container);
}
}
In my case every Operation needs the resource, so I see no advantage to use some lazy loading.
Is it valid to start a async Operation in a constructor or can result this into problems?
The biggest problem I can see here is that [Value]Task[<T>] is an API that enables async, not a promise to be async; just because CreateContainerIfNotExistsAsync is named *Async and returns Task<T> - that doesn't actually mean it is async - it could run synchronously and return a result via Task.FromResult (aka "async over sync"). If you're not concerned about that problem, then fine I guess. But I wonder whether an OpenAsync() method that you call after construction would be more appropriate, i.e.
public class DeviceAccess
{
private Container _container;
public DeviceAccess() {}
public async ValueTask OpenAsync(Database database) {
if (_container == null)
_container = await GetContainerAsync(database);
}
public async Task<Device> GetDeviceAsync(string deviceId)
{
var container = _container ?? throw new InvalidOperationException("not open");
return await doSomething(container); // might be able to inline the "await" here
}
}

c# Writing an async method that doesn't have an await in it

I want to have an async method in my call that would be called by my library consumers with an await. But the internal working of my method, while I need it to run on a separate thread, does not call any other await on it's own.
I just do the work the method is supposed to do and return the type. And the compiler warns me that this method will not run in an async way.
public async Task<MyResultObject> DoSomeWork()
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return result;
}
On the other hand, if I write a method that starts a new task using TaskFactory like this:
public Task<MyResultObject> DoSomeWork()
{
return Task<MyResultObject>.Factory.StartNew(() =>
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return result;
});
}
Then I cannot call it using the await keyword like this await DoSomeWork().
How do I write an async (must be async and not task with result or wait) without using some await call inside?
You can do this
public Task<MyResultObject> DoSomeWork()
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return Task.FromResult(result);
}
which is exactly the same as
public async Task<MyResultObject> DoSomeWork()
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return result;
}
Only this version gives a warning and has slightly more overhead.
But neither will run on another thread. The only benefit is that they have an awaitable interface.
To do it in parallel, your code is Ok but Task.Run is preferred over StartNew():
public Task<MyResultObject> DoSomeWork()
{
return Task.Run(() =>
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return result;
});
}
And in all these cases you can definitely await DoSomeWork()

Async for Long operation with HttpResponseMessage

I am figuring out performance of my C# web api. I wrote a very simple HelloWorld response:
public class HelloWorldController : ApiController
{
public HttpResponseMessage Get()
{
return new HttpResponseMessage()
{
Content = new StringContent("HelloWorld")
};
}
}
I tested by using JMeter I set 1000 Users request and it worked perfectly (CPU usage up to 100%). But the problem is that when the operation of the api take bit longer, the response become worse, got only 3 responses each (CPU usage <7%). It took minuets for 1000 users request.
public HttpResponseMessage Get()
{
Thread.Sleep(1000);
return new HttpResponseMessage()
{
Content = new StringContent("HelloWorld")
};
}
After google I come up with idea of using async but still I got same problem. I don't know what the problem is or my code implementation. Below is my sample implementation.
public async Task<HttpResponseMessage> Get()
{
return new HttpResponseMessage()
{
Content = new StringContent(await LongOperationAsync())
};
}
private string LongOperation()
{
//long operation here
Thread.Sleep(1000);
return "HelloWorld";
}
private Task<string> LongOperationAsync()
{
return Task.Factory.StartNew(() => LongOperation());
}
Anyone know what is the problem or any idea regarding to this problem?
async and await are not magic bullets that just "mak teh codez moah awesomz". On ASP.NET, await enables your application to be more scalable (and respond to changes in scale more quickly) by making optimum use of the thread pool.
So, if you're freeing up a thread pool thread (await) but using up another thread pool thread (StartNew), you're not going to gain anything. In particular, exposing a fake-async method for a synchronous API is an antipattern.
If possible, the best solution is to make LongOperationAsync a naturally-asynchronous operation:
public async Task<HttpResponseMessage> Get()
{
return new HttpResponseMessage()
{
Content = new StringContent(await LongOperationAsync())
};
}
private async Task<string> LongOperationAsync()
{
//long operation here
await Task.Delay(1000);
return "HelloWorld";
}
If this isn't possible, then you may as well keep it synchronous. Using Task.Run (or even worse, StartNew) isn't going to help at all.
The Method LongOperationAsync And LongOperation also should be async :
private async Task<string> LongOperation()
{
//long operation here
await Task.Delay(1000);
return "HelloWorld";
}
private async Task<string> LongOperationAsync()
{
var rt = await Task.Run(() => LongOperation());
return rt;
}
see:
Asynchronous programming

Async Func in C# - correct async await usage

I want to simplify out repository code and want to use Funcs to provide common functionality.
The problem now is based on this code:
namespace Test
{
public class Demo
{
public Task<Person> GetAsync1(Guid id)
{
return ExecuteAsync(context => context.Persons.GetAsync(id));
}
public async Task<Person> GetAsync2(Guid id)
{
return await ExecuteAsync(async context => await context.Persons.GetAsync(id));
}
public Task<Person> GetAsync3(Guid id)
{
return ExecuteAsync(async context => await context.Persons.GetAsync(id));
}
public Task<TOut> ExecuteAsync(Func<Context, Task<TOut>> func)
{
using(var context = new Context())
{
return func(context);
}
}
}
}
The problem here for me is now how to call the async func correctly.
Which of those three Get methods is correct?
With the first one I think I get a deadlock because it hangs at this point. Number 2 works fine but I think two async/awaits here are not correct, because of the Task re-wrapping!?
Actually all 3 GetAsync implmentations where fine to do (personally I would use GetAsync1), what you have is a bug in ExecuteAsync
public async Task<TOut> ExecuteAsync(Func<Context, Task<TOut>> func)
{
using(var context = new Context())
{
return await func(context);
}
}
By awaiting the output of func you do not dispose of the context until the function has completed it's work.

Categories

Resources