I would like to work with dotnet async Main method, having the following signature:
static async Task Main(string[] args) {
var parser = new Parser();
var parserResult = parser.ParseArguments<Options>(args);
var mainAsync = new MainAsync();
parserResult.WithParsed<Options>(async options => await mainAsync.Run(options).ConfigureAwait());
}
Run is defined like:
public async Task Run(Options options)
{
...
}
Problem is, my async methods behave strangely. They may work but can also simply terminate my program. It would seem I am doing something wrong, but I can't figure out what it is.
If I do this instead, there doesn't seem to be any problems, but I lose my async main method and some other stuff I have needs to be rewritten.
static void Main(string[] args) {
var parser = new Parser();
var parserResult = parser.ParseArguments<Options>(args);
var mainAsync = new MainAsync();
parserResult.WithParsed<Options>(options => mainAsync.Run(options).GetAwaiter().GetResult());
}
Why does the top-most Main fail in strange way and bottom one just works? Is CommandLineParser not async compatible?
MapResult is supporting async/await but WithParsed is not supporting async/await.
See example in wiki for async/await with live demo.
Hey @moh-hassan, the linked example doesn't seem to work when the Task doesn't return anything.
Example
static async Task RunAndReturnExitCodeAsync(Options options)
{
Console.WriteLine("Hello");
await Task.Delay(200); //simulate async method
Console.WriteLine("World");
}
Calling it in Main() as:
Console.WriteLine("Start");
var result = Parser.Default.ParseArguments<Options>(args)
.MapResult(async options => await RunAndReturnExitCodeAsync(options), _ => Task.FromResult(1));
Console.WriteLine("Finish");
The Thread is not awaited in the RunAndReturnExitCodeAsync function.
Am I doing something wrong?
I think result.Wait() solves the problem, and this would be the correct way of doing it?
@anas2204
MapResult is Func not Action, so you should use Task<T>. Use return value.
In v 2.8 you can use Task with WithParsedAsync.
Avoid using Wait in async/await context.
@moh-hassan Thanks for the update to the library!
I tried the example given here, and it seems to exit after printing "Before Task".
Isn't calling ".Result" or ".Wait()" same in the context of async/await?
If you tried the demo here, you get the result as expected:
output:
Starting async/await method
Before async/await
UserId=root
After async/await
Can you confirm this result?
Isn't calling ".Result" or ".Wait()" same in the context of async/await?
Wait() cause Deadlocks in your application.
Can you confirm this result?
For me, running the example on a .NET Core 3.1 Console application, I get this output:
Starting async/await method
Before async/await
Wait() cause Deadlocks in your application.
Is there a case for Deadlock in a Console application?
Also, in the sample you linked, shouldn't the Main() also have "async"?
shouldn't the Main() also have "async"?
Yes, it should have since c#7.1
I modified dotnetfiddle demo to run in NetCore 3.1 and it's working fine and also in vs 2019.
Note async in Main and await for MapResult and WithParsedAsync using a method group for lambda expression.
public static async Task<int> Main(string[] args)
{
int ret =await Parser.Default.ParseArguments<Options>(args)
.MapResult( RunAndReturnExitCodeAsync, _ => Task.FromResult(1));
Console.WriteLine($"retCode={ret}");
return ret;
}
Demo MapResult
WithParsedAsync:
public static async Task Main(string[] args)
{
await Parser.Default.ParseArguments<Options>(args)
.WithParsedAsync(RunAsync);
}
Thanks for the prompt reply @moh-hassan, this works great!