Quellcode durchsuchen

Use object indirection in HttpContextAccessor (#1066) (#6036)

John Luo vor 7 Jahren
Ursprung
Commit
38c0d5a50c

+ 1 - 0
eng/PatchConfig.props

@@ -29,6 +29,7 @@ Later on, this will be checked using this condition:
     <PackagesInPatch>
       @aspnet/signalr;
       Microsoft.AspNetCore.Authentication.Google;
+      Microsoft.AspNetCore.Http;
     </PackagesInPatch>
   </PropertyGroup>
 

+ 20 - 6
src/Http/Http/src/HttpContextAccessor.cs

@@ -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;
+        }
     }
 }

+ 0 - 4
src/Http/Http/src/HttpContextFactory.cs

@@ -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;
         }
     }
 }

+ 1 - 10
src/Http/Http/test/HttpContextAccessorTests.cs

@@ -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);

+ 0 - 2
src/Http/Http/test/HttpContextFactoryTests.cs

@@ -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]