diff --git a/README.md b/README.md index 1dbf89ce85..8bf71cfc4d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Hosting ======= -The Hosting repo contains code required to host an ASP.NET vNext application, it is the entry point used when self-hosting an application. +The Hosting repo contains code required to host an ASP.NET 5 application, it is the entry point used when self-hosting an application. -This project is part of ASP.NET vNext. You can find samples, documentation and getting started instructions for ASP.NET vNext at the [Home](https://github.com/aspnet/home) repo. +This project is part of ASP.NET 5. You can find samples, documentation and getting started instructions for ASP.NET 5 at the [Home](https://github.com/aspnet/home) repo. diff --git a/build.cmd b/build.cmd index 86ca5bbbf1..220a1ff561 100644 --- a/build.cmd +++ b/build.cmd @@ -19,10 +19,10 @@ IF EXIST packages\KoreBuild goto run .nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion -IF "%SKIP_KRE_INSTALL%"=="1" goto run -CALL packages\KoreBuild\build\kvm upgrade -runtime CLR -x86 -CALL packages\KoreBuild\build\kvm install default -runtime CoreCLR -x86 +IF "%SKIP_DOTNET_INSTALL%"=="1" goto run +CALL packages\KoreBuild\build\dotnetsdk upgrade -runtime CLR -x86 +CALL packages\KoreBuild\build\dotnetsdk install default -runtime CoreCLR -x86 :run -CALL packages\KoreBuild\build\kvm use default -runtime CLR -x86 +CALL packages\KoreBuild\build\dotnetsdk use default -runtime CLR -x86 packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* diff --git a/build.sh b/build.sh index c7873ef58e..350d7e389a 100755 --- a/build.sh +++ b/build.sh @@ -28,11 +28,11 @@ if test ! -d packages/KoreBuild; then fi if ! type k > /dev/null 2>&1; then - source packages/KoreBuild/build/kvm.sh + source packages/KoreBuild/build/dotnetsdk.sh fi if ! type k > /dev/null 2>&1; then - kvm upgrade + dotnetsdk upgrade fi mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" diff --git a/src/Microsoft.AspNet.Hosting/Builder/HttpContextFactory.cs b/src/Microsoft.AspNet.Hosting/Builder/HttpContextFactory.cs index 1b01ed6b17..227d7bd2f4 100644 --- a/src/Microsoft.AspNet.Hosting/Builder/HttpContextFactory.cs +++ b/src/Microsoft.AspNet.Hosting/Builder/HttpContextFactory.cs @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNet.Http; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Core; namespace Microsoft.AspNet.Hosting.Builder { diff --git a/src/Microsoft.AspNet.Hosting/ConfigureHostingEnvironment.cs b/src/Microsoft.AspNet.Hosting/ConfigureHostingEnvironment.cs index 420b731122..a714c2cfef 100644 --- a/src/Microsoft.AspNet.Hosting/ConfigureHostingEnvironment.cs +++ b/src/Microsoft.AspNet.Hosting/ConfigureHostingEnvironment.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNet.Hosting internal class ConfigureHostingEnvironment : IConfigureHostingEnvironment { private IConfiguration _config; - private const string EnvironmentKey = "KRE_ENV"; + private const string EnvironmentKey = "ASPNET_ENV"; public ConfigureHostingEnvironment(IConfiguration config) { 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/HostingEnvironment.cs b/src/Microsoft.AspNet.Hosting/HostingEnvironment.cs index 181aa6aac8..47d805f99b 100644 --- a/src/Microsoft.AspNet.Hosting/HostingEnvironment.cs +++ b/src/Microsoft.AspNet.Hosting/HostingEnvironment.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using Microsoft.AspNet.FileSystems; +using Microsoft.AspNet.FileProviders; using Microsoft.Framework.Runtime; namespace Microsoft.AspNet.Hosting @@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Hosting { EnvironmentName = DefaultEnvironmentName; WebRoot = HostingUtilities.GetWebRoot(appEnvironment.ApplicationBasePath); - WebRootFileSystem = new PhysicalFileSystem(WebRoot); + WebRootFileProvider = new PhysicalFileProvider(WebRoot); foreach (var configure in configures) { configure.Configure(this); @@ -26,6 +26,6 @@ namespace Microsoft.AspNet.Hosting public string WebRoot { get; private set; } - public IFileSystem WebRootFileSystem { get; set; } + public IFileProvider WebRootFileProvider { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/HostingServices.cs b/src/Microsoft.AspNet.Hosting/HostingServices.cs index 3ff28e403f..b717bb7050 100644 --- a/src/Microsoft.AspNet.Hosting/HostingServices.cs +++ b/src/Microsoft.AspNet.Hosting/HostingServices.cs @@ -45,7 +45,7 @@ namespace Microsoft.AspNet.Hosting public HostingManifest(IServiceProvider fallback) { var manifest = fallback.GetRequiredService(); - Services = new Type[] { typeof(ITypeActivator), typeof(IHostingEnvironment), typeof(ILoggerFactory) } + Services = new Type[] { typeof(ITypeActivator), typeof(IHostingEnvironment), typeof(ILoggerFactory), typeof(IHttpContextAccessor) } .Concat(manifest.Services).Distinct(); } diff --git a/src/Microsoft.AspNet.Hosting/HostingServicesCollectionExtensions.cs b/src/Microsoft.AspNet.Hosting/HostingServicesCollectionExtensions.cs index ac661999b2..82c134ffb2 100644 --- a/src/Microsoft.AspNet.Hosting/HostingServicesCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Hosting/HostingServicesCollectionExtensions.cs @@ -38,11 +38,8 @@ namespace Microsoft.Framework.DependencyInjection services.AddTypeActivator(configuration); // TODO: Do we expect this to be provide by the runtime eventually? services.AddLogging(configuration); - // REVIEW: okay to use existing hosting environment/httpcontext if specified? services.TryAdd(describer.Singleton()); - - // TODO: Remove this once we have IHttpContextAccessor - services.AddContextAccessor(configuration); + 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 new file mode 100644 index 0000000000..4507d384cf --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/HttpContextAccessor.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +#if ASPNET50 +using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting; +#elif ASPNETCORE50 +using System.Threading; +#endif +using Microsoft.AspNet.Http; + +namespace Microsoft.AspNet.Hosting +{ + public class HttpContextAccessor : IHttpContextAccessor + { +#if ASPNET50 + private const string LogicalDataKey = "__HttpContext_Current__"; + + public HttpContext Value + { + get + { + var handle = CallContext.LogicalGetData(LogicalDataKey) as ObjectHandle; + return handle != null ? handle.Unwrap() as HttpContext : null; + } + set + { + CallContext.LogicalSetData(LogicalDataKey, new ObjectHandle(value)); + } + } + +#elif ASPNETCORE50 + private AsyncLocal _httpContextCurrent = new AsyncLocal(); + public HttpContext Value + { + get + { + return _httpContextCurrent.Value; + } + set + { + _httpContextCurrent.Value = value; + } + } +#endif + } +} diff --git a/src/Microsoft.AspNet.Hosting/IHostingEnvironment.cs b/src/Microsoft.AspNet.Hosting/IHostingEnvironment.cs index bcf0e6b812..8f5966e332 100644 --- a/src/Microsoft.AspNet.Hosting/IHostingEnvironment.cs +++ b/src/Microsoft.AspNet.Hosting/IHostingEnvironment.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNet.FileSystems; +using Microsoft.AspNet.FileProviders; using Microsoft.Framework.Runtime; namespace Microsoft.AspNet.Hosting @@ -13,6 +13,6 @@ namespace Microsoft.AspNet.Hosting string WebRoot { get; } - IFileSystem WebRootFileSystem { get; set; } + IFileProvider WebRootFileProvider { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/IHttpContextAccessor.cs b/src/Microsoft.AspNet.Hosting/IHttpContextAccessor.cs new file mode 100644 index 0000000000..563808d7f8 --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/IHttpContextAccessor.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNet.Http; + +namespace Microsoft.AspNet.Hosting +{ + public interface IHttpContextAccessor + { + 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.Hosting/Program.cs b/src/Microsoft.AspNet.Hosting/Program.cs index 4776c41223..8376913626 100644 --- a/src/Microsoft.AspNet.Hosting/Program.cs +++ b/src/Microsoft.AspNet.Hosting/Program.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.Framework.ConfigurationModel; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.DependencyInjection.Fallback; +using Microsoft.Framework.Logging; using Microsoft.Framework.Runtime; namespace Microsoft.AspNet.Hosting @@ -52,6 +53,7 @@ namespace Microsoft.AspNet.Hosting }; var engine = services.GetRequiredService(); + var loggerFactory = services.GetRequiredService(); var appShutdownService = _serviceProvider.GetRequiredService(); var shutdownHandle = new ManualResetEvent(false); @@ -59,7 +61,15 @@ namespace Microsoft.AspNet.Hosting appShutdownService.ShutdownRequested.Register(() => { - serverShutdown.Dispose(); + try + { + serverShutdown.Dispose(); + } + catch (Exception ex) + { + var logger = loggerFactory.Create(); + logger.WriteError("TODO: Dispose threw an exception", ex); + } shutdownHandle.Set(); }); diff --git a/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs b/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs index 3b300a1eca..a7e85283bf 100644 --- a/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs +++ b/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs @@ -9,7 +9,6 @@ using System.Reflection; using Microsoft.AspNet.Builder; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.DependencyInjection.Fallback; -using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Hosting.Startup { @@ -153,8 +152,6 @@ namespace Microsoft.AspNet.Hosting.Startup if (servicesMethod != null) { var services = HostingServices.Create(builder.ApplicationServices); - // TODO: remove this once IHttpContextAccessor service is added - services.AddContextAccessor(); if (servicesMethod.ReturnType == typeof(IServiceProvider)) { // IServiceProvider ConfigureServices(IServiceCollection) diff --git a/src/Microsoft.AspNet.Hosting/project.json b/src/Microsoft.AspNet.Hosting/project.json index 63dd7c6c7d..5c740ce152 100644 --- a/src/Microsoft.AspNet.Hosting/project.json +++ b/src/Microsoft.AspNet.Hosting/project.json @@ -2,8 +2,8 @@ "version": "1.0.0-*", "description": "ASP.NET 5 core hosting infrastructure and startup logic for web applications.", "dependencies": { - "Microsoft.AspNet.FileSystems": "1.0.0-*", - "Microsoft.AspNet.PipelineCore": "1.0.0-*", + "Microsoft.AspNet.FileProviders": "1.0.0-*", + "Microsoft.AspNet.Http.Core": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", "Microsoft.Framework.OptionsModel": "1.0.0-*", "Microsoft.Framework.Runtime.Interfaces": { "version": "1.0.0-*", "type": "build" }, diff --git a/src/Microsoft.AspNet.RequestContainer/ContainerExtensions.cs b/src/Microsoft.AspNet.RequestContainer/ContainerExtensions.cs index 9813e9164f..06d89995f2 100644 --- a/src/Microsoft.AspNet.RequestContainer/ContainerExtensions.cs +++ b/src/Microsoft.AspNet.RequestContainer/ContainerExtensions.cs @@ -48,10 +48,6 @@ namespace Microsoft.AspNet.Builder // Import services from hosting/KRE as fallback var serviceCollection = HostingServices.Create(builder.ApplicationServices); - // TODO: remove this once IHttpContextAccessor service is added - serviceCollection.AddContextAccessor(); - - // REVIEW: serviceCollection has the merged services, manifests are lost after this builder.ApplicationServices = configureServices(serviceCollection); return builder.UseMiddleware(); diff --git a/src/Microsoft.AspNet.RequestContainer/ContainerMiddleware.cs b/src/Microsoft.AspNet.RequestContainer/ContainerMiddleware.cs index 4145525ab8..097acf6d1b 100644 --- a/src/Microsoft.AspNet.RequestContainer/ContainerMiddleware.cs +++ b/src/Microsoft.AspNet.RequestContainer/ContainerMiddleware.cs @@ -2,72 +2,21 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -#if ASPNET50 -using System.Runtime.Remoting.Messaging; -#endif using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; -using Microsoft.Framework.DependencyInjection; -#if ASPNET50 -using System.Runtime.Remoting; -#endif + namespace Microsoft.AspNet.RequestContainer { public class ContainerMiddleware { - private const string LogicalDataKey = "__HttpContext_Current__"; private readonly RequestDelegate _next; - private readonly IServiceProvider _rootServiceProvider; - private readonly IContextAccessor _rootHttpContextAccessor; - private readonly IServiceScopeFactory _rootServiceScopeFactory; + private readonly IServiceProvider _services; - public ContainerMiddleware( - RequestDelegate next, - IServiceProvider rootServiceProvider, - IContextAccessor rootHttpContextAccessor, - IServiceScopeFactory rootServiceScopeFactory) + public ContainerMiddleware(RequestDelegate next, IServiceProvider services) { - if (rootServiceProvider == null) - { - throw new ArgumentNullException("rootServiceProvider"); - } - if (rootHttpContextAccessor == null) - { - throw new ArgumentNullException("rootHttpContextAccessor"); - } - if (rootServiceScopeFactory == null) - { - throw new ArgumentNullException("rootServiceScopeFactory"); - } - + _services = services; _next = next; - _rootServiceProvider = rootServiceProvider; - _rootServiceScopeFactory = rootServiceScopeFactory; - _rootHttpContextAccessor = rootHttpContextAccessor; - - _rootHttpContextAccessor.SetContextSource(AccessRootHttpContext, ExchangeRootHttpContext); - } - - internal static HttpContext AccessRootHttpContext() - { -#if ASPNET50 - var handle = CallContext.LogicalGetData(LogicalDataKey) as ObjectHandle; - return handle != null ? handle.Unwrap() as HttpContext : null; -#else - throw new Exception("TODO: CallContext not available"); -#endif - } - - internal 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; -#else - return null; -#endif } public async Task Invoke(HttpContext httpContext) @@ -77,22 +26,7 @@ namespace Microsoft.AspNet.RequestContainer throw new Exception("TODO: nested request container scope? this is probably a mistake on your part?"); } - var priorApplicationServices = httpContext.ApplicationServices; - var priorRequestServices = httpContext.RequestServices; - - var appServiceProvider = _rootServiceProvider; - var appServiceScopeFactory = _rootServiceScopeFactory; - var appHttpContextAccessor = _rootHttpContextAccessor; - - if (priorApplicationServices != null && - priorApplicationServices != appServiceProvider) - { - appServiceProvider = priorApplicationServices; - appServiceScopeFactory = priorApplicationServices.GetRequiredService(); - appHttpContextAccessor = priorApplicationServices.GetRequiredService>(); - } - - using (var container = new RequestServicesContainer(httpContext, appServiceScopeFactory, appHttpContextAccessor, appServiceProvider)) + using (var container = RequestServicesContainer.EnsureRequestServices(httpContext, _services)) { await _next.Invoke(httpContext); } diff --git a/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs b/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs index a7c646321e..747aae5012 100644 --- a/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs +++ b/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs @@ -12,7 +12,6 @@ namespace Microsoft.AspNet.RequestContainer public RequestServicesContainer( HttpContext context, IServiceScopeFactory scopeFactory, - IContextAccessor appContextAccessor, IServiceProvider appServiceProvider) { if (scopeFactory == null) @@ -23,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; @@ -36,23 +29,16 @@ 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 IContextAccessor ScopeContextAccessor { get; set; } - private IContextAccessor AppContextAccessor { get; set; } + // CONSIDER: this could be an extension method on HttpContext instead public static RequestServicesContainer EnsureRequestServices(HttpContext httpContext, IServiceProvider services) @@ -64,7 +50,6 @@ namespace Microsoft.AspNet.RequestContainer } var serviceProvider = httpContext.ApplicationServices ?? services; - if (serviceProvider == null) { throw new InvalidOperationException("TODO: services and httpContext.ApplicationServices are both null!"); @@ -72,32 +57,27 @@ namespace Microsoft.AspNet.RequestContainer // Matches constructor of RequestContainer var rootServiceProvider = serviceProvider.GetRequiredService(); - var rootHttpContextAccessor = serviceProvider.GetRequiredService>(); var rootServiceScopeFactory = serviceProvider.GetRequiredService(); - rootHttpContextAccessor.SetContextSource(ContainerMiddleware.AccessRootHttpContext, ContainerMiddleware.ExchangeRootHttpContext); - // 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 +#region IDisposable Support private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) @@ -106,9 +86,6 @@ namespace Microsoft.AspNet.RequestContainer { if (disposing) { - ScopeContextAccessor.SetValue(PriorScopeHttpContext); - AppContextAccessor.SetValue(PriorAppHttpContext); - Context.RequestServices = PriorRequestServices; Context.ApplicationServices = PriorAppServices; } @@ -122,10 +99,6 @@ namespace Microsoft.AspNet.RequestContainer Context = null; PriorAppServices = null; PriorRequestServices = null; - ScopeContextAccessor = null; - AppContextAccessor = null; - PriorAppHttpContext = null; - PriorScopeHttpContext = null; disposedValue = true; } @@ -137,8 +110,6 @@ namespace Microsoft.AspNet.RequestContainer // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(true); } - #endregion - +#endregion } - } \ No newline at end of file diff --git a/src/Microsoft.AspNet.RequestContainer/project.json b/src/Microsoft.AspNet.RequestContainer/project.json index d8f3cef5a9..076064ad98 100644 --- a/src/Microsoft.AspNet.RequestContainer/project.json +++ b/src/Microsoft.AspNet.RequestContainer/project.json @@ -8,6 +8,10 @@ }, "frameworks": { "aspnet50": {}, - "aspnetcore50": {} + "aspnetcore50": { + "dependencies": { + "System.Threading": "4.0.10-beta-*" + } + }, } } diff --git a/src/Microsoft.AspNet.TestHost/ClientHandler.cs b/src/Microsoft.AspNet.TestHost/ClientHandler.cs index b23dffbe70..1549565532 100644 --- a/src/Microsoft.AspNet.TestHost/ClientHandler.cs +++ b/src/Microsoft.AspNet.TestHost/ClientHandler.cs @@ -12,8 +12,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; -using Microsoft.AspNet.HttpFeature; -using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.Http.Core; +using Microsoft.AspNet.Http.Interfaces; namespace Microsoft.AspNet.TestHost { @@ -38,6 +38,12 @@ namespace Microsoft.AspNet.TestHost } _next = next; + + // PathString.StartsWithSegments that we use below requires the base path to not end in a slash. + if (pathBase.HasValue && pathBase.Value.EndsWith("/")) + { + pathBase = new PathString(pathBase.Value.Substring(0, pathBase.Value.Length - 1)); + } _pathBase = pathBase; } diff --git a/src/Microsoft.AspNet.TestHost/RequestFeature.cs b/src/Microsoft.AspNet.TestHost/RequestFeature.cs index 2ea5ae5127..f23df6716a 100644 --- a/src/Microsoft.AspNet.TestHost/RequestFeature.cs +++ b/src/Microsoft.AspNet.TestHost/RequestFeature.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.IO; -using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.Http.Interfaces; namespace Microsoft.AspNet.TestHost { diff --git a/src/Microsoft.AspNet.TestHost/ResponseFeature.cs b/src/Microsoft.AspNet.TestHost/ResponseFeature.cs index 9f2ebfd081..8c8aa08e60 100644 --- a/src/Microsoft.AspNet.TestHost/ResponseFeature.cs +++ b/src/Microsoft.AspNet.TestHost/ResponseFeature.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.IO; -using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.Http.Interfaces; namespace Microsoft.AspNet.TestHost { diff --git a/src/Microsoft.AspNet.TestHost/TestServer.cs b/src/Microsoft.AspNet.TestHost/TestServer.cs index 97e848033a..54b908133e 100644 --- a/src/Microsoft.AspNet.TestHost/TestServer.cs +++ b/src/Microsoft.AspNet.TestHost/TestServer.cs @@ -62,11 +62,6 @@ namespace Microsoft.AspNet.TestHost public HttpMessageHandler CreateHandler() { var pathBase = BaseAddress == null ? PathString.Empty : PathString.FromUriComponent(BaseAddress); - if (pathBase.Equals(new PathString("/"))) - { - // When we just have http://host/ the trailing slash is really part of the Path, not the PathBase. - pathBase = PathString.Empty; - } return new ClientHandler(Invoke, pathBase); } diff --git a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs index e2e0ba6852..3c6d5c13b6 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs @@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Hosting var services = HostingServices.Create().BuildServiceProvider(); var env = services.GetRequiredService(); Assert.Equal(Path.GetFullPath("testroot"), env.WebRoot); - Assert.True(env.WebRootFileSystem.GetFileInfo("TextFile.txt").Exists); + Assert.True(env.WebRootFileProvider.GetFileInfo("TextFile.txt").Exists); } public void Initialize(IApplicationBuilder builder) diff --git a/test/Microsoft.AspNet.Hosting.Tests/UseRequestServicesFacts.cs b/test/Microsoft.AspNet.Hosting.Tests/UseRequestServicesFacts.cs index 7b01e54c6f..e247d4ec64 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/UseRequestServicesFacts.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/UseRequestServicesFacts.cs @@ -6,7 +6,7 @@ using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting.Builder; using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Hosting.Startup; -using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.RequestContainer; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.DependencyInjection.Fallback; @@ -92,6 +92,7 @@ namespace Microsoft.AspNet.Hosting.Tests [InlineData(typeof(ITypeActivator))] [InlineData(typeof(IApplicationLifetime))] [InlineData(typeof(ILoggerFactory))] + [InlineData(typeof(IHttpContextAccessor))] public void UseRequestServicesHostingImportedServicesAreDefined(Type service) { var baseServiceProvider = HostingServices.Create().BuildServiceProvider(); diff --git a/test/Microsoft.AspNet.Hosting.Tests/project.json b/test/Microsoft.AspNet.Hosting.Tests/project.json index 5c8c65cacf..8adf1a1d0e 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/project.json +++ b/test/Microsoft.AspNet.Hosting.Tests/project.json @@ -2,13 +2,13 @@ "dependencies": { "Microsoft.AspNet.Hosting": "1.0.0-*", "Microsoft.AspNet.RequestContainer": "1.0.0-*", - "Xunit.KRunner": "1.0.0-*" + "xunit.runner.kre": "1.0.0-*" }, "frameworks": { "aspnet50": { } }, "commands": { - "test": "Xunit.KRunner" + "test": "xunit.runner.kre" }, "webroot": "testroot" } diff --git a/test/Microsoft.AspNet.TestHost.Tests/ClientHandlerTests.cs b/test/Microsoft.AspNet.TestHost.Tests/ClientHandlerTests.cs index 23f65bce8b..9956339096 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/ClientHandlerTests.cs +++ b/test/Microsoft.AspNet.TestHost.Tests/ClientHandlerTests.cs @@ -9,8 +9,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; -using Microsoft.AspNet.HttpFeature; -using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.Http.Core; +using Microsoft.AspNet.Http.Interfaces; using Xunit; namespace Microsoft.AspNet.TestHost @@ -40,7 +40,7 @@ namespace Microsoft.AspNet.TestHost Assert.Equal("example.com", context.Request.Host.Value); return Task.FromResult(0); - }, new PathString("/A/Path")); + }, new PathString("/A/Path/")); var httpClient = new HttpClient(handler); return httpClient.GetAsync("https://example.com/A/Path/and/file.txt?and=query"); } diff --git a/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs b/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs index 9a1a2c7b19..0a31db1b21 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs +++ b/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs @@ -23,8 +23,8 @@ namespace Microsoft.AspNet.TestHost // Arrange var services = HostingServices.Create().BuildServiceProvider(); - // Act & Assert - Assert.DoesNotThrow(() => TestServer.Create(services, app => { })); + // Act & Assert (Does not throw) + TestServer.Create(services, app => { }); } [Fact] @@ -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() { diff --git a/test/Microsoft.AspNet.TestHost.Tests/project.json b/test/Microsoft.AspNet.TestHost.Tests/project.json index 996af770f3..cf98630c3f 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/project.json +++ b/test/Microsoft.AspNet.TestHost.Tests/project.json @@ -1,10 +1,10 @@ { "dependencies": { "Microsoft.AspNet.TestHost": "1.0.0-*", - "Xunit.KRunner": "1.0.0-*" + "xunit.runner.kre": "1.0.0-*" }, "commands": { - "test": "Xunit.KRunner" + "test": "xunit.runner.kre" }, "frameworks": { "aspnet50": { }