diff --git a/src/Microsoft.AspNet.Hosting/HostingEngine.cs b/src/Microsoft.AspNet.Hosting/HostingEngine.cs index 0dc426b1a4..83ef3a8d8e 100644 --- a/src/Microsoft.AspNet.Hosting/HostingEngine.cs +++ b/src/Microsoft.AspNet.Hosting/HostingEngine.cs @@ -16,17 +16,20 @@ namespace Microsoft.AspNet.Hosting private readonly IStartupManager _startupManager; private readonly IApplicationBuilderFactory _builderFactory; private readonly IHttpContextFactory _httpContextFactory; + private readonly IHttpContextAccessor _contextAccessor; public HostingEngine( IServerManager serverManager, IStartupManager startupManager, IApplicationBuilderFactory builderFactory, - IHttpContextFactory httpContextFactory) + IHttpContextFactory httpContextFactory, + IHttpContextAccessor contextAccessor) { _serverManager = serverManager; _startupManager = startupManager; _builderFactory = builderFactory; _httpContextFactory = httpContextFactory; + _contextAccessor = contextAccessor; } public IDisposable Start(HostingContext context) @@ -37,7 +40,7 @@ namespace Microsoft.AspNet.Hosting EnsureApplicationDelegate(context); var applicationLifetime = (ApplicationLifetime)context.Services.GetRequiredService(); - var pipeline = new PipelineInstance(_httpContextFactory, context.ApplicationDelegate); + var pipeline = new PipelineInstance(_httpContextFactory, context.ApplicationDelegate, _contextAccessor); var server = context.ServerFactory.Start(context.Server, pipeline.Invoke); return new Disposable(() => diff --git a/src/Microsoft.AspNet.Hosting/HostingServicesCollectionExtensions.cs b/src/Microsoft.AspNet.Hosting/HostingServicesCollectionExtensions.cs index 5122ca73da..82c134ffb2 100644 --- a/src/Microsoft.AspNet.Hosting/HostingServicesCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Hosting/HostingServicesCollectionExtensions.cs @@ -39,7 +39,7 @@ namespace Microsoft.Framework.DependencyInjection // TODO: Do we expect this to be provide by the runtime eventually? services.AddLogging(configuration); services.TryAdd(describer.Singleton()); - services.TryAdd(describer.Scoped()); + services.TryAdd(describer.Singleton()); // REVIEW: don't try add because we pull out IEnumerable? services.AddInstance(new ConfigureHostingEnvironment(configuration)); diff --git a/src/Microsoft.AspNet.Hosting/HttpContextAccessor.cs b/src/Microsoft.AspNet.Hosting/HttpContextAccessor.cs index c811d4bfef..4507d384cf 100644 --- a/src/Microsoft.AspNet.Hosting/HttpContextAccessor.cs +++ b/src/Microsoft.AspNet.Hosting/HttpContextAccessor.cs @@ -14,60 +14,35 @@ namespace Microsoft.AspNet.Hosting { public class HttpContextAccessor : IHttpContextAccessor { - private HttpContext _value; - - public bool IsRootContext { get; set; } +#if ASPNET50 + private const string LogicalDataKey = "__HttpContext_Current__"; public HttpContext Value { get { - return IsRootContext ? AccessRootHttpContext() : _value; + var handle = CallContext.LogicalGetData(LogicalDataKey) as ObjectHandle; + return handle != null ? handle.Unwrap() as HttpContext : null; } - } - - public HttpContext SetValue(HttpContext value) - { - if (IsRootContext) + set { - return ExchangeRootHttpContext(value); + CallContext.LogicalSetData(LogicalDataKey, new ObjectHandle(value)); } - var prior = _value; - _value = value; - return prior; } -#if ASPNET50 - private const string LogicalDataKey = "__HttpContext_Current__"; #elif ASPNETCORE50 - private static AsyncLocal _httpContextCurrent = new AsyncLocal(); -#endif - - private static HttpContext AccessRootHttpContext() + private AsyncLocal _httpContextCurrent = new AsyncLocal(); + public HttpContext Value { -#if ASPNET50 - var handle = CallContext.LogicalGetData(LogicalDataKey) as ObjectHandle; - return handle != null ? handle.Unwrap() as HttpContext : null; -#elif ASPNETCORE50 - return _httpContextCurrent.Value; -#else - throw new Exception("TODO: CallContext not available"); -#endif + get + { + return _httpContextCurrent.Value; + } + set + { + _httpContextCurrent.Value = value; + } } - - private static HttpContext ExchangeRootHttpContext(HttpContext httpContext) - { -#if ASPNET50 - var prior = CallContext.LogicalGetData(LogicalDataKey) as ObjectHandle; - CallContext.LogicalSetData(LogicalDataKey, new ObjectHandle(httpContext)); - return prior != null ? prior.Unwrap() as HttpContext : null; -#elif ASPNETCORE50 - var prior = _httpContextCurrent.Value; - _httpContextCurrent.Value = httpContext; - return prior; -#else - return null; #endif - } } -} \ No newline at end of file +} diff --git a/src/Microsoft.AspNet.Hosting/IHttpContextAccessor.cs b/src/Microsoft.AspNet.Hosting/IHttpContextAccessor.cs index 01656f4cd7..563808d7f8 100644 --- a/src/Microsoft.AspNet.Hosting/IHttpContextAccessor.cs +++ b/src/Microsoft.AspNet.Hosting/IHttpContextAccessor.cs @@ -7,9 +7,6 @@ namespace Microsoft.AspNet.Hosting { public interface IHttpContextAccessor { - bool IsRootContext { get; set; } - HttpContext Value { get; } - - HttpContext SetValue(HttpContext value); + HttpContext Value { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/PipelineInstance.cs b/src/Microsoft.AspNet.Hosting/PipelineInstance.cs index 2efe3d6b24..d69a700c94 100644 --- a/src/Microsoft.AspNet.Hosting/PipelineInstance.cs +++ b/src/Microsoft.AspNet.Hosting/PipelineInstance.cs @@ -4,9 +4,7 @@ using System; using System.Threading.Tasks; using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Http; using Microsoft.AspNet.Hosting.Builder; -using Microsoft.AspNet.Hosting.Server; namespace Microsoft.AspNet.Hosting { @@ -14,16 +12,19 @@ namespace Microsoft.AspNet.Hosting { private readonly IHttpContextFactory _httpContextFactory; private readonly RequestDelegate _requestDelegate; + private readonly IHttpContextAccessor _contextAccessor; - public PipelineInstance(IHttpContextFactory httpContextFactory, RequestDelegate requestDelegate) + public PipelineInstance(IHttpContextFactory httpContextFactory, RequestDelegate requestDelegate, IHttpContextAccessor contextAccessor) { _httpContextFactory = httpContextFactory; _requestDelegate = requestDelegate; + _contextAccessor = contextAccessor; } public Task Invoke(object serverEnvironment) { var httpContext = _httpContextFactory.CreateHttpContext(serverEnvironment); + _contextAccessor.Value = httpContext; return _requestDelegate(httpContext); } diff --git a/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs b/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs index 8b3d32316d..747aae5012 100644 --- a/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs +++ b/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; using Microsoft.Framework.DependencyInjection; @@ -13,7 +12,6 @@ namespace Microsoft.AspNet.RequestContainer public RequestServicesContainer( HttpContext context, IServiceScopeFactory scopeFactory, - IHttpContextAccessor appContextAccessor, IServiceProvider appServiceProvider) { if (scopeFactory == null) @@ -24,12 +22,6 @@ namespace Microsoft.AspNet.RequestContainer { throw new ArgumentNullException(nameof(context)); } - if (appContextAccessor == null) - { - throw new ArgumentNullException(nameof(appContextAccessor)); - } - - AppContextAccessor = appContextAccessor; Context = context; PriorAppServices = context.ApplicationServices; @@ -37,23 +29,15 @@ namespace Microsoft.AspNet.RequestContainer // Begin the scope Scope = scopeFactory.CreateScope(); - ScopeContextAccessor = Scope.ServiceProvider.GetRequiredService(); Context.ApplicationServices = appServiceProvider; Context.RequestServices = Scope.ServiceProvider; - - PriorAppHttpContext = AppContextAccessor.SetValue(context); - PriorScopeHttpContext = ScopeContextAccessor.SetValue(context); } private HttpContext Context { get; set; } private IServiceProvider PriorAppServices { get; set; } private IServiceProvider PriorRequestServices { get; set; } - private HttpContext PriorAppHttpContext { get; set; } - private HttpContext PriorScopeHttpContext { get; set; } private IServiceScope Scope { get; set; } - private IHttpContextAccessor ScopeContextAccessor { get; set; } - private IHttpContextAccessor AppContextAccessor { get; set; } // CONSIDER: this could be an extension method on HttpContext instead @@ -73,29 +57,24 @@ namespace Microsoft.AspNet.RequestContainer // Matches constructor of RequestContainer var rootServiceProvider = serviceProvider.GetRequiredService(); - var rootHttpContextAccessor = serviceProvider.GetRequiredService(); var rootServiceScopeFactory = serviceProvider.GetRequiredService(); - rootHttpContextAccessor.IsRootContext = true; - // Pre Scope setup var priorApplicationServices = serviceProvider; var priorRequestServices = serviceProvider; var appServiceProvider = rootServiceProvider; var appServiceScopeFactory = rootServiceScopeFactory; - var appHttpContextAccessor = rootHttpContextAccessor; if (priorApplicationServices != null && priorApplicationServices != appServiceProvider) { appServiceProvider = priorApplicationServices; appServiceScopeFactory = priorApplicationServices.GetRequiredService(); - appHttpContextAccessor = priorApplicationServices.GetRequiredService(); } // Creates the scope and does the service swaps - return new RequestServicesContainer(httpContext, appServiceScopeFactory, appHttpContextAccessor, appServiceProvider); + return new RequestServicesContainer(httpContext, appServiceScopeFactory, appServiceProvider); } #region IDisposable Support @@ -107,9 +86,6 @@ namespace Microsoft.AspNet.RequestContainer { if (disposing) { - ScopeContextAccessor.SetValue(PriorScopeHttpContext); - AppContextAccessor.SetValue(PriorAppHttpContext); - Context.RequestServices = PriorRequestServices; Context.ApplicationServices = PriorAppServices; } @@ -123,10 +99,6 @@ namespace Microsoft.AspNet.RequestContainer Context = null; PriorAppServices = null; PriorRequestServices = null; - ScopeContextAccessor = null; - AppContextAccessor = null; - PriorAppHttpContext = null; - PriorScopeHttpContext = null; disposedValue = true; } diff --git a/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs b/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs index 47cd1d1403..0a31db1b21 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs +++ b/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs @@ -37,6 +37,23 @@ namespace Microsoft.AspNet.TestHost Assert.Throws(() => TestServer.Create(services, new Startup().Configuration)); } + [Fact] + public async Task CanAccessHttpContext() + { + var services = new ServiceCollection().BuildServiceProvider(); + TestServer server = TestServer.Create(app => + { + app.Run(context => + { + var accessor = app.ApplicationServices.GetRequiredService(); + return context.Response.WriteAsync("HasContext:"+(accessor.Value != null)); + }); + }); + + string result = await server.CreateClient().GetStringAsync("/path"); + Assert.Equal("HasContext:True", result); + } + [Fact] public async Task CreateInvokesApp() {