Consider the following code:
private static async Task Main(string[] args)
{
    await SetValueInAsyncMethod();
    PrintValue();
    await SetValueInNonAsyncMethod();
    PrintValue();
}
private static readonly AsyncLocal<int> asyncLocal = new AsyncLocal<int>();
private static void PrintValue([CallerMemberName] string callingMemberName = "")
{
    Console.WriteLine($"{callingMemberName}: {asyncLocal.Value}");
}
private static async Task SetValueInAsyncMethod()
{
    asyncLocal.Value = 1;
    PrintValue();
    await Task.CompletedTask;
}
private static Task SetValueInNonAsyncMethod()
{
    asyncLocal.Value = 2;
    PrintValue();
    return Task.CompletedTask;
}
If you run this code inside a .NET 4.7.2 console application, you will get the following output:
SetValueInAsyncMethod: 1
Main: 0
SetValueInNonAsyncMethod: 2
Main: 2
I do understand that the differences in the output arise from the fact that SetValueInAsyncMethod is not really a method, but a state machine executed by AsyncTaskMethodBuilder which captures ExecutionContext internally and SetValueInNonAsyncMethod is just a regular method. 
But even with this understanding in mind I still have some questions:
- Is this a bug / missing feature or an intentional design decision?
- Do I need to worry about this behavior while writing code that depends on AsyncLocal? Say, I want to write myTransactionScope-wannabe that flows some ambient data though await points. IsAsyncLocalenough here?
- Are there any other alternatives to AsyncLocalandCallContext.LogicalGetData/CallContext.LogicalSetDatain .NET when it comes down to preserving values throughout the "logical code flow"?
 
     
    