NonAsync method going throw Async for single flow calls - c#

I'm creating a .NET Standard library with several methods, each having regular and async version.
So one method for example is:
public static int DoSomethingOne(string value) { ... }
public static async Task<int> DoSomethingOneAsync(string value) { ... }
Now they are doing some string manipulation and also calling DB with EF functions.
Currently I have these methods in complete separate flow but I have seen example of internal methods being joined meaning non async going throw async with if condition and returned with .GetAwaiter().GetResult();
This approach seems more DRY, no double code.
So the question: is that structure valid or should I stick to separate flow?
Also to note that I already have segments of logic in shared methods that are async agnostic, but still some code is doubled, like calls to those shared method and few other lines.
To extend the example:
Currently have:
public static int DoSomethingOne(string value)
{
return DoSomethingOneInternal(value);
}
public static async Task<int> DoSomethingOneAsync(string value, CancellationToken cancellationToken)
{
return await DoSomethingOneInternalAsync(value, cancellationToken).ConfigureAwait(false);
}
private static int DoSomethingOneInternal(string value)
{
var input = DoStringChangeOne(value);
CallDbOne(input);
var output = DoStringChangeTwo(input);
var count = CallDbTwo(output);
return count;
}
private static async Task<int> DoSomethingOneInternalAsync(string value, CancellationToken cancellationToken) { ... }
{
var input = DoStringChangeOne(value);
await CallDbOneAsync(input).ConfigureAwait(false);
var output = DoStringChangeTwo(input);
var count = await CallDbTwoAsync(output).ConfigureAwait(false);
return count;
}
Alternatively could write:
public static int DoSomethingOne(string value)
{
return DoSomethingOneInternalAsync(value, null, isAsync: false).GetAwaiter().GetResult();
}
public static async Task<int> DoSomethingOneAsync(string value, CancellationToken cancellationToken)
{
return await DoSomethingOneInternalAsync(value, cancellationToken, isAsync: true).ConfigureAwait(false);
}
private static int DoSomethingOneInternalAsync(string s, CancellationToken? cancellationToken, bool isAsync)
{
var input = DoStringChangeOne(value);
if(isAsync) {
await CallDbOneAsync(input).ConfigureAwait(false);
}
else {
CallDbOne(input);
}
var output = DoStringChangeTwo(input);
var count = isAsync ? await CallDbTwoAsync(output).ConfigureAwait(false) : CallDbTwo(output);
return count;
}
Now there are around 10 method like this, and they have 2 to 4 depth levels of calls to internal submethods for better structure.
Also to add that async version are 'main' ones and more often used as to why they have direct flow, while nonAsync are not regularly used so they are redirected in option 2.

is that structure valid or should I stick to separate flow?
It's valid. Whether you should use it or not is up to you. The benefits of the "boolean argument hack" is that your code is DRY - in particular, this means that if there's a bugfix applied to one method, then both the synchronous and asynchronous versions always get that bugfix. But if these are relatively small methods, then the extra boilerplate may not be worthwhile.

Related

How can an "async" task return an integer and not a public one?

