Use object indirection in HttpContextAccessor (#1066)
This commit is contained in:
parent
ea1ee2b68c
commit
49d785c934
|
|
@ -7,21 +7,35 @@ namespace Microsoft.AspNetCore.Http
|
|||
{
|
||||
public class HttpContextAccessor : IHttpContextAccessor
|
||||
{
|
||||
private static AsyncLocal<(string traceIdentifier, HttpContext context)> _httpContextCurrent = new AsyncLocal<(string traceIdentifier, HttpContext context)>();
|
||||
private static AsyncLocal<HttpContextHolder> _httpContextCurrent = new AsyncLocal<HttpContextHolder>();
|
||||
|
||||
public HttpContext HttpContext
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = _httpContextCurrent.Value;
|
||||
// Only return the context if the stored request id matches the stored trace identifier
|
||||
// context.TraceIdentifier is cleared by HttpContextFactory.Dispose.
|
||||
return value.traceIdentifier == value.context?.TraceIdentifier ? value.context : null;
|
||||
return _httpContextCurrent.Value?.Context;
|
||||
}
|
||||
set
|
||||
{
|
||||
_httpContextCurrent.Value = (value?.TraceIdentifier, value);
|
||||
var holder = _httpContextCurrent.Value;
|
||||
if (holder != null)
|
||||
{
|
||||
// Clear current HttpContext trapped in the AsyncLocals, as its done.
|
||||
holder.Context = null;
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
// Use an object indirection to hold the HttpContext in the AsyncLocal,
|
||||
// so it can be cleared in all ExecutionContexts when its cleared.
|
||||
_httpContextCurrent.Value = new HttpContextHolder { Context = value };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class HttpContextHolder
|
||||
{
|
||||
public HttpContext Context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,10 +53,6 @@ namespace Microsoft.AspNetCore.Http
|
|||
{
|
||||
_httpContextAccessor.HttpContext = null;
|
||||
}
|
||||
|
||||
// Null out the TraceIdentifier here as a sign that this request is done,
|
||||
// the HttpContextAccessor implementation relies on this to detect that the request is over
|
||||
httpContext.TraceIdentifier = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,7 +44,6 @@ namespace Microsoft.AspNetCore.Http
|
|||
var accessor = new HttpContextAccessor();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
context.TraceIdentifier = "1";
|
||||
accessor.HttpContext = context;
|
||||
|
||||
var checkAsyncFlowTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
|
@ -76,7 +75,6 @@ namespace Microsoft.AspNetCore.Http
|
|||
|
||||
// Null out the accessor
|
||||
accessor.HttpContext = null;
|
||||
context.TraceIdentifier = null;
|
||||
|
||||
waitForNullTcs.SetResult(null);
|
||||
|
||||
|
|
@ -86,12 +84,11 @@ namespace Microsoft.AspNetCore.Http
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HttpContextAccessor_GettingHttpContextReturnsNullHttpContextIfDifferentTraceIdentifier()
|
||||
public async Task HttpContextAccessor_GettingHttpContextReturnsNullHttpContextIfChanged()
|
||||
{
|
||||
var accessor = new HttpContextAccessor();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
context.TraceIdentifier = "1";
|
||||
accessor.HttpContext = context;
|
||||
|
||||
var checkAsyncFlowTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
|
@ -121,12 +118,8 @@ namespace Microsoft.AspNetCore.Http
|
|||
|
||||
await checkAsyncFlowTcs.Task;
|
||||
|
||||
// Reset the trace identifier on the first request
|
||||
context.TraceIdentifier = null;
|
||||
|
||||
// Set a new http context
|
||||
var context2 = new DefaultHttpContext();
|
||||
context2.TraceIdentifier = "2";
|
||||
accessor.HttpContext = context2;
|
||||
|
||||
waitForNullTcs.SetResult(null);
|
||||
|
|
@ -142,7 +135,6 @@ namespace Microsoft.AspNetCore.Http
|
|||
var accessor = new HttpContextAccessor();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
context.TraceIdentifier = "1";
|
||||
accessor.HttpContext = context;
|
||||
|
||||
var checkAsyncFlowTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
|
@ -172,7 +164,6 @@ namespace Microsoft.AspNetCore.Http
|
|||
var accessor = new HttpContextAccessor();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
context.TraceIdentifier = "1";
|
||||
accessor.HttpContext = context;
|
||||
|
||||
var checkAsyncFlowTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ namespace Microsoft.AspNetCore.Http
|
|||
|
||||
// Act
|
||||
var context = contextFactory.Create(new FeatureCollection());
|
||||
var traceIdentifier = context.TraceIdentifier;
|
||||
|
||||
// Assert
|
||||
Assert.Same(context, accessor.HttpContext);
|
||||
|
|
@ -42,7 +41,6 @@ namespace Microsoft.AspNetCore.Http
|
|||
contextFactory.Dispose(context);
|
||||
|
||||
Assert.Null(accessor.HttpContext);
|
||||
Assert.NotEqual(traceIdentifier, context.TraceIdentifier);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Reference in New Issue