diff --git a/Hosting.sln b/Hosting.sln index b698bea6b8..1110900290 100644 --- a/Hosting.sln +++ b/Hosting.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22530.0 +VisualStudioVersion = 14.0.22710.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E0497F39-AFFB-4819-A116-E39E361915AB}" EndProject @@ -15,8 +15,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Hosting", EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Hosting.Tests", "test\Microsoft.AspNet.Hosting.Tests\Microsoft.AspNet.Hosting.Tests.xproj", "{D4F18D58-52B1-435D-A012-10F2CDF158C4}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.RequestContainer", "src\Microsoft.AspNet.RequestContainer\Microsoft.AspNet.RequestContainer.xproj", "{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A66E3673-3976-4152-B902-2D0EC1428EA2}" ProjectSection(SolutionItems) = preProject global.json = global.json @@ -74,16 +72,6 @@ Global {D4F18D58-52B1-435D-A012-10F2CDF158C4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {D4F18D58-52B1-435D-A012-10F2CDF158C4}.Release|Mixed Platforms.Build.0 = Release|Any CPU {D4F18D58-52B1-435D-A012-10F2CDF158C4}.Release|x86.ActiveCfg = Release|Any CPU - {374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Debug|Any CPU.Build.0 = Debug|Any CPU - {374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Debug|x86.ActiveCfg = Debug|Any CPU - {374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Release|Any CPU.ActiveCfg = Release|Any CPU - {374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Release|Any CPU.Build.0 = Release|Any CPU - {374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Release|x86.ActiveCfg = Release|Any CPU {BB780FBB-7842-4759-8DE7-96FA2E5571C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BB780FBB-7842-4759-8DE7-96FA2E5571C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {BB780FBB-7842-4759-8DE7-96FA2E5571C1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -105,7 +93,6 @@ Global {1A415A3F-1081-45DB-809B-EE19CEA02DC0} = {E0497F39-AFFB-4819-A116-E39E361915AB} {3944F036-7E75-47E8-AA52-C4B89A64EC3A} = {E0497F39-AFFB-4819-A116-E39E361915AB} {D4F18D58-52B1-435D-A012-10F2CDF158C4} = {FEB39027-9158-4DE2-997F-7ADAEF8188D0} - {374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814} = {E0497F39-AFFB-4819-A116-E39E361915AB} {BB780FBB-7842-4759-8DE7-96FA2E5571C1} = {E0497F39-AFFB-4819-A116-E39E361915AB} EndGlobalSection EndGlobal diff --git a/src/Microsoft.AspNet.Hosting.Interfaces/IHostingEnvironment.cs b/src/Microsoft.AspNet.Hosting.Interfaces/IHostingEnvironment.cs index c38028a604..393c963e20 100644 --- a/src/Microsoft.AspNet.Hosting.Interfaces/IHostingEnvironment.cs +++ b/src/Microsoft.AspNet.Hosting.Interfaces/IHostingEnvironment.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNet.Hosting { public interface IHostingEnvironment { - string EnvironmentName { get; set; } + string EnvironmentName { get; set; } string WebRootPath { get; } diff --git a/src/Microsoft.AspNet.Hosting/ConfigureHostingEnvironment.cs b/src/Microsoft.AspNet.Hosting/ConfigureHostingEnvironment.cs deleted file mode 100644 index 892eaab372..0000000000 --- a/src/Microsoft.AspNet.Hosting/ConfigureHostingEnvironment.cs +++ /dev/null @@ -1,23 +0,0 @@ -// 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; -using Microsoft.Framework.ConfigurationModel; - -namespace Microsoft.AspNet.Hosting -{ - internal class ConfigureHostingEnvironment : IConfigureHostingEnvironment - { - private IConfiguration _config; - private const string EnvironmentKey = "ASPNET_ENV"; - - public ConfigureHostingEnvironment(IConfiguration config) - { - _config = config; - } - - public void Configure(IHostingEnvironment hostingEnv) - { - hostingEnv.EnvironmentName = _config?.Get(EnvironmentKey) ?? hostingEnv.EnvironmentName; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/HostingContext.cs b/src/Microsoft.AspNet.Hosting/HostingContext.cs index f5dd096850..3ff679a6b3 100644 --- a/src/Microsoft.AspNet.Hosting/HostingContext.cs +++ b/src/Microsoft.AspNet.Hosting/HostingContext.cs @@ -4,22 +4,29 @@ using System; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting.Server; +using Microsoft.AspNet.Hosting.Startup; using Microsoft.Framework.ConfigurationModel; +using Microsoft.Framework.DependencyInjection; namespace Microsoft.AspNet.Hosting { public class HostingContext { - public IApplicationLifetime ApplicationLifetime { get; set; } public IConfiguration Configuration { get; set; } public IApplicationBuilder Builder { get; set; } public string ApplicationName { get; set; } + public string WebRootPath { get; set; } public string EnvironmentName { get; set; } - public Action ApplicationStartup { get; set; } + public StartupMethods StartupMethods { get; set; } public RequestDelegate ApplicationDelegate { get; set; } + public IServiceCollection Services { get; } = new ServiceCollection(); + + // Result of ConfigureServices + public IServiceProvider ApplicationServices { get; set; } + public string ServerFactoryLocation { get; set; } public IServerFactory ServerFactory { get; set; } public IServerInformation Server { get; set; } diff --git a/src/Microsoft.AspNet.Hosting/HostingEngine.cs b/src/Microsoft.AspNet.Hosting/HostingEngine.cs index 1970e48bef..01fae429d5 100644 --- a/src/Microsoft.AspNet.Hosting/HostingEngine.cs +++ b/src/Microsoft.AspNet.Hosting/HostingEngine.cs @@ -9,51 +9,116 @@ using Microsoft.AspNet.Hosting.Builder; using Microsoft.AspNet.Hosting.Internal; using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Hosting.Startup; +using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.Runtime; +using Microsoft.Framework.Runtime.Infrastructure; namespace Microsoft.AspNet.Hosting { - public class HostingEngine : IHostingEngine + public class HostingEngine { - private readonly IServerLoader _serverManager; - private readonly IStartupLoader _startupLoader; - private readonly IApplicationBuilderFactory _builderFactory; - private readonly IHttpContextFactory _httpContextFactory; - private readonly IHttpContextAccessor _contextAccessor; + private const string EnvironmentKey = "ASPNET_ENV"; - public HostingEngine( - IServerLoader serverManager, - IStartupLoader startupLoader, - IApplicationBuilderFactory builderFactory, - IHttpContextFactory httpContextFactory, - IHttpContextAccessor contextAccessor) + private readonly IServiceProvider _fallbackServices; + private readonly ApplicationLifetime _appLifetime; + private readonly IApplicationEnvironment _applicationEnvironment; + private readonly HostingEnvironment _hostingEnvironment; + + private IServerLoader _serverLoader; + private IApplicationBuilderFactory _builderFactory; + + public HostingEngine() : this(fallbackServices: null) { } + + public HostingEngine(IServiceProvider fallbackServices) { - _serverManager = serverManager; - _startupLoader = startupLoader; - _builderFactory = builderFactory; - _httpContextFactory = httpContextFactory; - _contextAccessor = contextAccessor; + _fallbackServices = fallbackServices ?? CallContextServiceLocator.Locator.ServiceProvider; + _appLifetime = new ApplicationLifetime(); + _applicationEnvironment = _fallbackServices.GetRequiredService(); + _hostingEnvironment = new HostingEnvironment(_applicationEnvironment); + _fallbackServices = new WrappingServiceProvider(_fallbackServices, _hostingEnvironment, _appLifetime); } public IDisposable Start(HostingContext context) { + EnsureContextDefaults(context); + EnsureApplicationServices(context); EnsureBuilder(context); EnsureServerFactory(context); InitalizeServerFactory(context); EnsureApplicationDelegate(context); - var applicationLifetime = (ApplicationLifetime)context.ApplicationLifetime; - var pipeline = new PipelineInstance(_httpContextFactory, context.ApplicationDelegate, _contextAccessor); - var server = context.ServerFactory.Start(context.Server, pipeline.Invoke); + var contextFactory = context.ApplicationServices.GetRequiredService(); + var contextAccessor = context.ApplicationServices.GetRequiredService(); + var server = context.ServerFactory.Start(context.Server, + features => + { + var httpContext = contextFactory.CreateHttpContext(features); + contextAccessor.HttpContext = httpContext; + return context.ApplicationDelegate(httpContext); + }); return new Disposable(() => { - applicationLifetime.NotifyStopping(); + _appLifetime.NotifyStopping(); server.Dispose(); - pipeline.Dispose(); - applicationLifetime.NotifyStopped(); + _appLifetime.NotifyStopped(); }); } + private void EnsureContextDefaults(HostingContext context) + { + if (context.ApplicationName == null) + { + context.ApplicationName = _applicationEnvironment.ApplicationName; + } + + if (context.EnvironmentName == null) + { + context.EnvironmentName = context.Configuration?.Get(EnvironmentKey) ?? HostingEnvironment.DefaultEnvironmentName; + } + + _hostingEnvironment.EnvironmentName = context.EnvironmentName; + + if (context.WebRootPath != null) + { + _hostingEnvironment.WebRootPath = context.WebRootPath; + } + } + + private void EnsureApplicationServices(HostingContext context) + { + if (context.ApplicationServices != null) + { + return; + } + + EnsureStartupMethods(context); + + context.ApplicationServices = context.StartupMethods.ConfigureServicesDelegate(CreateHostingServices(context)); + } + + private void EnsureStartupMethods(HostingContext context) + { + if (context.StartupMethods != null) + { + return; + } + + var diagnosticMessages = new List(); + context.StartupMethods = ApplicationStartup.LoadStartupMethods( + _fallbackServices, + context.ApplicationName, + context.EnvironmentName, + diagnosticMessages); + + if (context.StartupMethods == null) + { + throw new ArgumentException( + diagnosticMessages.Aggregate("Failed to find an entry point for the web application.", (a, b) => a + "\r\n" + b), + nameof(context)); + } + } + private void EnsureBuilder(HostingContext context) { if (context.Builder != null) @@ -61,7 +126,13 @@ namespace Microsoft.AspNet.Hosting return; } + if (_builderFactory == null) + { + _builderFactory = context.ApplicationServices.GetRequiredService(); + } + context.Builder = _builderFactory.CreateBuilder(); + context.Builder.ApplicationServices = context.ApplicationServices; } private void EnsureServerFactory(HostingContext context) @@ -71,7 +142,12 @@ namespace Microsoft.AspNet.Hosting return; } - context.ServerFactory = _serverManager.LoadServerFactory(context.ServerFactoryLocation); + if (_serverLoader == null) + { + _serverLoader = context.ApplicationServices.GetRequiredService(); + } + + context.ServerFactory = _serverLoader.LoadServerFactory(context.ServerFactoryLocation); } private void InitalizeServerFactory(HostingContext context) @@ -87,6 +163,32 @@ namespace Microsoft.AspNet.Hosting } } + private IServiceCollection CreateHostingServices(HostingContext context) + { + var services = Import(_fallbackServices); + + services.TryAdd(ServiceDescriptor.Transient()); + + services.TryAdd(ServiceDescriptor.Transient()); + services.TryAdd(ServiceDescriptor.Transient()); + + // TODO: Do we expect this to be provide by the runtime eventually? + services.AddLogging(); + services.TryAdd(ServiceDescriptor.Singleton()); + + // Apply user services + services.Add(context.Services); + + // Jamming in app lifetime and hosting env since these must not be replaceable + services.AddInstance(_appLifetime); + services.AddInstance(_hostingEnvironment); + + // Conjure up a RequestServices + services.AddTransient(); + + return services; + } + private void EnsureApplicationDelegate(HostingContext context) { if (context.ApplicationDelegate != null) @@ -94,30 +196,59 @@ namespace Microsoft.AspNet.Hosting return; } - EnsureApplicationStartup(context); + // REVIEW: should we call EnsureApplicationServices? + var startupFilters = context.ApplicationServices.GetService>(); + var configure = context.StartupMethods.ConfigureDelegate; + foreach (var filter in startupFilters) + { + configure = filter.Configure(context.Builder, configure); + } + + configure(context.Builder); - context.ApplicationStartup.Invoke(context.Builder); context.ApplicationDelegate = context.Builder.Build(); } - private void EnsureApplicationStartup(HostingContext context) + private static IServiceCollection Import(IServiceProvider fallbackProvider) { - if (context.ApplicationStartup != null) + var services = new ServiceCollection(); + var manifest = fallbackProvider.GetRequiredService(); + foreach (var service in manifest.Services) { - return; + services.AddTransient(service, sp => fallbackProvider.GetService(service)); } - var diagnosticMessages = new List(); - context.ApplicationStartup = _startupLoader.LoadStartup( - context.ApplicationName, - context.EnvironmentName, - diagnosticMessages); + return services; + } - if (context.ApplicationStartup == null) + private class WrappingServiceProvider : IServiceProvider + { + private readonly IServiceProvider _sp; + private readonly IHostingEnvironment _hostingEnvironment; + private readonly IApplicationLifetime _applicationLifetime; + + public WrappingServiceProvider(IServiceProvider sp, + IHostingEnvironment hostingEnvironment, + IApplicationLifetime applicationLifetime) { - throw new ArgumentException( - diagnosticMessages.Aggregate("Failed to find an entry point for the web application.", (a, b) => a + "\r\n" + b), - nameof(context)); + _sp = sp; + _hostingEnvironment = hostingEnvironment; + _applicationLifetime = applicationLifetime; + } + + public object GetService(Type serviceType) + { + if (serviceType == typeof(IHostingEnvironment)) + { + return _hostingEnvironment; + } + + if (serviceType == typeof(IApplicationLifetime)) + { + return _applicationLifetime; + } + + return _sp.GetService(serviceType); } } diff --git a/src/Microsoft.AspNet.Hosting/HostingEnvironment.cs b/src/Microsoft.AspNet.Hosting/HostingEnvironment.cs index 03a7317453..b7a0249319 100644 --- a/src/Microsoft.AspNet.Hosting/HostingEnvironment.cs +++ b/src/Microsoft.AspNet.Hosting/HostingEnvironment.cs @@ -10,22 +10,18 @@ namespace Microsoft.AspNet.Hosting { public class HostingEnvironment : IHostingEnvironment { - private const string DefaultEnvironmentName = "Development"; + internal const string DefaultEnvironmentName = "Development"; - public HostingEnvironment(IApplicationEnvironment appEnvironment, IEnumerable configures) + public HostingEnvironment(IApplicationEnvironment appEnvironment) { EnvironmentName = DefaultEnvironmentName; WebRootPath = HostingUtilities.GetWebRoot(appEnvironment.ApplicationBasePath); WebRootFileProvider = new PhysicalFileProvider(WebRootPath); - foreach (var configure in configures) - { - configure.Configure(this); - } } public string EnvironmentName { get; set; } - public string WebRootPath { get; private set; } + public string WebRootPath { get; set; } public IFileProvider WebRootFileProvider { get; private set; } } diff --git a/src/Microsoft.AspNet.Hosting/HostingServices.cs b/src/Microsoft.AspNet.Hosting/HostingServices.cs deleted file mode 100644 index 6a321a0098..0000000000 --- a/src/Microsoft.AspNet.Hosting/HostingServices.cs +++ /dev/null @@ -1,89 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Framework.ConfigurationModel; -using Microsoft.Framework.DependencyInjection; -using Microsoft.Framework.Logging; -using Microsoft.Framework.Runtime; -using Microsoft.Framework.Runtime.Infrastructure; - -namespace Microsoft.AspNet.Hosting -{ - public static class HostingServices - { - private static IServiceCollection Import(IServiceProvider fallbackProvider, Action configureHostServices) - { - var services = new ServiceCollection(); - var manifest = fallbackProvider.GetRequiredService(); - foreach (var service in manifest.Services) - { - services.AddTransient(service, sp => fallbackProvider.GetService(service)); - } - - if (configureHostServices != null) - { - configureHostServices(services); - } - - services.AddSingleton(sp => new HostingManifest(services)); - - return services; - } - - public static IServiceCollection Create() - { - return Create(CallContextServiceLocator.Locator.ServiceProvider, configureHostServices: null, configuration: null); - } - - public static IServiceCollection Create(IServiceProvider fallbackServices) - { - return Create(fallbackServices, configureHostServices: null, configuration: null); - } - - public static IServiceCollection Create(Action configureHostServices) - { - return Create(CallContextServiceLocator.Locator.ServiceProvider, configureHostServices, configuration: null); - } - - public static IServiceCollection Create(IServiceProvider fallbackServices, Action configureHostServices) - { - return Create(fallbackServices, configureHostServices, configuration: null); - } - - public static IServiceCollection Create(Action configureHostServices, IConfiguration configuration) - { - return Create(CallContextServiceLocator.Locator.ServiceProvider, configureHostServices, configuration); - } - - public static IServiceCollection Create(IServiceProvider fallbackServices, IConfiguration configuration) - { - return Create(CallContextServiceLocator.Locator.ServiceProvider, configureHostServices: null, configuration: configuration); - } - - public static IServiceCollection Create(IServiceProvider fallbackServices, Action configureHostServices, IConfiguration configuration) - { - var services = Import(fallbackServices, configureHostServices); - services.AddHosting(configuration); - return services; - } - - // Manifest exposes the fallback manifest in addition to ITypeActivator, IHostingEnvironment, and ILoggerFactory - private class HostingManifest : IServiceManifest - { - public HostingManifest(IServiceCollection hostServices) - { - Services = new Type[] { - typeof(IHostingEnvironment), - typeof(ILoggerFactory), - typeof(IHttpContextAccessor), - typeof(IApplicationLifetime) - }.Concat(hostServices.Select(s => s.ServiceType)).Distinct(); - } - - public IEnumerable Services { get; private set; } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/HostingServicesCollectionExtensions.cs b/src/Microsoft.AspNet.Hosting/HostingServicesCollectionExtensions.cs deleted file mode 100644 index ba3336d541..0000000000 --- a/src/Microsoft.AspNet.Hosting/HostingServicesCollectionExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -// 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.Hosting; -using Microsoft.AspNet.Hosting.Builder; -using Microsoft.AspNet.Hosting.Server; -using Microsoft.AspNet.Hosting.Startup; -using Microsoft.Framework.ConfigurationModel; - -namespace Microsoft.Framework.DependencyInjection -{ - public static class HostingServicesExtensions - { - public static IServiceCollection AddHosting(this IServiceCollection services) - { - return services.AddHosting(configuration: null); - } - - public static IServiceCollection AddHosting(this IServiceCollection services, IConfiguration configuration) - { - services.TryAdd(ServiceDescriptor.Transient()); - services.TryAdd(ServiceDescriptor.Transient()); - - services.TryAdd(ServiceDescriptor.Transient()); - - services.TryAdd(ServiceDescriptor.Transient()); - services.TryAdd(ServiceDescriptor.Transient()); - - services.TryAdd(ServiceDescriptor.Instance(new ApplicationLifetime())); - - // TODO: Do we expect this to be provide by the runtime eventually? - services.AddLogging(); - services.TryAdd(ServiceDescriptor.Singleton()); - services.TryAdd(ServiceDescriptor.Singleton()); - - // REVIEW: don't try add because we pull out IEnumerable? - services.AddInstance(new ConfigureHostingEnvironment(configuration)); - - return services; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/IHostingEngine.cs b/src/Microsoft.AspNet.Hosting/IHostingEngine.cs deleted file mode 100644 index ba6c74ecd1..0000000000 --- a/src/Microsoft.AspNet.Hosting/IHostingEngine.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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; - -namespace Microsoft.AspNet.Hosting -{ - public interface IHostingEngine - { - IDisposable Start(HostingContext context); - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/Internal/AutoRequestServicesStartupFilter.cs b/src/Microsoft.AspNet.Hosting/Internal/AutoRequestServicesStartupFilter.cs new file mode 100644 index 0000000000..0d28da169c --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/Internal/AutoRequestServicesStartupFilter.cs @@ -0,0 +1,21 @@ +// 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; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting.Startup; + +namespace Microsoft.AspNet.Hosting.Internal +{ + public class AutoRequestServicesStartupFilter : IStartupFilter + { + public Action Configure(IApplicationBuilder app, Action next) + { + return builder => + { + app.UseMiddleware(); + next(builder); + }; + } + } +} diff --git a/src/Microsoft.AspNet.Hosting/Internal/PipelineInstance.cs b/src/Microsoft.AspNet.Hosting/Internal/PipelineInstance.cs deleted file mode 100644 index b2f67c2eca..0000000000 --- a/src/Microsoft.AspNet.Hosting/Internal/PipelineInstance.cs +++ /dev/null @@ -1,37 +0,0 @@ -// 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; -using System.Threading.Tasks; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Hosting.Builder; - -namespace Microsoft.AspNet.Hosting.Internal -{ - public class PipelineInstance : IDisposable - { - private readonly IHttpContextFactory _httpContextFactory; - private readonly RequestDelegate _requestDelegate; - private readonly IHttpContextAccessor _contextAccessor; - - public PipelineInstance(IHttpContextFactory httpContextFactory, RequestDelegate requestDelegate, IHttpContextAccessor contextAccessor) - { - _httpContextFactory = httpContextFactory; - _requestDelegate = requestDelegate; - _contextAccessor = contextAccessor; - } - - public Task Invoke(IFeatureCollection featureCollection) - { - var httpContext = _httpContextFactory.CreateHttpContext(featureCollection); - _contextAccessor.HttpContext = httpContext; - return _requestDelegate(httpContext); - } - - public void Dispose() - { - // TODO: application notification of disposal - } - } -} diff --git a/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs b/src/Microsoft.AspNet.Hosting/Internal/RequestServicesContainer.cs similarity index 98% rename from src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs rename to src/Microsoft.AspNet.Hosting/Internal/RequestServicesContainer.cs index 747aae5012..716c2ed3be 100644 --- a/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs +++ b/src/Microsoft.AspNet.Hosting/Internal/RequestServicesContainer.cs @@ -5,7 +5,7 @@ using System; using Microsoft.AspNet.Http; using Microsoft.Framework.DependencyInjection; -namespace Microsoft.AspNet.RequestContainer +namespace Microsoft.AspNet.Hosting.Internal { public class RequestServicesContainer : IDisposable { diff --git a/src/Microsoft.AspNet.RequestContainer/ContainerMiddleware.cs b/src/Microsoft.AspNet.Hosting/Internal/RequestServicesContainerMiddleware.cs similarity index 67% rename from src/Microsoft.AspNet.RequestContainer/ContainerMiddleware.cs rename to src/Microsoft.AspNet.Hosting/Internal/RequestServicesContainerMiddleware.cs index 097acf6d1b..8ffd9f7a06 100644 --- a/src/Microsoft.AspNet.RequestContainer/ContainerMiddleware.cs +++ b/src/Microsoft.AspNet.Hosting/Internal/RequestServicesContainerMiddleware.cs @@ -6,14 +6,14 @@ using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; -namespace Microsoft.AspNet.RequestContainer +namespace Microsoft.AspNet.Hosting.Internal { - public class ContainerMiddleware + public class RequestServicesContainerMiddleware { private readonly RequestDelegate _next; private readonly IServiceProvider _services; - public ContainerMiddleware(RequestDelegate next, IServiceProvider services) + public RequestServicesContainerMiddleware(RequestDelegate next, IServiceProvider services) { _services = services; _next = next; @@ -21,11 +21,6 @@ namespace Microsoft.AspNet.RequestContainer public async Task Invoke(HttpContext httpContext) { - if (httpContext.RequestServices != null) - { - throw new Exception("TODO: nested request container scope? this is probably a mistake on your part?"); - } - using (var container = RequestServicesContainer.EnsureRequestServices(httpContext, _services)) { await _next.Invoke(httpContext); diff --git a/src/Microsoft.AspNet.Hosting/Program.cs b/src/Microsoft.AspNet.Hosting/Program.cs index 65658f606b..47211a65ed 100644 --- a/src/Microsoft.AspNet.Hosting/Program.cs +++ b/src/Microsoft.AspNet.Hosting/Program.cs @@ -33,29 +33,19 @@ namespace Microsoft.AspNet.Hosting config.AddEnvironmentVariables(); config.AddCommandLine(args); - var services = HostingServices.Create(_serviceProvider, config) - .BuildServiceProvider(); - - var appEnv = services.GetRequiredService(); - var hostingEnv = services.GetRequiredService(); - var applicationLifetime = services.GetRequiredService(); - var context = new HostingContext() { - ApplicationLifetime = applicationLifetime, Configuration = config, - ServerFactoryLocation = config.Get("server"), // TODO: Key names - ApplicationName = config.Get("app") // TODO: Key names - ?? appEnv.ApplicationName, - EnvironmentName = hostingEnv.EnvironmentName, + ServerFactoryLocation = config.Get("server"), + ApplicationName = config.Get("app") }; - var engine = services.GetRequiredService(); - var loggerFactory = services.GetRequiredService(); - var appShutdownService = _serviceProvider.GetRequiredService(); - var shutdownHandle = new ManualResetEvent(false); - + var engine = new HostingEngine(_serviceProvider); + var serverShutdown = engine.Start(context); + var loggerFactory = context.ApplicationServices.GetRequiredService(); + var appShutdownService = context.ApplicationServices.GetRequiredService(); + var shutdownHandle = new ManualResetEvent(false); appShutdownService.ShutdownRequested.Register(() => { diff --git a/src/Microsoft.AspNet.Hosting/Startup/ApplicationStartup.cs b/src/Microsoft.AspNet.Hosting/Startup/ApplicationStartup.cs new file mode 100644 index 0000000000..811afb5590 --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/Startup/ApplicationStartup.cs @@ -0,0 +1,125 @@ +// 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; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Reflection; +using Microsoft.Framework.DependencyInjection; + +namespace Microsoft.AspNet.Hosting.Startup +{ + public static class ApplicationStartup + { + internal static ConfigureServicesDelegate DefaultBuildServiceProvider = s => s.BuildServiceProvider(); + + public static StartupMethods LoadStartupMethods( + IServiceProvider services, + string applicationName, + string environmentName, + IList diagnosticMessages) + { + if (string.IsNullOrEmpty(applicationName)) + { + throw new ArgumentException("Value cannot be null or empty.", "applicationName"); + } + + var assembly = Assembly.Load(new AssemblyName(applicationName)); + if (assembly == null) + { + throw new InvalidOperationException(String.Format("The assembly '{0}' failed to load.", applicationName)); + } + + var startupNameWithEnv = "Startup" + environmentName; + var startupNameWithoutEnv = "Startup"; + + // Check the most likely places first + var type = + assembly.GetType(startupNameWithEnv) ?? + assembly.GetType(applicationName + "." + startupNameWithEnv) ?? + assembly.GetType(startupNameWithoutEnv) ?? + assembly.GetType(applicationName + "." + startupNameWithoutEnv); + + if (type == null) + { + // Full scan + var definedTypes = assembly.DefinedTypes.ToList(); + + var startupType1 = definedTypes.Where(info => info.Name.Equals(startupNameWithEnv, StringComparison.Ordinal)); + var startupType2 = definedTypes.Where(info => info.Name.Equals(startupNameWithoutEnv, StringComparison.Ordinal)); + + var typeInfo = startupType1.Concat(startupType2).FirstOrDefault(); + if (typeInfo != null) + { + type = typeInfo.AsType(); + } + } + + if (type == null) + { + throw new InvalidOperationException(String.Format("A type named '{0}' or '{1}' could not be found in assembly '{2}'.", + startupNameWithEnv, + startupNameWithoutEnv, + applicationName)); + } + + var configureMethod = FindConfigureDelegate(type, environmentName); + var servicesMethod = FindConfigureServicesDelegate(type, environmentName); + + object instance = null; + if (!configureMethod.MethodInfo.IsStatic || (servicesMethod != null && !servicesMethod.MethodInfo.IsStatic)) + { + instance = ActivatorUtilities.GetServiceOrCreateInstance(services, type); + } + + return new StartupMethods(configureMethod.Build(instance), servicesMethod?.Build(instance)); + } + + + public static ConfigureBuilder FindConfigureDelegate(Type startupType, string environmentName) + { + var configureMethod = FindMethod(startupType, "Configure{0}", environmentName, typeof(void), required: true); + return new ConfigureBuilder(configureMethod); + } + + public static ConfigureServicesBuilder FindConfigureServicesDelegate(Type startupType, string environmentName) + { + var servicesMethod = FindMethod(startupType, "Configure{0}Services", environmentName, typeof(IServiceProvider), required: false) + ?? FindMethod(startupType, "Configure{0}Services", environmentName, typeof(void), required: false); + return servicesMethod == null ? null : new ConfigureServicesBuilder(servicesMethod); + } + + private static MethodInfo FindMethod(Type startupType, string methodName, string environmentName, Type returnType = null, bool required = true) + { + var methodNameWithEnv = string.Format(CultureInfo.InvariantCulture, methodName, environmentName); + var methodNameWithNoEnv = string.Format(CultureInfo.InvariantCulture, methodName, ""); + var methodInfo = startupType.GetMethod(methodNameWithEnv, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) + ?? startupType.GetMethod(methodNameWithNoEnv, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); + if (methodInfo == null) + { + if (required) + { + throw new InvalidOperationException(string.Format("A method named '{0}' or '{1}' in the type '{2}' could not be found.", + methodNameWithEnv, + methodNameWithNoEnv, + startupType.FullName)); + + } + return null; + } + if (returnType != null && methodInfo.ReturnType != returnType) + { + if (required) + { + throw new InvalidOperationException(string.Format("The '{0}' method in the type '{1}' must have a return type of '{2}'.", + methodInfo.Name, + startupType.FullName, + returnType.Name)); + } + return null; + } + return methodInfo; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/Startup/ConfigureDelegate.cs b/src/Microsoft.AspNet.Hosting/Startup/ConfigureDelegate.cs new file mode 100644 index 0000000000..415302a961 --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/Startup/ConfigureDelegate.cs @@ -0,0 +1,60 @@ +// 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; +using System.Reflection; +using Microsoft.AspNet.Builder; +using Microsoft.Framework.DependencyInjection; + +namespace Microsoft.AspNet.Hosting.Startup +{ + // TODO: replace all Action eventually with this + public delegate void ConfigureDelegate(IApplicationBuilder builder); + + public class ConfigureBuilder + { + public ConfigureBuilder(MethodInfo configure) + { + MethodInfo = configure; + } + + public MethodInfo MethodInfo { get; } + + public Action Build(object instance) + { + return builder => Invoke(instance, builder); + } + + private void Invoke(object instance, IApplicationBuilder builder) + { + var serviceProvider = builder.ApplicationServices; + var parameterInfos = MethodInfo.GetParameters(); + var parameters = new object[parameterInfos.Length]; + for (var index = 0; index != parameterInfos.Length; ++index) + { + var parameterInfo = parameterInfos[index]; + if (parameterInfo.ParameterType == typeof(IApplicationBuilder)) + { + parameters[index] = builder; + } + else + { + try + { + parameters[index] = serviceProvider.GetRequiredService(parameterInfo.ParameterType); + } + catch (Exception) + { + throw new Exception(string.Format( + "Could not resolve a service of type '{0}' for the parameter '{1}' of method '{2}' on type '{3}'.", + parameterInfo.ParameterType.FullName, + parameterInfo.Name, + MethodInfo.Name, + MethodInfo.DeclaringType.FullName)); + } + } + } + MethodInfo.Invoke(instance, parameters); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/Startup/ConfigureServicesDelegate.cs b/src/Microsoft.AspNet.Hosting/Startup/ConfigureServicesDelegate.cs new file mode 100644 index 0000000000..c55eee4c6f --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/Startup/ConfigureServicesDelegate.cs @@ -0,0 +1,43 @@ +// 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; +using System.Reflection; +using Microsoft.Framework.DependencyInjection; + +namespace Microsoft.AspNet.Hosting.Startup +{ + public delegate IServiceProvider ConfigureServicesDelegate(IServiceCollection services); + + public class ConfigureServicesBuilder + { + public ConfigureServicesBuilder(MethodInfo configureServices) + { + MethodInfo = configureServices; + } + + public MethodInfo MethodInfo { get; } + + public ConfigureServicesDelegate Build(object instance) + { + return services => Invoke(instance, services); + } + + private IServiceProvider Invoke(object instance, IServiceCollection exportServices) + { + var parameterInfos = MethodInfo.GetParameters(); + var parameters = new object[parameterInfos.Length]; + for (var index = 0; index != parameterInfos.Length; ++index) + { + var parameterInfo = parameterInfos[index]; + if (exportServices != null && parameterInfo.ParameterType == typeof(IServiceCollection)) + { + parameters[index] = exportServices; + } + } + + // REVIEW: We null ref if exportServices is null, cuz it should not be null + return MethodInfo.Invoke(instance, parameters) as IServiceProvider ?? exportServices.BuildServiceProvider(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/Startup/IStartupLoader.cs b/src/Microsoft.AspNet.Hosting/Startup/IStartupFilter.cs similarity index 54% rename from src/Microsoft.AspNet.Hosting/Startup/IStartupLoader.cs rename to src/Microsoft.AspNet.Hosting/Startup/IStartupFilter.cs index 24667a0c42..943c8aed32 100644 --- a/src/Microsoft.AspNet.Hosting/Startup/IStartupLoader.cs +++ b/src/Microsoft.AspNet.Hosting/Startup/IStartupFilter.cs @@ -2,16 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using Microsoft.AspNet.Builder; namespace Microsoft.AspNet.Hosting.Startup { - public interface IStartupLoader + public interface IStartupFilter { - Action LoadStartup( - string applicationName, - string environmentName, - IList diagnosticMessages); + // TODO: replace with ConfigureDelegate? + Action Configure(IApplicationBuilder app, Action next); } } diff --git a/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs b/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs deleted file mode 100644 index bed2a0190d..0000000000 --- a/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs +++ /dev/null @@ -1,174 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Reflection; -using Microsoft.AspNet.Builder; -using Microsoft.Framework.DependencyInjection; - -namespace Microsoft.AspNet.Hosting.Startup -{ - public class StartupLoader : IStartupLoader - { - private readonly IServiceProvider _services; - - public StartupLoader(IServiceProvider services) - { - _services = services; - } - - private MethodInfo FindMethod(Type startupType, string methodName, string environmentName, Type returnType = null, bool required = true) - { - var methodNameWithEnv = string.Format(CultureInfo.InvariantCulture, methodName, environmentName); - var methodNameWithNoEnv = string.Format(CultureInfo.InvariantCulture, methodName, ""); - var methodInfo = startupType.GetMethod(methodNameWithEnv, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) - ?? startupType.GetMethod(methodNameWithNoEnv, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); - if (methodInfo == null) - { - if (required) - { - throw new Exception(string.Format("A method named '{0}' or '{1}' in the type '{2}' could not be found.", - methodNameWithEnv, - methodNameWithNoEnv, - startupType.FullName)); - - } - return null; - } - if (returnType != null && methodInfo.ReturnType != returnType) - { - if (required) - { - throw new Exception(string.Format("The '{0}' method in the type '{1}' must have a return type of '{2}'.", - methodInfo.Name, - startupType.FullName, - returnType.Name)); - } - return null; - } - return methodInfo; - } - - private object Invoke(MethodInfo methodInfo, object instance, IApplicationBuilder builder, IServiceCollection services = null) - { - var serviceProvider = builder.ApplicationServices ?? _services; - var parameterInfos = methodInfo.GetParameters(); - var parameters = new object[parameterInfos.Length]; - for (var index = 0; index != parameterInfos.Length; ++index) - { - var parameterInfo = parameterInfos[index]; - if (parameterInfo.ParameterType == typeof(IApplicationBuilder)) - { - parameters[index] = builder; - } - else if (services != null && parameterInfo.ParameterType == typeof(IServiceCollection)) - { - parameters[index] = services; - } - else - { - try - { - parameters[index] = serviceProvider.GetRequiredService(parameterInfo.ParameterType); - } - catch (Exception) - { - throw new Exception(string.Format( - "Could not resolve a service of type '{0}' for the parameter '{1}' of method '{2}' on type '{3}'.", - parameterInfo.ParameterType.FullName, - parameterInfo.Name, - methodInfo.Name, - methodInfo.DeclaringType.FullName)); - } - } - } - return methodInfo.Invoke(instance, parameters); - } - - public Action LoadStartup( - string applicationName, - string environmentName, - IList diagnosticMessages) - { - if (string.IsNullOrEmpty(applicationName)) - { - throw new ArgumentException("Value cannot be null or empty.", "applicationName"); - } - - var assembly = Assembly.Load(new AssemblyName(applicationName)); - if (assembly == null) - { - throw new Exception(String.Format("The assembly '{0}' failed to load.", applicationName)); - } - - var startupNameWithEnv = "Startup" + environmentName; - var startupNameWithoutEnv = "Startup"; - - // Check the most likely places first - var type = - assembly.GetType(startupNameWithEnv) ?? - assembly.GetType(applicationName + "." + startupNameWithEnv) ?? - assembly.GetType(startupNameWithoutEnv) ?? - assembly.GetType(applicationName + "." + startupNameWithoutEnv); - - if (type == null) - { - // Full scan - var definedTypes = assembly.DefinedTypes.ToList(); - - var startupType1 = definedTypes.Where(info => info.Name.Equals(startupNameWithEnv, StringComparison.Ordinal)); - var startupType2 = definedTypes.Where(info => info.Name.Equals(startupNameWithoutEnv, StringComparison.Ordinal)); - - var typeInfo = startupType1.Concat(startupType2).FirstOrDefault(); - if (typeInfo != null) - { - type = typeInfo.AsType(); - } - } - - if (type == null) - { - throw new Exception(String.Format("A type named '{0}' or '{1}' could not be found in assembly '{2}'.", - startupNameWithEnv, - startupNameWithoutEnv, - applicationName)); - } - - var configureMethod = FindMethod(type, "Configure{0}", environmentName, typeof(void), required: true); - var servicesMethod = FindMethod(type, "Configure{0}Services", environmentName, typeof(IServiceProvider), required: false) - ?? FindMethod(type, "Configure{0}Services", environmentName, typeof(void), required: false); - - object instance = null; - if (!configureMethod.IsStatic || (servicesMethod != null && !servicesMethod.IsStatic)) - { - instance = ActivatorUtilities.GetServiceOrCreateInstance(_services, type); - } - return builder => - { - if (servicesMethod != null) - { - var services = HostingServices.Create(builder.ApplicationServices); - if (servicesMethod.ReturnType == typeof(IServiceProvider)) - { - // IServiceProvider ConfigureServices(IServiceCollection) - builder.ApplicationServices = (Invoke(servicesMethod, instance, builder, services) as IServiceProvider) - ?? builder.ApplicationServices; - } - else - { - // void ConfigureServices(IServiceCollection) - Invoke(servicesMethod, instance, builder, services); - if (builder != null) - { - builder.ApplicationServices = services.BuildServiceProvider(); - } - } - } - Invoke(configureMethod, instance, builder); - }; - } - } -} diff --git a/src/Microsoft.AspNet.Hosting/Startup/StartupMethods.cs b/src/Microsoft.AspNet.Hosting/Startup/StartupMethods.cs new file mode 100644 index 0000000000..4b3a5c9c5c --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/Startup/StartupMethods.cs @@ -0,0 +1,22 @@ +// 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; +using Microsoft.AspNet.Builder; + +namespace Microsoft.AspNet.Hosting.Startup +{ + public class StartupMethods + { + // TODO: switch to ConfigureDelegate eventually + public StartupMethods(Action configure, ConfigureServicesDelegate configureServices) + { + ConfigureDelegate = configure; + ConfigureServicesDelegate = configureServices ?? ApplicationStartup.DefaultBuildServiceProvider; + } + + public ConfigureServicesDelegate ConfigureServicesDelegate { get; } + public Action ConfigureDelegate { get; } + + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/project.json b/src/Microsoft.AspNet.Hosting/project.json index 9d97fb6f7d..4763927417 100644 --- a/src/Microsoft.AspNet.Hosting/project.json +++ b/src/Microsoft.AspNet.Hosting/project.json @@ -6,6 +6,7 @@ "Microsoft.Framework.Runtime.Interfaces": "1.0.0-*", "Microsoft.AspNet.FileProviders": "1.0.0-*", "Microsoft.AspNet.Http.Core": "1.0.0-*", + "Microsoft.AspNet.Http.Extensions": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", "Microsoft.Framework.DependencyInjection": "1.0.0-*", "Newtonsoft.Json": "6.0.6" diff --git a/src/Microsoft.AspNet.RequestContainer/ContainerExtensions.cs b/src/Microsoft.AspNet.RequestContainer/ContainerExtensions.cs deleted file mode 100644 index 919df65864..0000000000 --- a/src/Microsoft.AspNet.RequestContainer/ContainerExtensions.cs +++ /dev/null @@ -1,55 +0,0 @@ -// 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; -using System.Collections.Generic; -using Microsoft.AspNet.RequestContainer; -using Microsoft.AspNet.Hosting; -using Microsoft.Framework.DependencyInjection; - -namespace Microsoft.AspNet.Builder -{ - public static class ContainerExtensions - { - public static IApplicationBuilder UseRequestServices(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); - } - - // Review: what do we use these for? - - public static IApplicationBuilder UseRequestServices(this IApplicationBuilder builder, IServiceProvider applicationServices) - { - // REVIEW: should this be doing fallback? - builder.ApplicationServices = applicationServices; - - return builder.UseMiddleware(); - } - - // Note: Manifests are lost after UseServices, services are flattened into ApplicationServices - - public static IApplicationBuilder UseServices(this IApplicationBuilder builder, IServiceCollection applicationServices) - { - return builder.UseServices(services => services.Add(applicationServices)); - } - - public static IApplicationBuilder UseServices(this IApplicationBuilder builder, Action configureServices) - { - return builder.UseServices(serviceCollection => - { - configureServices(serviceCollection); - return serviceCollection.BuildServiceProvider(); - }); - } - - public static IApplicationBuilder UseServices(this IApplicationBuilder builder, Func configureServices) - { - // Import services from hosting/DNX as fallback - var serviceCollection = HostingServices.Create(builder.ApplicationServices); - - builder.ApplicationServices = configureServices(serviceCollection); - - return builder.UseMiddleware(); - } - } -} diff --git a/src/Microsoft.AspNet.RequestContainer/Microsoft.AspNet.RequestContainer.xproj b/src/Microsoft.AspNet.RequestContainer/Microsoft.AspNet.RequestContainer.xproj deleted file mode 100644 index 9740be9106..0000000000 --- a/src/Microsoft.AspNet.RequestContainer/Microsoft.AspNet.RequestContainer.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 374a5b0c-3e93-4a23-a4a0-ee2ab6df7814 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ - - - 2.0 - - - diff --git a/src/Microsoft.AspNet.RequestContainer/project.json b/src/Microsoft.AspNet.RequestContainer/project.json deleted file mode 100644 index fdb20e9e8f..0000000000 --- a/src/Microsoft.AspNet.RequestContainer/project.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "version": "1.0.0-*", - "description": "ASP.NET 5 enables per-request scoping of services.", - "dependencies": { - "Microsoft.AspNet.Http.Extensions": "1.0.0-*", - "Microsoft.AspNet.Hosting": "1.0.0-*", - "Microsoft.Framework.OptionsModel": "1.0.0-*" - }, - "frameworks": { - "dnx451": {}, - "dnxcore50": { - "dependencies": { - "System.Threading": "4.0.10-beta-*" - } - }, - } -} diff --git a/src/Microsoft.AspNet.TestHost/TestServer.cs b/src/Microsoft.AspNet.TestHost/TestServer.cs index 2a6517a4a2..0cc7b83a65 100644 --- a/src/Microsoft.AspNet.TestHost/TestServer.cs +++ b/src/Microsoft.AspNet.TestHost/TestServer.cs @@ -8,10 +8,10 @@ using Microsoft.AspNet.Builder; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Hosting.Server; +using Microsoft.AspNet.Hosting.Startup; using Microsoft.AspNet.Http; using Microsoft.Framework.ConfigurationModel; using Microsoft.Framework.DependencyInjection; -using Microsoft.Framework.Runtime; using Microsoft.Framework.Runtime.Infrastructure; namespace Microsoft.AspNet.TestHost @@ -25,46 +25,63 @@ namespace Microsoft.AspNet.TestHost private IDisposable _appInstance; private bool _disposed = false; - public TestServer(IConfiguration config, IServiceProvider serviceProvider, Action appStartup) + // REVIEW: we can configure services via AppStartup or via hostContext.Services + public TestServer(IConfiguration config, IServiceProvider serviceProvider, Action configureApp, ConfigureServicesDelegate configureServices) { - var appEnv = serviceProvider.GetRequiredService(); - var applicationLifetime = serviceProvider.GetRequiredService(); - - HostingContext hostContext = new HostingContext() + var hostContext = new HostingContext() { - ApplicationName = appEnv.ApplicationName, - ApplicationLifetime = applicationLifetime, + ApplicationName = "Test App", Configuration = config, ServerFactory = this, - ApplicationStartup = appStartup + StartupMethods = new StartupMethods(configureApp, configureServices) }; - var engine = serviceProvider.GetRequiredService(); - _appInstance = engine.Start(hostContext); + _appInstance = new HostingEngine(serviceProvider).Start(hostContext); } public Uri BaseAddress { get; set; } = new Uri("http://localhost/"); - public static TestServer Create(Action app) + public static TestServer Create(Action configureApp) { - return Create(CallContextServiceLocator.Locator.ServiceProvider, app, configureHostServices: null); + return Create(CallContextServiceLocator.Locator.ServiceProvider, configureApp, configureServices: null); } - public static TestServer Create(Action app, Action configureHostServices) + public static TestServer Create(Action configureApp, Action configureServices) { - return Create(CallContextServiceLocator.Locator.ServiceProvider, app, configureHostServices); + return Create(CallContextServiceLocator.Locator.ServiceProvider, configureApp, + sc => + { + if (configureServices != null) + { + configureServices(sc); + } + return sc.BuildServiceProvider(); + }); } - public static TestServer Create(IServiceProvider serviceProvider, Action app) + public static TestServer Create(IServiceProvider serviceProvider, Action configureApp) { - return Create(serviceProvider, app, configureHostServices: null); + return Create(serviceProvider, configureApp, configureServices: null); } - public static TestServer Create(IServiceProvider serviceProvider, Action app, Action configureHostServices) + public static TestServer Create(IServiceProvider serviceProvider, Action configureApp, Action configureServices) { - var appServices = HostingServices.Create(serviceProvider, configureHostServices).BuildServiceProvider(); + return Create(serviceProvider, configureApp, + sc => + { + if (configureServices != null) + { + configureServices(sc); + } + return sc.BuildServiceProvider(); + }); + } + + public static TestServer Create(IServiceProvider serviceProvider, Action configureApp, ConfigureServicesDelegate configureServices) + { + // REVIEW: do we need an overload that takes Config for Create? var config = new Configuration(); - return new TestServer(config, appServices, app); + return new TestServer(config, serviceProvider, configureApp, configureServices); } public HttpMessageHandler CreateHandler() @@ -124,7 +141,7 @@ namespace Microsoft.AspNet.TestHost { public string Name { - get { return TestServer.ServerName; } + get { return ServerName; } } } } diff --git a/test/Microsoft.AspNet.Hosting.Tests/Fakes/StartupUseServices.cs b/test/Microsoft.AspNet.Hosting.Tests/Fakes/StartupUseServices.cs deleted file mode 100644 index bfd85da550..0000000000 --- a/test/Microsoft.AspNet.Hosting.Tests/Fakes/StartupUseServices.cs +++ /dev/null @@ -1,30 +0,0 @@ -// 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.Builder; -using Microsoft.Framework.DependencyInjection; - -namespace Microsoft.AspNet.Hosting.Fakes -{ - public class StartupUseServices - { - public StartupUseServices() - { - } - - public void ConfigureUseServicesServices(IServiceCollection services) - { - services.Configure(o => o.Configured = true); - services.AddTransient(); - } - - public void Configure(IApplicationBuilder builder) - { - builder.UseServices(services => - { - services.AddTransient(); - services.Configure(o => o.Message = "Configured"); - }); - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Hosting.Tests/Fakes/StartupWithNullConfigureServices.cs b/test/Microsoft.AspNet.Hosting.Tests/Fakes/StartupWithNullConfigureServices.cs new file mode 100644 index 0000000000..b14bf11e99 --- /dev/null +++ b/test/Microsoft.AspNet.Hosting.Tests/Fakes/StartupWithNullConfigureServices.cs @@ -0,0 +1,16 @@ +using System; +using Microsoft.AspNet.Builder; +using Microsoft.Framework.DependencyInjection; + +namespace Microsoft.AspNet.Hosting.Fakes +{ + public class StartupWithNullConfigureServices + { + public IServiceProvider ConfigureServices(IServiceCollection services) + { + return null; + } + + public void Configure(IApplicationBuilder app) { } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs index d6e1e64be5..078bc3681e 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs @@ -18,32 +18,16 @@ namespace Microsoft.AspNet.Hosting { private readonly IList _startInstances = new List(); - [Fact] - public void HostingEngineCanBeResolvedWithDefaultServices() - { - var services = HostingServices.Create().BuildServiceProvider(); - - var engine = services.GetRequiredService(); - - Assert.NotNull(engine); - } - [Fact] public void HostingEngineCanBeStarted() { - var services = HostingServices.Create().BuildServiceProvider(); - - var engine = services.GetRequiredService(); - var applicationLifetime = services.GetRequiredService(); - var context = new HostingContext { - ApplicationLifetime = applicationLifetime, ServerFactory = this, ApplicationName = "Microsoft.AspNet.Hosting.Tests" }; - var engineStart = engine.Start(context); + var engineStart = new HostingEngine().Start(context); Assert.NotNull(engineStart); Assert.Equal(1, _startInstances.Count); @@ -54,39 +38,97 @@ namespace Microsoft.AspNet.Hosting Assert.Equal(1, _startInstances[0].DisposeCalls); } + [Fact] + public void ApplicationNameDefaultsToApplicationEnvironmentName() + { + var context = new HostingContext + { + ServerFactory = this + }; + + var engine = new HostingEngine(); + + using (engine.Start(context)) + { + Assert.Equal("Microsoft.AspNet.Hosting.Tests", context.ApplicationName); + } + } + + [Fact] + public void EnvDefaultsToDevelopmentIfNoConfig() + { + var context = new HostingContext + { + ServerFactory = this + }; + + var engine = new HostingEngine(); + + using (engine.Start(context)) + { + Assert.Equal("Development", context.EnvironmentName); + var env = context.ApplicationServices.GetRequiredService(); + Assert.Equal("Development", env.EnvironmentName); + } + } + + [Fact] + public void EnvDefaultsToDevelopmentConfigValueIfSpecified() + { + var vals = new Dictionary + { + { "ASPNET_ENV", "Staging" } + }; + + var config = new Configuration() + .Add(new MemoryConfigurationSource(vals)); + + var context = new HostingContext + { + ServerFactory = this, + Configuration = config + }; + + var engine = new HostingEngine(); + + using (engine.Start(context)) + { + Assert.Equal("Staging", context.EnvironmentName); + var env = context.ApplicationServices.GetRequiredService(); + Assert.Equal("Staging", env.EnvironmentName); + } + } + [Fact] public void WebRootCanBeResolvedFromTheProjectJson() { - var services = HostingServices.Create().BuildServiceProvider(); - var env = services.GetRequiredService(); + var context = new HostingContext + { + ServerFactory = this + }; + + var engineStart = new HostingEngine().Start(context); + var env = context.ApplicationServices.GetRequiredService(); Assert.Equal(Path.GetFullPath("testroot"), env.WebRootPath); Assert.True(env.WebRootFileProvider.GetFileInfo("TextFile.txt").Exists); } - [Fact] - public void Validate_Environment_Name() - { - var services = HostingServices.Create().BuildServiceProvider(); - var env = services.GetRequiredService(); - Assert.Equal("Development", env.EnvironmentName); - - var config = new Configuration() - .AddCommandLine(new string[] { "--ASPNET_ENV", "Overridden_Environment" }); - - services = HostingServices.Create(fallbackServices: null, configuration: config) - .BuildServiceProvider(); - - env = services.GetRequiredService(); - Assert.Equal("Overridden_Environment", env.EnvironmentName); - } - [Fact] public void IsEnvironment_Extension_Is_Case_Insensitive() { - var services = HostingServices.Create().BuildServiceProvider(); - var env = services.GetRequiredService(); - Assert.True(env.IsEnvironment("Development")); - Assert.True(env.IsEnvironment("developMent")); + var context = new HostingContext + { + ServerFactory = this + }; + + var engine = new HostingEngine(); + + using (engine.Start(context)) + { + var env = context.ApplicationServices.GetRequiredService(); + Assert.True(env.IsEnvironment("Development")); + Assert.True(env.IsEnvironment("developMent")); + } } public void Initialize(IApplicationBuilder builder) diff --git a/test/Microsoft.AspNet.Hosting.Tests/HostingServicesFacts.cs b/test/Microsoft.AspNet.Hosting.Tests/HostingServicesFacts.cs deleted file mode 100644 index a0fff83ac5..0000000000 --- a/test/Microsoft.AspNet.Hosting.Tests/HostingServicesFacts.cs +++ /dev/null @@ -1,210 +0,0 @@ -// 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; -using System.Collections.Generic; -using Microsoft.AspNet.Hosting.Fakes; -using Microsoft.Framework.DependencyInjection; -using Microsoft.Framework.Runtime; -using Xunit; - -namespace Microsoft.AspNet.Hosting.Tests -{ - public class HostingServicesFacts - { - [Fact] - public void CreateImportsServices() - { - // Arrange - var fallbackServices = new ServiceCollection(); - fallbackServices.AddSingleton(); - var instance = new FakeService(); - var factoryInstance = new FakeFactoryService(instance); - fallbackServices.AddInstance(instance); - fallbackServices.AddTransient(); - fallbackServices.AddSingleton(serviceProvider => factoryInstance); - fallbackServices.AddTransient(); // Don't register in manifest - - fallbackServices.AddInstance(new ServiceManifest( - new Type[] { - typeof(IFakeServiceInstance), - typeof(IFakeService), - typeof(IFakeSingletonService), - typeof(IFactoryService), - typeof(INonexistentService) - })); - - var services = HostingServices.Create(fallbackServices.BuildServiceProvider()); - - // Act - var provider = services.BuildServiceProvider(); - var singleton = provider.GetRequiredService(); - var transient = provider.GetRequiredService(); - var factory = provider.GetRequiredService(); - - // Assert - Assert.Same(singleton, provider.GetRequiredService()); - Assert.NotSame(transient, provider.GetRequiredService()); - Assert.Same(instance, provider.GetRequiredService()); - Assert.Same(factoryInstance, factory); - Assert.Same(factory.FakeService, instance); - Assert.Null(provider.GetService()); - Assert.Null(provider.GetService()); // Make sure we don't leak non manifest services - } - - [Fact] - public void CreateCanAddAdditionalServices() - { - // Arrange - var fallbackServices = new ServiceCollection(); - fallbackServices.AddTransient(); - fallbackServices.AddTransient(); // Don't register in manifest - - fallbackServices.AddInstance(new ServiceManifest( - new Type[] { - typeof(IFakeService), - })); - - var instance = new FakeService(); - var factoryInstance = new FakeFactoryService(instance); - - var services = HostingServices.Create(fallbackServices.BuildServiceProvider(), - additionalHostServices => - { - additionalHostServices.AddSingleton(); - additionalHostServices.AddInstance(instance); - additionalHostServices.AddSingleton(serviceProvider => factoryInstance); - }); - - // Act - var provider = services.BuildServiceProvider(); - var singleton = provider.GetRequiredService(); - var transient = provider.GetRequiredService(); - var factory = provider.GetRequiredService(); - var manifest = provider.GetRequiredService(); - - // Assert - Assert.Same(singleton, provider.GetRequiredService()); - Assert.NotSame(transient, provider.GetRequiredService()); - Assert.Same(instance, provider.GetRequiredService()); - Assert.Same(factoryInstance, factory); - Assert.Same(factory.FakeService, instance); - Assert.Null(provider.GetService()); - Assert.Null(provider.GetService()); // Make sure we don't leak non manifest services - Assert.Contains(typeof(IFakeSingletonService), manifest.Services); - Assert.Contains(typeof(IFakeServiceInstance), manifest.Services); - Assert.Contains(typeof(IFactoryService), manifest.Services); - } - - [Fact] - public void CreateAdditionalServicesOverridesFallback() - { - // Arrange - var fallbackServices = new ServiceCollection(); - fallbackServices.AddTransient(); - - fallbackServices.AddInstance(new ServiceManifest( - new Type[] { - typeof(IFakeService), - })); - - var services = HostingServices.Create(fallbackServices.BuildServiceProvider(), - additionalHostServices => additionalHostServices.AddSingleton()); - - // Act - var provider = services.BuildServiceProvider(); - var singleton = provider.GetRequiredService(); - - // Assert - Assert.Same(singleton, provider.GetRequiredService()); - } - - [Fact] - public void CreateAdditionalServices_IncludesServicesInManifest() - { - // Arrange - var fallbackServices = new ServiceCollection(); - fallbackServices.AddTransient(); - fallbackServices.AddInstance(new ServiceManifest( - new Type[] { - typeof(IFakeService), - })); - var expectedInstance = new FakeService(); - var services = HostingServices.Create( - fallbackServices.BuildServiceProvider(), - additionalHostServices => additionalHostServices.AddInstance(expectedInstance)); - - // Act - var provider = services.BuildServiceProvider(); - var instance = provider.GetRequiredService(); - var anotherInstance = provider.GetRequiredService(); - var manifest = provider.GetRequiredService(); - - // Assert - Assert.Same(expectedInstance, instance); - Assert.Same(expectedInstance, anotherInstance); - Assert.Contains(typeof(IFakeServiceInstance), manifest.Services); - } - - [Fact] - public void CanHideImportedServices() - { - // Arrange - var fallbackServices = new ServiceCollection(); - var fallbackInstance = new FakeService(); - fallbackServices.AddInstance(fallbackInstance); - fallbackServices.AddInstance(new ServiceManifest(new Type[] { typeof(IFakeService) })); - - var services = HostingServices.Create(fallbackServices.BuildServiceProvider()); - var realInstance = new FakeService(); - services.AddInstance(realInstance); - - // Act - var provider = services.BuildServiceProvider(); - - // Assert - Assert.Equal(realInstance, provider.GetRequiredService()); - } - - [Fact] - public void CreateThrowsWithNoManifest() - { - // Arrange - var fallbackServices = new ServiceCollection(); - fallbackServices.AddSingleton(); - var instance = new FakeService(); - fallbackServices.AddInstance(instance); - fallbackServices.AddTransient(); - - // Act - var exception = Assert.Throws(() => HostingServices.Create(fallbackServices.BuildServiceProvider())); - - - // Assert - Assert.Equal($"No service for type '{typeof(IServiceManifest).FullName}' has been registered.", - exception.Message); - } - - private class ServiceManifest : IServiceManifest - { - public ServiceManifest(IEnumerable services) - { - Services = services; - } - - public IEnumerable Services { get; private set; } - } - - private class FakeFactoryService : IFactoryService - { - public FakeFactoryService(FakeService service) - { - FakeService = service; - } - - public IFakeService FakeService { get; private set; } - - public int Value { get; private set; } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs b/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs index cefc9877e7..a7ecf91aaa 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs @@ -12,7 +12,6 @@ using Xunit; namespace Microsoft.AspNet.Hosting.Tests { - public class StartupManagerTests : IFakeStartupCallback { private readonly IList _configurationMethodCalledList = new List(); @@ -20,16 +19,16 @@ namespace Microsoft.AspNet.Hosting.Tests [Fact] public void StartupClassMayHaveHostingServicesInjected() { - var serviceCollection = new ServiceCollection().AddHosting(); + var serviceCollection = new ServiceCollection(); serviceCollection.AddInstance(this); var services = serviceCollection.BuildServiceProvider(); - var loader = services.GetRequiredService(); - var diagnosticMessages = new List(); - var startup = loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", "WithServices", diagnosticMessages); + var startup = ApplicationStartup.LoadStartupMethods(services, "Microsoft.AspNet.Hosting.Tests", "WithServices", diagnosticMessages); - startup.Invoke(new ApplicationBuilder(services)); + var app = new ApplicationBuilder(services); + app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection); + startup.ConfigureDelegate(app); Assert.Equal(2, _configurationMethodCalledList.Count); } @@ -45,15 +44,14 @@ namespace Microsoft.AspNet.Hosting.Tests [InlineData("BaseClass")] public void StartupClassAddsConfigureServicesToApplicationServices(string environment) { - var services = HostingServices.Create().BuildServiceProvider(); - var loader = services.GetRequiredService(); + var services = new ServiceCollection().BuildServiceProvider(); var diagnosticMesssages = new List(); - var startup = loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", environment ?? "", diagnosticMesssages); + var startup = ApplicationStartup.LoadStartupMethods(services, "Microsoft.AspNet.Hosting.Tests", environment ?? "", diagnosticMesssages); var app = new ApplicationBuilder(services); - - startup.Invoke(app); + app.ApplicationServices = startup.ConfigureServicesDelegate(new ServiceCollection()); + startup.ConfigureDelegate(app); var options = app.ApplicationServices.GetRequiredService>().Options; Assert.NotNull(options); @@ -61,92 +59,46 @@ namespace Microsoft.AspNet.Hosting.Tests Assert.Equal(environment, options.Environment); } - [Theory] - [InlineData("Null")] - [InlineData("FallbackProvider")] - public void StartupClassConfigureServicesThatFallsbackToApplicationServices(string env) - { - var services = HostingServices.Create().BuildServiceProvider(); - var loader = services.GetRequiredService(); - var diagnosticMessages = new List(); - - var startup = loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", env, diagnosticMessages); - - var app = new ApplicationBuilder(services); - - startup.Invoke(app); - - Assert.Equal(services, app.ApplicationServices); - } - - // REVIEW: With the manifest change, Since the ConfigureServices are not imported, UseServices will mask what's in ConfigureServices - // This will throw since ConfigureServices consumes manifest and then UseServices will blow up - [Fact(Skip = "Review Failure")] - public void StartupClassWithConfigureServicesAndUseServicesHidesConfigureServices() - { - var services = HostingServices.Create().BuildServiceProvider(); - var loader = services.GetRequiredService(); - var diagnosticMessages = new List(); - - var startup = loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", "UseServices", diagnosticMessages); - - var app = new ApplicationBuilder(services); - - startup.Invoke(app); - - Assert.NotNull(app.ApplicationServices.GetRequiredService()); - Assert.Null(app.ApplicationServices.GetService()); - - var options = app.ApplicationServices.GetRequiredService>().Options; - Assert.NotNull(options); - Assert.Equal("Configured", options.Message); - Assert.False(options.Configured); // Options never resolved from inner containers - } - [Fact] public void StartupWithNoConfigureThrows() { - var serviceCollection = HostingServices.Create(); + var serviceCollection = new ServiceCollection(); serviceCollection.AddInstance(this); var services = serviceCollection.BuildServiceProvider(); - var loader = services.GetRequiredService(); var diagnosticMessages = new List(); - var ex = Assert.Throws(() => loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", "Boom", diagnosticMessages)); + var ex = Assert.Throws(() => ApplicationStartup.LoadStartupMethods(services, "Microsoft.AspNet.Hosting.Tests", "Boom", diagnosticMessages)); Assert.Equal("A method named 'ConfigureBoom' or 'Configure' in the type 'Microsoft.AspNet.Hosting.Fakes.StartupBoom' could not be found.", ex.Message); } [Fact] - public void StartupWithConfigureServicesNotResolvedThrows() + public void StartupClassCanHandleConfigureServicesThatReturnsNull() { - var serviceCollection = HostingServices.Create(); + var serviceCollection = new ServiceCollection(); var services = serviceCollection.BuildServiceProvider(); - var loader = services.GetRequiredService(); + var diagnosticMessages = new List(); - - var startup = loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", "WithConfigureServicesNotResolved", diagnosticMessages); - + var startup = ApplicationStartup.LoadStartupMethods(services, "Microsoft.AspNet.Hosting.Tests", "WithNullConfigureServices", diagnosticMessages); var app = new ApplicationBuilder(services); - - var ex = Assert.Throws(() => startup.Invoke(app)); - - Assert.Equal("Could not resolve a service of type 'System.Int32' for the parameter 'notAService' of method 'Configure' on type 'Microsoft.AspNet.Hosting.Fakes.StartupWithConfigureServicesNotResolved'.", ex.Message); + app.ApplicationServices = startup.ConfigureServicesDelegate(new ServiceCollection()); + Assert.NotNull(app.ApplicationServices); + startup.ConfigureDelegate(app); + Assert.NotNull(app.ApplicationServices); } [Fact] public void StartupClassWithConfigureServicesShouldMakeServiceAvailableInConfigure() { - var serviceCollection = HostingServices.Create(); + var serviceCollection = new ServiceCollection(); var services = serviceCollection.BuildServiceProvider(); - var loader = services.GetRequiredService(); - - var app = new ApplicationBuilder(services); var diagnosticMessages = new List(); - var startup = loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", "WithConfigureServices", diagnosticMessages); + var startup = ApplicationStartup.LoadStartupMethods(services, "Microsoft.AspNet.Hosting.Tests", "WithConfigureServices", diagnosticMessages); - startup.Invoke(app); + var app = new ApplicationBuilder(services); + app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection); + startup.ConfigureDelegate(app); var foo = app.ApplicationServices.GetRequiredService(); Assert.True(foo.Invoked); diff --git a/test/Microsoft.AspNet.Hosting.Tests/UseRequestServicesFacts.cs b/test/Microsoft.AspNet.Hosting.Tests/UseRequestServicesFacts.cs deleted file mode 100644 index 0e235a45db..0000000000 --- a/test/Microsoft.AspNet.Hosting.Tests/UseRequestServicesFacts.cs +++ /dev/null @@ -1,98 +0,0 @@ -// 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; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.RequestContainer; -using Microsoft.Framework.DependencyInjection; -using Microsoft.Framework.Logging; -using Xunit; - -namespace Microsoft.AspNet.Hosting.Tests -{ - public class RequestServicesContainerFacts - { - [Fact] - public void RequestServicesAvailableOnlyAfterRequestServices() - { - var baseServiceProvider = HostingServices.Create().BuildServiceProvider(); - var builder = new ApplicationBuilder(baseServiceProvider); - - bool foundRequestServicesBefore = false; - builder.Use(next => async c => - { - foundRequestServicesBefore = c.RequestServices != null; - await next.Invoke(c); - }); - builder.UseRequestServices(); - bool foundRequestServicesAfter = false; - builder.Use(next => async c => - { - foundRequestServicesAfter = c.RequestServices != null; - await next.Invoke(c); - }); - - var context = new DefaultHttpContext(); - builder.Build().Invoke(context); - Assert.False(foundRequestServicesBefore); - Assert.True(foundRequestServicesAfter); - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void EnsureRequestServicesSetsRequestServices(bool initializeApplicationServices) - { - var baseServiceProvider = HostingServices.Create().BuildServiceProvider(); - var builder = new ApplicationBuilder(baseServiceProvider); - - bool foundRequestServicesBefore = false; - builder.Use(next => async c => - { - foundRequestServicesBefore = c.RequestServices != null; - await next.Invoke(c); - }); - builder.Use(next => async c => - { - using (var container = RequestServicesContainer.EnsureRequestServices(c, baseServiceProvider)) - { - await next.Invoke(c); - } - }); - bool foundRequestServicesAfter = false; - builder.Use(next => async c => - { - foundRequestServicesAfter = c.RequestServices != null; - await next.Invoke(c); - }); - - var context = new DefaultHttpContext(); - if (initializeApplicationServices) - { - context.ApplicationServices = baseServiceProvider; - } - builder.Build().Invoke(context); - Assert.False(foundRequestServicesBefore); - Assert.True(foundRequestServicesAfter); - } - - [Theory] - [InlineData(typeof(IHostingEnvironment))] - [InlineData(typeof(ILoggerFactory))] - [InlineData(typeof(IHttpContextAccessor))] - [InlineData(typeof(IApplicationLifetime))] - public void UseRequestServicesHostingImportedServicesAreDefined(Type service) - { - var baseServiceProvider = HostingServices.Create().BuildServiceProvider(); - var builder = new ApplicationBuilder(baseServiceProvider); - - builder.UseRequestServices(); - - var fromAppServices = builder.ApplicationServices.GetRequiredService(service); - - Assert.NotNull(fromAppServices); - Assert.Equal(baseServiceProvider.GetRequiredService(service), fromAppServices); - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Hosting.Tests/project.json b/test/Microsoft.AspNet.Hosting.Tests/project.json index a87f3cffd7..aa3d3b7bb0 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/project.json +++ b/test/Microsoft.AspNet.Hosting.Tests/project.json @@ -2,7 +2,7 @@ "dependencies": { "Microsoft.AspNet.Hosting": "1.0.0-*", "Microsoft.AspNet.Owin": "1.0.0-*", - "Microsoft.AspNet.RequestContainer": "1.0.0-*", + "Microsoft.Framework.OptionsModel": "1.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, "frameworks": { diff --git a/test/Microsoft.AspNet.TestHost.Tests/ClientHandlerTests.cs b/test/Microsoft.AspNet.TestHost.Tests/ClientHandlerTests.cs index c92a8ca35c..74838032eb 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/ClientHandlerTests.cs +++ b/test/Microsoft.AspNet.TestHost.Tests/ClientHandlerTests.cs @@ -10,7 +10,6 @@ using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.Http; using Xunit; namespace Microsoft.AspNet.TestHost diff --git a/test/Microsoft.AspNet.TestHost.Tests/TestApplicationEnvironment.cs b/test/Microsoft.AspNet.TestHost.Tests/TestApplicationEnvironment.cs deleted file mode 100644 index de715c253c..0000000000 --- a/test/Microsoft.AspNet.TestHost.Tests/TestApplicationEnvironment.cs +++ /dev/null @@ -1,37 +0,0 @@ -// 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; -using System.Runtime.Versioning; -using Microsoft.Framework.Runtime; - -namespace Microsoft.AspNet.TestHost -{ - public class TestApplicationEnvironment : IApplicationEnvironment - { - public string ApplicationName - { - get { return "Test App environment"; } - } - - public string Version - { - get { return "1.0.0"; } - } - - public string ApplicationBasePath - { - get { return Environment.CurrentDirectory; } - } - - public string Configuration - { - get { return "Test"; } - } - - public FrameworkName RuntimeFramework - { - get { return new FrameworkName(".NETFramework", new Version(4, 5)); } - } - } -} diff --git a/test/Microsoft.AspNet.TestHost.Tests/TestClientTests.cs b/test/Microsoft.AspNet.TestHost.Tests/TestClientTests.cs index b392bac6ad..19b54c06f5 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/TestClientTests.cs +++ b/test/Microsoft.AspNet.TestHost.Tests/TestClientTests.cs @@ -20,9 +20,7 @@ namespace Microsoft.AspNet.TestHost public TestClientTests() { - _services = HostingServices.Create().BuildServiceProvider(); - - _server = TestServer.Create(_services, app => app.Run(ctx => Task.FromResult(0))); + _server = TestServer.Create(app => app.Run(ctx => Task.FromResult(0))); } [Fact] @@ -32,7 +30,7 @@ namespace Microsoft.AspNet.TestHost var expected = "GET Response"; RequestDelegate appDelegate = ctx => ctx.Response.WriteAsync(expected); - var server = TestServer.Create(_services, app => app.Run(appDelegate)); + var server = TestServer.Create(app => app.Run(appDelegate)); var client = server.CreateClient(); // Act @@ -53,7 +51,7 @@ namespace Microsoft.AspNet.TestHost Assert.Equal("/", ctx.Request.Path.Value); return ctx.Response.WriteAsync(expected); }; - var server = TestServer.Create(_services, app => app.Run(appDelegate)); + var server = TestServer.Create(app => app.Run(appDelegate)); var client = server.CreateClient(); // Act @@ -74,7 +72,7 @@ namespace Microsoft.AspNet.TestHost Assert.Equal("/", ctx.Request.Path.Value); return ctx.Response.WriteAsync(expected); }; - var server = TestServer.Create(_services, app => app.Run(appDelegate)); + var server = TestServer.Create(app => app.Run(appDelegate)); var client = server.CreateClient(); // Act @@ -90,7 +88,7 @@ namespace Microsoft.AspNet.TestHost // Arrange RequestDelegate appDelegate = ctx => ctx.Response.WriteAsync(new StreamReader(ctx.Request.Body).ReadToEnd() + " PUT Response"); - var server = TestServer.Create(_services, app => app.Run(appDelegate)); + var server = TestServer.Create(app => app.Run(appDelegate)); var client = server.CreateClient(); // Act @@ -107,7 +105,7 @@ namespace Microsoft.AspNet.TestHost // Arrange RequestDelegate appDelegate = async ctx => await ctx.Response.WriteAsync(new StreamReader(ctx.Request.Body).ReadToEnd() + " POST Response"); - var server = TestServer.Create(_services, app => app.Run(appDelegate)); + var server = TestServer.Create(app => app.Run(appDelegate)); var client = server.CreateClient(); // Act diff --git a/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs b/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs index 899d3be45a..f3a3fc0bef 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs +++ b/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs @@ -21,10 +21,8 @@ namespace Microsoft.AspNet.TestHost public void CreateWithDelegate() { // Arrange - var services = HostingServices.Create().BuildServiceProvider(); - // Act & Assert (Does not throw) - TestServer.Create(services, app => { }); + TestServer.Create(app => { }); } [Fact] @@ -37,6 +35,21 @@ namespace Microsoft.AspNet.TestHost Assert.Throws(() => TestServer.Create(services, new Startup().Configuration)); } + [Fact] + public async Task RequestServicesAutoCreated() + { + TestServer server = TestServer.Create(app => + { + app.Run(context => + { + return context.Response.WriteAsync("RequestServices:" + (context.RequestServices != null)); + }); + }); + + string result = await server.CreateClient().GetStringAsync("/path"); + Assert.Equal("RequestServices:True", result); + } + [Fact] public async Task CanAccessLogger() { @@ -92,7 +105,8 @@ namespace Microsoft.AspNet.TestHost var accessor = app.ApplicationServices.GetRequiredService(); return context.Response.WriteAsync("HasContext:" + (accessor.Accessor.HttpContext != null)); }); - }, newHostServices => newHostServices.AddSingleton()); + }, + services => services.AddSingleton().BuildServiceProvider()); string result = await server.CreateClient().GetStringAsync("/path"); Assert.Equal("HasContext:True", result);