C# Async/Await: Leave AsyncLocal<T> context upon task creation

Viewed 2517

AsyncLocal allows us to keep context data on a async control flow. This is pretty neat since all following resumes (even on another thread) can retrieve and modify the ambient data (AsyncLocal on MSDN).

Is there any way to 'leave' the current async local context for a sub-task and thus create a new one?

AsyncLocal<string> Data = new AsyncLocal<string>();
Data.Value = "One";

Task.Factory.StartNew( () =>
{
    string InnerValue = Data.Value;
    //InnerValue equals to "One", I need it to be null.
} );

In the example above, the inner task shares the AsyncLocal context with the outer control flow. Is there any way to enforce a new context?

Update: in order to solve my issue here, the following worked like a charm (despite the fact that it didn't entirely reset the context):

AsyncLocal<string> Data = new AsyncLocal<string>();
Data.Value = "One";

Task.Factory.StartNew( () =>
{
    Data.Value = null;
    string InnerValue = Data.Value;
    //InnerValue equals to null now.
} );

string OuterValue = Data.Value; //Stays "one" even after the inner change.
2 Answers

You can use ExecutionContext.SuppressFlow:

AsyncLocal<string> Data = new AsyncLocal<string>();
Data.Value = "One";

using (ExecutionContext.SuppressFlow())
{    
    Task.Factory.StartNew( () =>
    {
        string InnerValue = Data.Value;
        //InnerValue is null.
    } );
}

Note that this may have side-effects, such as no longer producing proper stack traces. However, since you ignore the result of StartNew, i.e. you seem to not be interested in actually having a flow, this would be the correct thing to do.

Alternatively, and more in line with the solution in your own update, remember that AsyncLocal is scoped, i.e. if you set the value in a nested async operation, it does not affect the value in your outer function. This means that you can reset AsyncLocals first thing in the nested operation without destroying the values for the outer operation.

Related