I have a webapi with a custom execution context set on the request pipeline using a middleware something like this:
public async Task Invoke(HttpContext httpContext)
{
using (Context.With(new TokenContext("token")))
{
await _next(httpContext);
}
}
And the Context-manager looks a bit like this with a stack of IContext objects that are local to the current thread (and the threads it create).
public static class Context
{
private static AsyncLocal<Stack<IContext>> _current = new AsyncLocal<Stack<IContext>>();
public static IContext Current
{
get
{
return _current.Value != null && _current.Value.Count > 0 ?_current.Value.Peek() : null;
}
}
public static IDisposable With(IContext context)
{
Assert.IsNotNull(context);
if (_current.Value == null) _current.Value = new Stack<IContext>();
_current.Value.Push(context);
return new DelegateDisposable(() =>
{
_current.Value.Pop();
});
}
}
The problem I experience is when having multiple requests going on at the same time. Sometimes I get issues with the current context not being what I expected. I have noticed that the current context sometimes have a value already before I set it with the using-statement. My conclusion is that the initial thread used for the request is returned to a thread pool when hitting the await _next line and that this thread is/can be reused for following requests, which sometimes happen before "child-threads" have completed. This leaves me with a lot of unpredictable behavior.
So, my question: How can I tweak this so that I don't run into this issue? Can I force the request-pipeline to not return threads before all "child-threads" have completed? Will this be inefficient? Can I force the "mother-thread" to clean up it's reference to the context-stack before it returns itself to the pool?
Any other options?