I just had following piece of code, which did not compile:
public Task<int> Handle
{
var result = <do_something_returning_an_int>();
...
return result;
}
This gives compiler error `cannot implicitly convert type 'int' to 'System.Threading.Thread.Task'.
When I change this into:
async Task<int> Handle
{
var result = <do_something_returning_an_int>();
...
return result;
}
... no compiler error.
I know that async means that the task does not need to wait for the answer to arrive, but what does this have to do with typecasting?
If you're not awaiting anything in your asynchronous method you omit the async keyword and return a Task instead of the result directly.
public Task<int> Handle
{
var result = <do_something_returning_an_int>();
...
return Task.FromResult(result);
}
As far as I can tell, doing that only makes sense if other code strictly expects a Task from your method.
This has of course nothing to do with access modifiers, you can combine async with public or any other access modifier.
I'd also recommend taking a look at the documentation
(By request, promoted from a comment.)
This is by design of the async logic in the C# Language Specification. See the section Async Functions.
You can also read the programming guide, Async return types (C#) ยง Task<TResult>.
The point is that a method without the async keyword, like
public Task<int> HandleAsync()
{
...
Task<int> result = ...;
...
return result;
}
must return what it says it returns, just as with all other types. In this case, you could create a Task<> that can be awaited, in your own manual way, like:
Task<int> result = Task.Run(GetLastDigitOfSmallestTwinPrimeWithMoreThan1000000Digits);
The caller can await the task you return, even if your method is written like above.
But if you use the async keyword, and if your return type is, say, Task<int>, then you must return a plain int, and the C# compiler will write the needed logic for you.
Usually, you would use await somewhere in the body (otherwise, why async). So something like:
public async Task<int> HandleAsync()
{
...
int result = await GetLastDigitOfSmallestTwinPrimeWithMoreThan1000000DigitsAsync();
...
return result;
}
Related question here: Why is it not necessary to return a Task when the signature is public async Task MethodName?
try using task result and then iterate the results
Task<int> Handle
{
return Task.Run(()=>
{
var result = <do_something_returning_an_int>();
...
return result;
}
}
List<Task<int>> tasks = new List<Task<int>>();
tasks.Add(Handle);
Task.WaitAll(tasks.ToArray());
for(int ctr = 0; ctr < tasks.Count; ctr++) {
if (tasks[ctr].Status == TaskStatus.Faulted)
output.WriteLine(" Task fault occurred");
else
{
output.WriteLine("test sent {0}",
tasks[ctr].Result);
Assert.True(true);
}
}
or
Task<int> Handle
{
return Task.FromResult(do_something_returning_an_int);
}

c#: Chain asynchronous methods

I've found a piece of code showing how to chain asynchronous methods. Here is the code:
public static class ExtensionMethod
{
public static async Task<TResult> MapAsync<TSource, TResult>(
this Task<TSource> #this,
Func<TSource, Task<TResult>> fn)
{
return await fn(await #this);
}
}
public partial class Program
{
public async static Task<int> FunctionA
(int a) => await Task.FromResult(a * 1);
public async static Task<int> FunctionB(
int b) => await Task.FromResult(b * 2);
public async static Task<int> FunctionC(
int c) => await Task.FromResult(c * 3);
public async static void AsyncChain()
{
int i = await FunctionC(10)
.MapAsync(FunctionB)
.MapAsync(FunctionA);
Console.WriteLine("The result = {0}", i);
}
}
But I don't understand why inside the extension method MapAsync we have await fn(await #this)?
Can someone explain me this, please?
The reason for this is because in order to get the value of the previous call (in this case the value stored within the Task #this) it must be awaited. Because await is now being used in the method and it must be marked as async, you can now no longer simply return the result from fn because it's a Task. (As I'm sure you are aware, and in very simple terms, marking the method as async means that the method signature sort of ignores the Task and just wants an instance of the generic type as the return or nothing if it's not using the genric version of Task.)
In response to your comment about chaining both sync vs async methods, this approach of using Task would still work for sync methods, you just have to pretend that its async by wrapping the result in a task (which is already marked as completed). Something like this:
public async static Task<int> AsyncFunction(int x)
=> await SomeAsyncMethodThatReturnsTaskOfInt();
public static Task<int> SyncFunction(int x)
=> Task.FromResult(SomeSyncMethodThatReturnsInt());
public async static void AsyncChain()
{
int i = await AsyncFunction(10)
.MapAsync(SyncFunction);
Console.WriteLine("The result = {0}", i);
}
You can remove all the async/awaits from the FunctionA, FunctionB and FunctionC definitions as they can just return the task.
There is a nice article on Eliding await by Stephen Cleary for a better explanation of when you should and shouldn't use await when the only thing the method is doing is returning Task.
Having said all that, Gusman's comment is completely correct that this is total overkill for a fairly simple ContinueWith

How to make async method generic over Task type

My question is on the surface very similar to Using a generic type as a return type of an async method. However, he did not have a real world usage scenario and so all that could be stated is that you can't do that. I understand from Jon Skeet's answer to that question and from the blog post Why must async methods return Task? why it is not supported. The post discusses workarounds, but none of them apply to my use case.
My question is, what is the best way to work around the language limitation given what I am trying to do?
In production code, we had a retry method that takes a Func<Task> and returns Task. We then needed to be able to retry TaskT> functions as well. So we changed the retry method to (slightly simplified):
public static async T Retry<T>(Func<T> action) where T : Task
{
for (var i = 0; ; i++)
{
try
{
return await action();
}
catch (Exception)
{
if (i >= 3)
throw;
}
}
}
The compiler of course reports the error "The return type of an async method must be void, Task or Task". Can I make Retry work with both Task and Task<T> without writing two copies of the method?
No, async just doesn't support that. The simplest option to fake it would be:
public static async Task<T> Retry<T>(Func<Task<T>> action)
{
for (var i = 0; ; i++)
{
try
{
return await action();
}
catch (Exception)
{
if (i >= 3)
throw;
}
}
}
public static async Task Retry(Func<Task> action)
{
Func<Task<int>> d = async () => { await action(); return 0; };
await Retry(d);
}
That doesn't involve code duplication, but you do end up with an awful lot of layers of tasks on top of each other when you call the non-generic version. You could change the latter to:
public static Task Retry(Func<Task> action)
{
Func<Task<int>> d = async () => { await action(); return 0; };
return Retry(d);
}
Then it will actually return a Task<int>, but assuming your callers don't care, it does save one bit of redirection.

What's the best way to wrap a Task as a Task<TResult>

I am writing some async helper methods and I have APIs to support both Task and Task<T>. To re-use code, I'd like the Task-based API to wrap the given task as a Task<T> and just call through to the Task<T> API.
One way I can do this is:
private static async Task<bool> Convert(this Task #this)
{
await #this.ConfigureAwait(false);
return false;
}
However, I'm wondering: is there there is a better/builtin way to do this?
There is no existing Task method that does exactly this, no. Your method is fine, and is likely about as simple as you'll be able to get.
Implementing the proper error propagating/cancellation semantics using any other method is deceptively hard.
Updated, the following propagates exceptions and cancellation:
public static class TaskExt
{
public static Task<Empty> AsGeneric(this Task #this)
{
return #this.IsCompleted ?
CompletedAsGeneric(#this) :
#this.ContinueWith<Task<Empty>>(CompletedAsGeneric,
TaskContinuationOptions.ExecuteSynchronously).Unwrap();
}
static Task<Empty> CompletedAsGeneric(Task completedTask)
{
try
{
if (completedTask.Status != TaskStatus.RanToCompletion)
// propagate exceptions
completedTask.GetAwaiter().GetResult();
// return completed task
return Task.FromResult(Empty.Value);
}
catch (OperationCanceledException ex)
{
// propagate cancellation
if (completedTask.IsCanceled)
// return cancelled task
return new Task<Empty>(() => Empty.Value, ex.CancellationToken);
throw;
}
}
}
public struct Empty
{
public static readonly Empty Value = default(Empty);
}
I've had the same requirement recently and I solved it with my own helper extension method, which allows the user to effectively wrap a Task with a Task<T>:
public static async Task<TResult> WithCompletionResult<TResult>(
this Task sourceTask,
TResult result
)
{
await sourceTask;
return result;
}
In your example call with:
Task<bool> task = myTask.WithCompletionResult<bool>(false);
If the result of Task<T> does not matter, I will use:
Task<object> task = myTask.WithCompletionResult<object>(null);
I hope this helps. If anyone knows of a pitfall with this approach let me know!
Using await seems a bit overkill here. No need for the state machine here, just use a ContinueWith
private static Task<bool> Convert(this Task #this)
{
return #this.ContinueWith(p => { p.Wait(); return false;});
}
Note: This will result in an AggregateException being wrapped unfortunately

Converting an async method to return IObservable<>

I have an async method that is a long-running method that reads a stream and when it finds something fires an event:
public static async void GetStream(int id, CancellationToken token)
It takes a cancellation token because it is create in a new task. Internally it calls await when it reads a stream:
var result = await sr.ReadLineAsync()
Now, I want to convert this to a method that returns an IObservable<> so that I can use this with the reactive extensions. From what I've read, the best way to do this is using Observable.Create, and since RX 2.0 now also supports async I can get it all to work with something like this:
public static IObservable<Message> ObservableStream(int id, CancellationToken token)
{
return Observable.Create<Message>(
async (IObserver<Message> observer) =>
{
The rest of the code inside is the same, but instead of firing events I'm calling observer.OnNext(). But, this feels wrong. For one thing I'm mixing CancellationTokens up in there, and although adding the async keyword made it work, is this actually the best thing to do? I'm calling my ObservableStream like this:
Client.ObservableStream(555404, token).ObserveOn(Dispatcher.CurrentDispatcher).SubscribeOn(TaskPoolScheduler.Default).Subscribe(m => Messages.Add(m));
You are correct. Once you represent your interface through an IObservable, you should avoid requiring the callers to supply a CancellationToken. That doesn't mean you cannot use them internally. Rx provides several mechanisms to produce CancellationToken instances which are canceled when the observer unsubscribes from your observable.
There are a number of ways to tackle your problem. The simplest requires almost no changes in your code. It uses an overload of Observable.Create which supplies you with a CancellationToken that triggers if the caller unsubscribes:
public static IObservable<Message> ObservableStream(int id)
{
return Observable.Create<Message>(async (observer, token) =>
{
// no exception handling required. If this method throws,
// Rx will catch it and call observer.OnError() for us.
using (var stream = /*...open your stream...*/)
{
string msg;
while ((msg = await stream.ReadLineAsync()) != null)
{
if (token.IsCancellationRequested) { return; }
observer.OnNext(msg);
}
observer.OnCompleted();
}
});
}
You should change GetStream to return a Task, instead of void (returning async void is not good, except when absolutely required, as svick commented). Once you return a Task, you can just call .ToObservable() and you are done.
For example:
public static async Task<int> GetStream(int id, CancellationToken token) { ... }
Then,
GetStream(1, new CancellationToken(false))
.ToObservable()
.Subscribe(Console.Write);

Categories

Resources