diff --git a/src/Microsoft.AspNet.Hosting/HostingEngine.cs b/src/Microsoft.AspNet.Hosting/HostingEngine.cs deleted file mode 100644 index 4889150d04..0000000000 --- a/src/Microsoft.AspNet.Hosting/HostingEngine.cs +++ /dev/null @@ -1,257 +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 System.Threading; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Hosting.Builder; -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.Logging; - -namespace Microsoft.AspNet.Hosting -{ - public class HostingEngine : IHostingEngine - { - private readonly IServiceCollection _applicationServiceCollection; - private readonly IStartupLoader _startupLoader; - private readonly ApplicationLifetime _applicationLifetime; - private readonly IHostingEnvironment _hostingEnvironment; - private readonly IConfiguration _config; - - // Start/ApplicationServices block use methods - private bool _useDisabled; - - private IApplicationBuilderFactory _builderFactory; - private IApplicationBuilder _builder; - private IServiceProvider _applicationServices; - - // Only one of these should be set - private string _startupAssemblyName; - private StartupMethods _startup; - - // Only one of these should be set - private string _serverFactoryLocation; - private IServerFactory _serverFactory; - private IServerInformation _serverInstance; - - public HostingEngine(IServiceCollection appServices, IStartupLoader startupLoader, IConfiguration config, IHostingEnvironment hostingEnv, string appName) - { - _config = config ?? new Configuration(); - _applicationServiceCollection = appServices; - _startupLoader = startupLoader; - _startupAssemblyName = appName; - _applicationLifetime = new ApplicationLifetime(); - _hostingEnvironment = hostingEnv; - } - - public virtual IDisposable Start() - { - EnsureApplicationServices(); - EnsureServer(); - EnsureBuilder(); - - var applicationDelegate = BuildApplicationDelegate(); - - var logger = _applicationServices.GetRequiredService>(); - var contextFactory = _applicationServices.GetRequiredService(); - var contextAccessor = _applicationServices.GetRequiredService(); - var server = _serverFactory.Start(_serverInstance, - async features => - { - var httpContext = contextFactory.CreateHttpContext(features); - var requestIdentifier = GetRequestIdentifier(httpContext); - - using (logger.BeginScope("Request Id: {RequestId}", requestIdentifier)) - { - contextAccessor.HttpContext = httpContext; - await applicationDelegate(httpContext); - } - }); - - return new Disposable(() => - { - _applicationLifetime.NotifyStopping(); - server.Dispose(); - _applicationLifetime.NotifyStopped(); - }); - } - - private void EnsureApplicationServices() - { - _useDisabled = true; - EnsureStartup(); - - _applicationServiceCollection.AddInstance(_applicationLifetime); - - _applicationServices = _startup.ConfigureServicesDelegate(_applicationServiceCollection); - } - - private void EnsureStartup() - { - if (_startup != null) - { - return; - } - - var diagnosticMessages = new List(); - _startup = _startupLoader.Load( - _startupAssemblyName, - _hostingEnvironment.EnvironmentName, - diagnosticMessages); - - if (_startup == null) - { - throw new ArgumentException( - diagnosticMessages.Aggregate("Failed to find a startup entry point for the web application.", (a, b) => a + "\r\n" + b), - _startupAssemblyName); - } - } - - private void EnsureServer() - { - if (_serverFactory == null) - { - // Blow up if we don't have a server set at this point - if (_serverFactoryLocation == null) - { - throw new InvalidOperationException("UseStartup() is required for Start()"); - } - - _serverFactory = _applicationServices.GetRequiredService().LoadServerFactory(_serverFactoryLocation); - } - - _serverInstance = _serverFactory.Initialize(_config); - } - - private void EnsureBuilder() - { - if (_builderFactory == null) - { - _builderFactory = _applicationServices.GetRequiredService(); - } - - _builder = _builderFactory.CreateBuilder(_serverInstance); - _builder.ApplicationServices = _applicationServices; - } - - private RequestDelegate BuildApplicationDelegate() - { - var startupFilters = _applicationServices.GetService>(); - var configure = _startup.ConfigureDelegate; - foreach (var filter in startupFilters) - { - configure = filter.Configure(_builder, configure); - } - - configure(_builder); - - return _builder.Build(); - } - - public IServiceProvider ApplicationServices - { - get - { - EnsureApplicationServices(); - return _applicationServices; - } - } - - private void CheckUseAllowed() - { - if (_useDisabled) - { - throw new InvalidOperationException("HostingEngine has already been started."); - } - } - - private Guid GetRequestIdentifier(HttpContext httpContext) - { - var requestIdentifierFeature = httpContext.GetFeature(); - if (requestIdentifierFeature == null) - { - requestIdentifierFeature = new DefaultRequestIdentifierFeature(); - httpContext.SetFeature(requestIdentifierFeature); - } - - return requestIdentifierFeature.TraceIdentifier; - } - - // Consider cutting - public IHostingEngine UseEnvironment(string environment) - { - CheckUseAllowed(); - _hostingEnvironment.EnvironmentName = environment; - return this; - } - - public IHostingEngine UseServer(string assemblyName) - { - CheckUseAllowed(); - _serverFactoryLocation = assemblyName; - return this; - } - - public IHostingEngine UseServer(IServerFactory factory) - { - CheckUseAllowed(); - _serverFactory = factory; - return this; - } - - public IHostingEngine UseStartup(string startupAssemblyName) - { - CheckUseAllowed(); - _startupAssemblyName = startupAssemblyName; - return this; - } - - public IHostingEngine UseStartup(Action configureApp) - { - return UseStartup(configureApp, configureServices: null); - } - - public IHostingEngine UseStartup(Action configureApp, ConfigureServicesDelegate configureServices) - { - CheckUseAllowed(); - _startup = new StartupMethods(configureApp, configureServices); - return this; - } - - public IHostingEngine UseStartup(Action configureApp, Action configureServices) - { - CheckUseAllowed(); - _startup = new StartupMethods(configureApp, - services => { - if (configureServices != null) - { - configureServices(services); - } - return services.BuildServiceProvider(); - }); - return this; - } - - private class Disposable : IDisposable - { - private Action _dispose; - - public Disposable(Action dispose) - { - _dispose = dispose; - } - - public void Dispose() - { - Interlocked.Exchange(ref _dispose, () => { }).Invoke(); - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/HostingFactory.cs b/src/Microsoft.AspNet.Hosting/HostingFactory.cs deleted file mode 100644 index 1b77dc7e59..0000000000 --- a/src/Microsoft.AspNet.Hosting/HostingFactory.cs +++ /dev/null @@ -1,35 +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.Internal; -using Microsoft.AspNet.Hosting.Startup; -using Microsoft.Framework.ConfigurationModel; -using Microsoft.Framework.Runtime; - -namespace Microsoft.AspNet.Hosting -{ - public class HostingFactory : IHostingFactory - { - public const string EnvironmentKey = "ASPNET_ENV"; - - private readonly RootHostingServiceCollectionInitializer _serviceInitializer; - private readonly IStartupLoader _startupLoader; - private readonly IApplicationEnvironment _applicationEnvironment; - private readonly IHostingEnvironment _hostingEnvironment; - - public HostingFactory(RootHostingServiceCollectionInitializer initializer, IStartupLoader startupLoader, IApplicationEnvironment appEnv, IHostingEnvironment hostingEnv) - { - _serviceInitializer = initializer; - _startupLoader = startupLoader; - _applicationEnvironment = appEnv; - _hostingEnvironment = hostingEnv; - } - - public IHostingEngine Create(IConfiguration config) - { - _hostingEnvironment.Initialize(_applicationEnvironment.ApplicationBasePath, config?[EnvironmentKey]); - - return new HostingEngine(_serviceInitializer.Build(), _startupLoader, config, _hostingEnvironment, _applicationEnvironment.ApplicationName); - } - } -} \ 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 dbd6577b05..0000000000 --- a/src/Microsoft.AspNet.Hosting/IHostingEngine.cs +++ /dev/null @@ -1,32 +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.Hosting.Server; -using Microsoft.AspNet.Hosting.Startup; -using Microsoft.Framework.DependencyInjection; - -namespace Microsoft.AspNet.Hosting -{ - public interface IHostingEngine - { - IDisposable Start(); - - // Accessing this will block Use methods - IServiceProvider ApplicationServices { get; } - - // Use methods blow up after any of the above methods are called - IHostingEngine UseEnvironment(string environment); - - // Mutually exclusive - IHostingEngine UseServer(string assemblyName); - IHostingEngine UseServer(IServerFactory factory); - - // Mutually exclusive - IHostingEngine UseStartup(string startupAssemblyName); - IHostingEngine UseStartup(Action configureApp); - IHostingEngine UseStartup(Action configureApp, ConfigureServicesDelegate configureServices); - IHostingEngine UseStartup(Action configureApp, Action configureServices); - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/IHostingFactory.cs b/src/Microsoft.AspNet.Hosting/IHostingFactory.cs deleted file mode 100644 index f44b02c1db..0000000000 --- a/src/Microsoft.AspNet.Hosting/IHostingFactory.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 Microsoft.Framework.ConfigurationModel; - -namespace Microsoft.AspNet.Hosting -{ - public interface IHostingFactory - { - IHostingEngine Create(IConfiguration config); - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs b/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs new file mode 100644 index 0000000000..86bbee3936 --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs @@ -0,0 +1,184 @@ +// 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 System.Threading; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting.Builder; +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.Internal; +using Microsoft.Framework.Logging; + +namespace Microsoft.AspNet.Hosting.Internal +{ + public class HostingEngine : IHostingEngine + { + private readonly IServiceCollection _applicationServiceCollection; + private readonly IStartupLoader _startupLoader; + private readonly ApplicationLifetime _applicationLifetime; + private readonly IConfiguration _config; + + private IServiceProvider _applicationServices; + + // Only one of these should be set + internal string StartupAssemblyName { get; set; } + internal StartupMethods Startup { get; set; } + internal Type StartupType { get; set; } + + // Only one of these should be set + internal IServerFactory ServerFactory { get; set; } + internal string ServerFactoryLocation { get; set; } + private IServerInformation _serverInstance; + + public HostingEngine( + [NotNull] IServiceCollection appServices, + [NotNull] IStartupLoader startupLoader, + [NotNull] IConfiguration config) + { + _config = config; + _applicationServiceCollection = appServices; + _startupLoader = startupLoader; + _applicationLifetime = new ApplicationLifetime(); + } + + public IServiceProvider ApplicationServices + { + get + { + EnsureApplicationServices(); + return _applicationServices; + } + } + + public virtual IDisposable Start() + { + EnsureApplicationServices(); + + var application = BuildApplication(); + + var logger = _applicationServices.GetRequiredService>(); + var contextFactory = _applicationServices.GetRequiredService(); + var contextAccessor = _applicationServices.GetRequiredService(); + var server = ServerFactory.Start(_serverInstance, + async features => + { + var httpContext = contextFactory.CreateHttpContext(features); + var requestIdentifier = GetRequestIdentifier(httpContext); + + using (logger.BeginScope("Request Id: {RequestId}", requestIdentifier)) + { + contextAccessor.HttpContext = httpContext; + await application(httpContext); + } + }); + + return new Disposable(() => + { + _applicationLifetime.NotifyStopping(); + server.Dispose(); + _applicationLifetime.NotifyStopped(); + }); + } + + private void EnsureApplicationServices() + { + EnsureStartup(); + + _applicationServiceCollection.AddInstance(_applicationLifetime); + + _applicationServices = Startup.ConfigureServicesDelegate(_applicationServiceCollection); + } + + private void EnsureStartup() + { + if (Startup != null) + { + return; + } + + if (StartupType == null) + { + var diagnosticTypeMessages = new List(); + StartupType = _startupLoader.FindStartupType(StartupAssemblyName, diagnosticTypeMessages); + if (StartupType == null) + { + throw new ArgumentException( + diagnosticTypeMessages.Aggregate("Failed to find a startup type for the web application.", (a, b) => a + "\r\n" + b), + StartupAssemblyName); + } + } + + var diagnosticMessages = new List(); + Startup = _startupLoader.LoadMethods(StartupType, diagnosticMessages); + if (Startup == null) + { + throw new ArgumentException( + diagnosticMessages.Aggregate("Failed to find a startup entry point for the web application.", (a, b) => a + "\r\n" + b), + StartupAssemblyName); + } + } + + private RequestDelegate BuildApplication() + { + if (ServerFactory == null) + { + // Blow up if we don't have a server set at this point + if (ServerFactoryLocation == null) + { + throw new InvalidOperationException("IHostingBuilder.UseServer() is required for " + nameof(Start) + "()"); + } + + ServerFactory = _applicationServices.GetRequiredService().LoadServerFactory(ServerFactoryLocation); + } + + _serverInstance = ServerFactory.Initialize(_config); + var builderFactory = _applicationServices.GetRequiredService(); + var builder = builderFactory.CreateBuilder(_serverInstance); + builder.ApplicationServices = _applicationServices; + + var startupFilters = _applicationServices.GetService>(); + var configure = Startup.ConfigureDelegate; + foreach (var filter in startupFilters) + { + configure = filter.Configure(builder, configure); + } + + configure(builder); + + return builder.Build(); + } + + private Guid GetRequestIdentifier(HttpContext httpContext) + { + var requestIdentifierFeature = httpContext.GetFeature(); + if (requestIdentifierFeature == null) + { + requestIdentifierFeature = new DefaultRequestIdentifierFeature(); + httpContext.SetFeature(requestIdentifierFeature); + } + + return requestIdentifierFeature.TraceIdentifier; + } + + private class Disposable : IDisposable + { + private Action _dispose; + + public Disposable(Action dispose) + { + _dispose = dispose; + } + + public void Dispose() + { + Interlocked.Exchange(ref _dispose, () => { }).Invoke(); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/Internal/IHostingEngine.cs b/src/Microsoft.AspNet.Hosting/Internal/IHostingEngine.cs new file mode 100644 index 0000000000..f79031eb0f --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/Internal/IHostingEngine.cs @@ -0,0 +1,15 @@ +// 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.Internal +{ + public interface IHostingEngine + { + IDisposable Start(); + + // Accessing this will block Use methods + IServiceProvider ApplicationServices { get; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/Internal/RootHostingServiceCollectionInitializer.cs b/src/Microsoft.AspNet.Hosting/Internal/RootHostingServiceCollectionInitializer.cs deleted file mode 100644 index 3e9a9babec..0000000000 --- a/src/Microsoft.AspNet.Hosting/Internal/RootHostingServiceCollectionInitializer.cs +++ /dev/null @@ -1,66 +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.Hosting.Builder; -using Microsoft.AspNet.Hosting.Internal; -using Microsoft.AspNet.Hosting.Server; -using Microsoft.AspNet.Hosting.Startup; -using Microsoft.Framework.DependencyInjection; -using Microsoft.Framework.Logging; -using Microsoft.Framework.Runtime; -using Microsoft.Framework.Runtime.Infrastructure; - -namespace Microsoft.AspNet.Hosting.Internal -{ - public class RootHostingServiceCollectionInitializer - { - private readonly IServiceProvider _fallbackServices; - private readonly Action _configureServices; - private readonly IHostingEnvironment _hostingEnvironment; - private readonly ILoggerFactory _loggerFactory; - - public RootHostingServiceCollectionInitializer(IServiceProvider fallbackServices, Action configureServices) - { - _fallbackServices = fallbackServices; - _configureServices = configureServices; - _hostingEnvironment = new HostingEnvironment(); - _loggerFactory = new LoggerFactory(); - } - - public IServiceCollection Build() - { - var services = new ServiceCollection(); - - // Import from manifest - var manifest = _fallbackServices.GetRequiredService(); - foreach (var service in manifest.Services) - { - services.AddTransient(service, sp => _fallbackServices.GetService(service)); - } - - services.AddInstance(_hostingEnvironment); - services.AddInstance(this); - services.AddInstance(_loggerFactory); - - services.AddTransient(); - services.AddTransient(); - - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddSingleton(); - services.AddLogging(); - - // Conjure up a RequestServices - services.AddTransient(); - - if (_configureServices != null) - { - _configureServices(services); - } - - return services; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/Program.cs b/src/Microsoft.AspNet.Hosting/Program.cs index 6c4a24ae1c..541eec0f0d 100644 --- a/src/Microsoft.AspNet.Hosting/Program.cs +++ b/src/Microsoft.AspNet.Hosting/Program.cs @@ -5,6 +5,7 @@ using System; using System.IO; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Hosting.Internal; using Microsoft.Framework.ConfigurationModel; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Logging; @@ -33,21 +34,10 @@ namespace Microsoft.AspNet.Hosting config.AddEnvironmentVariables(); config.AddCommandLine(args); - var engine = WebHost.CreateEngine(_serviceProvider, config); - var server = config.Get("server"); - if (server != null) - { - engine.UseServer(server); - } - var startup = config.Get("app"); - if (startup != null) - { - engine.UseStartup(startup); - } - - var serverShutdown = engine.Start(); - var loggerFactory = engine.ApplicationServices.GetRequiredService(); - var appShutdownService = engine.ApplicationServices.GetRequiredService(); + var host = new WebHostBuilder(_serviceProvider).Build(); + var serverShutdown = host.Start(); + var loggerFactory = host.ApplicationServices.GetRequiredService(); + var appShutdownService = host.ApplicationServices.GetRequiredService(); var shutdownHandle = new ManualResetEvent(false); appShutdownService.ShutdownRequested.Register(() => diff --git a/src/Microsoft.AspNet.Hosting/Startup/IStartupLoader.cs b/src/Microsoft.AspNet.Hosting/Startup/IStartupLoader.cs index cab29b61ce..6ba16f4e08 100644 --- a/src/Microsoft.AspNet.Hosting/Startup/IStartupLoader.cs +++ b/src/Microsoft.AspNet.Hosting/Startup/IStartupLoader.cs @@ -8,9 +8,8 @@ namespace Microsoft.AspNet.Hosting.Startup { public interface IStartupLoader { - StartupMethods Load( - string startupAssemblyName, - string environmentName, - IList diagnosticMessages); + Type FindStartupType(string startupAssemblyName, IList diagnosticMessages); + + StartupMethods LoadMethods(Type startupType, IList diagnosticMessages); } } diff --git a/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs b/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs index 6ebc09f04e..2b95b72ed7 100644 --- a/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs +++ b/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs @@ -13,17 +13,19 @@ namespace Microsoft.AspNet.Hosting.Startup public class StartupLoader : IStartupLoader { private readonly IServiceProvider _services; + private readonly IHostingEnvironment _hostingEnv; - public StartupLoader(IServiceProvider services) + public StartupLoader(IServiceProvider services, IHostingEnvironment hostingEnv) { _services = services; + _hostingEnv = hostingEnv; } - public StartupMethods Load( + public StartupMethods LoadMethods( Type startupType, - string environmentName, IList diagnosticMessages) { + var environmentName = _hostingEnv.EnvironmentName; var configureMethod = FindConfigureDelegate(startupType, environmentName); var servicesMethod = FindConfigureServicesDelegate(startupType, environmentName); @@ -36,11 +38,9 @@ namespace Microsoft.AspNet.Hosting.Startup return new StartupMethods(configureMethod.Build(instance), servicesMethod?.Build(instance)); } - public StartupMethods Load( - string startupAssemblyName, - string environmentName, - IList diagnosticMessages) + public Type FindStartupType(string startupAssemblyName, IList diagnosticMessages) { + var environmentName = _hostingEnv.EnvironmentName; if (string.IsNullOrEmpty(startupAssemblyName)) { throw new ArgumentException("Value cannot be null or empty.", nameof(startupAssemblyName)); @@ -85,7 +85,7 @@ namespace Microsoft.AspNet.Hosting.Startup startupAssemblyName)); } - return Load(type, environmentName, diagnosticMessages); + return type; } private static ConfigureBuilder FindConfigureDelegate(Type startupType, string environmentName) diff --git a/src/Microsoft.AspNet.Hosting/WebHost.cs b/src/Microsoft.AspNet.Hosting/WebHost.cs deleted file mode 100644 index c1d331e0c4..0000000000 --- a/src/Microsoft.AspNet.Hosting/WebHost.cs +++ /dev/null @@ -1,63 +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.Hosting.Internal; -using Microsoft.Framework.ConfigurationModel; -using Microsoft.Framework.DependencyInjection; -using Microsoft.Framework.Runtime.Infrastructure; - -namespace Microsoft.AspNet.Hosting -{ - public static class WebHost - { - public static IHostingEngine CreateEngine() - { - return CreateEngine(new Configuration()); - } - - public static IHostingEngine CreateEngine(Action configureServices) - { - return CreateEngine(new Configuration(), configureServices); - } - - public static IHostingEngine CreateEngine(IConfiguration config) - { - return CreateEngine(config, configureServices: null); - } - - public static IHostingEngine CreateEngine(IConfiguration config, Action configureServices) - { - return CreateEngine(fallbackServices: null, config: config, configureServices: configureServices); - } - - public static IHostingEngine CreateEngine(IServiceProvider fallbackServices, IConfiguration config) - { - return CreateEngine(fallbackServices, config, configureServices: null); - } - - public static IHostingEngine CreateEngine(IServiceProvider fallbackServices, IConfiguration config, Action configureServices) - { - return CreateFactory(fallbackServices, configureServices).Create(config); - } - - public static IHostingFactory CreateFactory() - { - return CreateFactory(fallbackServices: null, configureServices: null); - } - - public static IHostingFactory CreateFactory(Action configureServices) - { - return CreateFactory(fallbackServices: null, configureServices: configureServices); - } - - public static IHostingFactory CreateFactory(IServiceProvider fallbackServices, Action configureServices) - { - fallbackServices = fallbackServices ?? CallContextServiceLocator.Locator.ServiceProvider; - return new RootHostingServiceCollectionInitializer(fallbackServices, configureServices) - .Build() - .BuildServiceProvider() - .GetRequiredService(); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/WebHostBuilder.cs b/src/Microsoft.AspNet.Hosting/WebHostBuilder.cs new file mode 100644 index 0000000000..09e70f2650 --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/WebHostBuilder.cs @@ -0,0 +1,189 @@ +// 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.Builder; +using Microsoft.AspNet.Hosting.Internal; +using Microsoft.AspNet.Hosting.Server; +using Microsoft.AspNet.Hosting.Startup; +using Microsoft.Framework.ConfigurationModel; +using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.Internal; +using Microsoft.Framework.Logging; +using Microsoft.Framework.Runtime; + +namespace Microsoft.AspNet.Hosting +{ + public class WebHostBuilder + { + public const string OldEnvironmentKey = "ASPNET_ENV"; + public const string EnvironmentKey = "Hosting:Environment"; + + public const string OldApplicationKey = "app"; + public const string ApplicationKey = "Hosting:Application"; + + public const string OldServerKey = "server"; + public const string ServerKey = "Hosting:Server"; + + private readonly IServiceProvider _services; + private readonly IHostingEnvironment _hostingEnvironment; + private readonly ILoggerFactory _loggerFactory; + private readonly IConfiguration _config; + + private Action _configureServices; + + // Only one of these should be set + private StartupMethods _startup; + private Type _startupType; + private string _startupAssemblyName; + + // Only one of these should be set + private string _serverFactoryLocation; + private IServerFactory _serverFactory; + + public WebHostBuilder([NotNull] IServiceProvider services) : this(services, config: new Configuration()) { } + + public WebHostBuilder([NotNull] IServiceProvider services, [NotNull] IConfiguration config) + { + _hostingEnvironment = new HostingEnvironment(); + _loggerFactory = new LoggerFactory(); + _services = services; + _config = config; + } + + private IServiceCollection BuildHostingServices() + { + var services = new ServiceCollection(); + + // Import from manifest + var manifest = _services.GetService(); + if (manifest != null) + { + foreach (var service in manifest.Services) + { + services.AddTransient(service, sp => _services.GetService(service)); + } + } + + services.AddInstance(_hostingEnvironment); + services.AddInstance(_loggerFactory); + + services.AddTransient(); + + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddSingleton(); + services.AddLogging(); + + // Conjure up a RequestServices + services.AddTransient(); + + if (_configureServices != null) + { + _configureServices(services); + } + + return services; + } + + public IHostingEngine Build() + { + var hostingServices = BuildHostingServices(); + + var hostingContainer = hostingServices.BuildServiceProvider(); + + var appEnvironment = hostingContainer.GetRequiredService(); + var startupLoader = hostingContainer.GetRequiredService(); + + _hostingEnvironment.Initialize(appEnvironment.ApplicationBasePath, _config?[EnvironmentKey] ?? _config?[OldEnvironmentKey]); + + var engine = new HostingEngine(hostingServices, startupLoader, _config); + + // Only one of these should be set, but they are used in priority + engine.ServerFactory = _serverFactory; + engine.ServerFactoryLocation = _config.Get(ServerKey) ?? _config.Get(OldServerKey) ?? _serverFactoryLocation; + + // Only one of these should be set, but they are used in priority + engine.Startup = _startup; + engine.StartupType = _startupType; + engine.StartupAssemblyName = _config.Get(ApplicationKey) ?? _config.Get(OldApplicationKey) ?? appEnvironment.ApplicationName; + + return engine; + } + + public WebHostBuilder UseServices(Action configureServices) + { + _configureServices = configureServices; + return this; + } + + public WebHostBuilder UseEnvironment([NotNull] string environment) + { + _hostingEnvironment.EnvironmentName = environment; + return this; + } + + public WebHostBuilder UseServer([NotNull] string assemblyName) + { + _serverFactoryLocation = assemblyName; + return this; + } + + public WebHostBuilder UseServer(IServerFactory factory) + { + _serverFactory = factory; + return this; + } + + public WebHostBuilder UseStartup([NotNull] string startupAssemblyName) + { + if (startupAssemblyName == null) + { + throw new ArgumentNullException(nameof(startupAssemblyName)); + } + _startupAssemblyName = startupAssemblyName; + return this; + } + + public WebHostBuilder UseStartup([NotNull] Type startupType) + { + if (startupType == null) + { + throw new ArgumentNullException(nameof(startupType)); + } + _startupType = startupType; + return this; + } + + public WebHostBuilder UseStartup() where TStartup : class + { + return UseStartup(typeof(TStartup)); + } + + public WebHostBuilder UseStartup([NotNull] Action configureApp) + { + return UseStartup(configureApp, configureServices: null); + } + + public WebHostBuilder UseStartup([NotNull] Action configureApp, ConfigureServicesDelegate configureServices) + { + _startup = new StartupMethods(configureApp, configureServices); + return this; + } + + public WebHostBuilder UseStartup([NotNull] Action configureApp, Action configureServices) + { + _startup = new StartupMethods(configureApp, + services => { + if (configureServices != null) + { + configureServices(services); + } + return services.BuildServiceProvider(); + }); + return this; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/project.json b/src/Microsoft.AspNet.Hosting/project.json index 68028eeede..25eda4017f 100644 --- a/src/Microsoft.AspNet.Hosting/project.json +++ b/src/Microsoft.AspNet.Hosting/project.json @@ -12,6 +12,7 @@ "Microsoft.Framework.DependencyInjection": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", "Microsoft.Framework.Runtime.Interfaces": "1.0.0-*", + "Microsoft.Framework.NotNullAttribute.Internal": { "type": "build", "version": "1.0.0-*" }, "Newtonsoft.Json": "6.0.6" }, "frameworks": { diff --git a/src/Microsoft.AspNet.TestHost/TestServer.cs b/src/Microsoft.AspNet.TestHost/TestServer.cs index f290092609..d5bf3e52a6 100644 --- a/src/Microsoft.AspNet.TestHost/TestServer.cs +++ b/src/Microsoft.AspNet.TestHost/TestServer.cs @@ -12,6 +12,7 @@ using Microsoft.AspNet.Hosting.Startup; using Microsoft.AspNet.Http; using Microsoft.Framework.ConfigurationModel; using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.Runtime.Infrastructure; namespace Microsoft.AspNet.TestHost { @@ -24,101 +25,66 @@ namespace Microsoft.AspNet.TestHost private IDisposable _appInstance; private bool _disposed = false; - public TestServer(IHostingEngine engine) + public TestServer(WebHostBuilder builder) { - _appInstance = engine.UseServer(this).Start(); + _appInstance = builder.UseServer(this).Build().Start(); } public Uri BaseAddress { get; set; } = new Uri("http://localhost/"); public static TestServer Create() { - return Create(fallbackServices: null, config: null, configureApp: null, configureServices: null); + return Create(services: null, config: null, configureApp: null, configureServices: null); } public static TestServer Create(Action configureApp) { - return Create(fallbackServices: null, config: null, configureApp: configureApp, configureServices: null); + return Create(services: null, config: null, configureApp: configureApp, configureServices: null); } public static TestServer Create(Action configureApp, Action configureServices) { - return Create(fallbackServices: null, config: null, configureApp: configureApp, configureServices: configureServices); + return Create(services: null, config: null, configureApp: configureApp, configureServices: configureServices); } - public static TestServer Create(IServiceProvider fallbackServices, Action configureApp, ConfigureServicesDelegate configureServices) + public static TestServer Create(IServiceProvider services, Action configureApp, ConfigureServicesDelegate configureServices) { - return CreateBuilder(fallbackServices, config: null, configureApp: configureApp, configureServices: configureServices).Build(); + return new TestServer(CreateBuilder(services, config: null, configureApp: configureApp, configureServices: configureServices)); } - public static TestServer Create(IServiceProvider fallbackServices, IConfiguration config, Action configureApp, Action configureServices) + public static TestServer Create(IServiceProvider services, IConfiguration config, Action configureApp, Action configureServices) { - return CreateBuilder(fallbackServices, config, configureApp, configureServices).Build(); + return new TestServer(CreateBuilder(services, config, configureApp, configureServices)); } - public static TestServer Create() where TStartup : class + public static WebHostBuilder CreateBuilder(IServiceProvider services, IConfiguration config, Action configureApp, Action configureServices) { - return Create(fallbackServices: null, config: null, configureApp: null, configureServices: null); - } - - public static TestServer Create(Action configureApp) where TStartup : class - { - return Create(fallbackServices: null, config: null, configureApp: configureApp, configureServices: null); - } - - public static TestServer Create(Action configureApp, Action configureServices) where TStartup : class - { - return Create(fallbackServices: null, config: null, configureApp: configureApp, configureServices: configureServices); - } - - public static TestServer Create(IServiceProvider fallbackServices, IConfiguration config, Action configureApp, Action configureServices) where TStartup : class - { - var builder = CreateBuilder(fallbackServices, config, configureApp, configureServices); - builder.StartupType = typeof(TStartup); - return builder.Build(); - } - - public static TestServerBuilder CreateBuilder() where TStartup : class - { - var builder = CreateBuilder(fallbackServices: null, config: null, configureApp: null, configureServices: null); - builder.StartupType = typeof(TStartup); - return builder; - } - - public static TestServerBuilder CreateBuilder(IServiceProvider fallbackServices, IConfiguration config, Action configureApp, Action configureServices) where TStartup : class - { - var builder = CreateBuilder(fallbackServices, config, configureApp, configureServices); - builder.StartupType = typeof(TStartup); - return builder; - } - - public static TestServerBuilder CreateBuilder(IServiceProvider fallbackServices, IConfiguration config, Action configureApp, Action configureServices) - { - return CreateBuilder(fallbackServices, config, configureApp, - services => + return CreateBuilder(services, config, configureApp, + s => { if (configureServices != null) { - configureServices(services); + configureServices(s); } - return services.BuildServiceProvider(); + return s.BuildServiceProvider(); }); } - public static TestServerBuilder CreateBuilder(IServiceProvider fallbackServices, IConfiguration config) + public static WebHostBuilder CreateBuilder(IServiceProvider services, IConfiguration config, Action configureApp, ConfigureServicesDelegate configureServices) { - return new TestServerBuilder - { - FallbackServices = fallbackServices, - Config = config - }; + return CreateBuilder(services, config).UseStartup(configureApp, configureServices); } - public static TestServerBuilder CreateBuilder(IServiceProvider fallbackServices, IConfiguration config, Action configureApp, ConfigureServicesDelegate configureServices) + public static WebHostBuilder CreateBuilder(IServiceProvider services, IConfiguration config) { - var builder = CreateBuilder(fallbackServices, config); - builder.Startup = new StartupMethods(configureApp, configureServices); - return builder; + return new WebHostBuilder( + services ?? CallContextServiceLocator.Locator.ServiceProvider, + config ?? new Configuration()); + } + + public static WebHostBuilder CreateBuilder() + { + return CreateBuilder(services: null, config: null); } public HttpMessageHandler CreateHandler() diff --git a/src/Microsoft.AspNet.TestHost/TestServerBuilder.cs b/src/Microsoft.AspNet.TestHost/TestServerBuilder.cs deleted file mode 100644 index 74425f89f5..0000000000 --- a/src/Microsoft.AspNet.TestHost/TestServerBuilder.cs +++ /dev/null @@ -1,126 +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.Runtime.Versioning; -using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.Hosting.Startup; -using Microsoft.Framework.ConfigurationModel; -using Microsoft.Framework.DependencyInjection; -using Microsoft.Framework.Runtime; -using Microsoft.Framework.Runtime.Infrastructure; - -namespace Microsoft.AspNet.TestHost -{ - public class TestServerBuilder - { - public IServiceProvider FallbackServices { get; set; } - public string Environment { get; set; } - public string ApplicationName { get; set; } - public string ApplicationBasePath { get; set; } - - public Type StartupType { get; set; } - public string StartupAssemblyName { get; set; } - public IConfiguration Config { get; set; } - - public IServiceCollection AdditionalServices { get; } = new ServiceCollection(); - - public StartupMethods Startup { get; set; } - - public TestServer Build() - { - var fallbackServices = FallbackServices ?? CallContextServiceLocator.Locator.ServiceProvider; - var config = Config ?? new Configuration(); - if (Environment != null) - { - config[HostingFactory.EnvironmentKey] = Environment; - } - if (ApplicationName != null || ApplicationBasePath != null) - { - var appEnv = new TestApplicationEnvironment(fallbackServices.GetRequiredService()); - appEnv.ApplicationBasePath = ApplicationBasePath; - appEnv.ApplicationName = ApplicationName; - AdditionalServices.AddInstance(appEnv); - } - - var engine = WebHost.CreateEngine(fallbackServices, - config, - services => services.Add(AdditionalServices)); - if (StartupType != null) - { - Startup = new StartupLoader(fallbackServices).Load(StartupType, Environment, new List()); - } - if (Startup != null) - { - engine.UseStartup(Startup.ConfigureDelegate, Startup.ConfigureServicesDelegate); - } - else if (StartupAssemblyName != null) - { - engine.UseStartup(StartupAssemblyName); - } - - return new TestServer(engine); - } - - private class TestApplicationEnvironment : IApplicationEnvironment - { - private readonly IApplicationEnvironment _appEnv; - private string _appName; - private string _appBasePath; - - public TestApplicationEnvironment(IApplicationEnvironment appEnv) - { - _appEnv = appEnv; - } - - public string ApplicationBasePath - { - get - { - return _appBasePath ?? _appEnv.ApplicationBasePath; - } - set - { - _appBasePath = value; - } - } - - public string ApplicationName - { - get - { - return _appName ?? _appEnv.ApplicationName; - } - set - { - _appName = value; - } - } - - public string Configuration - { - get - { - return _appEnv.Configuration; - } - } - - public FrameworkName RuntimeFramework - { - get - { - return _appEnv.RuntimeFramework; - } - } - - public string Version - { - get - { - throw new NotImplementedException(); - } - } - } - } -} \ 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 07d946e490..dca50c4e0f 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Hosting.Builder; +using Microsoft.AspNet.Hosting.Internal; using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Hosting.Startup; using Microsoft.AspNet.Http; @@ -16,6 +17,7 @@ using Microsoft.Framework.ConfigurationModel; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Logging; using Microsoft.Framework.OptionsModel; +using Microsoft.Framework.Runtime.Infrastructure; using Moq; using Xunit; @@ -24,19 +26,58 @@ namespace Microsoft.AspNet.Hosting public class HostingEngineTests : IServerFactory { private readonly IList _startInstances = new List(); + private IFeatureCollection _featuresSupportedByThisHost = new FeatureCollection(); [Fact] public void HostingEngineThrowsWithNoServer() { - Assert.Throws(() => WebHost.CreateEngine().Start()); + var ex = Assert.Throws(() => CreateBuilder().Build().Start()); + Assert.True(ex.Message.Contains("UseServer()")); + } + + [Fact] + public void UseStartupThrowsWithNull() + { + Assert.Throws(() => CreateBuilder().UseStartup((string)null)); + } + + [Fact] + public void CanStartWithOldServerConfig() + { + var vals = new Dictionary + { + { "server", "Microsoft.AspNet.Hosting.Tests" } + }; + + var config = new Configuration() + .Add(new MemoryConfigurationSource(vals)); + var host = CreateBuilder(config).Build(); + host.Start(); + Assert.NotNull(host.ApplicationServices.GetRequiredService()); + } + + [Fact] + public void CanStartWithServerConfig() + { + var vals = new Dictionary + { + { "Hosting:Server", "Microsoft.AspNet.Hosting.Tests" } + }; + + var config = new Configuration() + .Add(new MemoryConfigurationSource(vals)); + var host = CreateBuilder(config).Build(); + host.Start(); + Assert.NotNull(host.ApplicationServices.GetRequiredService()); } [Fact] public void HostingEngineCanBeStarted() { - var engine = WebHost.CreateEngine() + var engine = CreateBuilder() .UseServer(this) .UseStartup("Microsoft.AspNet.Hosting.Tests") + .Build() .Start(); Assert.NotNull(engine); @@ -51,10 +92,11 @@ namespace Microsoft.AspNet.Hosting [Fact] public void HostingEngineInjectsHostingEnvironment() { - var engine = WebHost.CreateEngine() + var engine = CreateBuilder() .UseServer(this) .UseStartup("Microsoft.AspNet.Hosting.Tests") - .UseEnvironment("WithHostingEnvironment"); + .UseEnvironment("WithHostingEnvironment") + .Build(); using (var server = engine.Start()) { @@ -63,20 +105,13 @@ namespace Microsoft.AspNet.Hosting } } - [Fact] - public void CanReplaceHostingFactory() - { - var factory = WebHost.CreateFactory(services => services.AddTransient()); - - Assert.NotNull(factory as TestEngineFactory); - } - [Fact] public void CanReplaceStartupLoader() { - var engine = WebHost.CreateEngine(services => services.AddTransient()) + var engine = CreateBuilder().UseServices(services => services.AddTransient()) .UseServer(this) - .UseStartup("Microsoft.AspNet.Hosting.Tests"); + .UseStartup("Microsoft.AspNet.Hosting.Tests") + .Build(); Assert.Throws(() => engine.Start()); } @@ -84,20 +119,20 @@ namespace Microsoft.AspNet.Hosting [Fact] public void CanCreateApplicationServicesWithAddedServices() { - var engineStart = WebHost.CreateEngine(services => services.AddOptions()); - Assert.NotNull(engineStart.ApplicationServices.GetRequiredService>()); + var host = CreateBuilder().UseServices(services => services.AddOptions()).Build(); + Assert.NotNull(host.ApplicationServices.GetRequiredService>()); } [Fact] public void EnvDefaultsToDevelopmentIfNoConfig() { - var engine = WebHost.CreateEngine(new Configuration()); + var engine = CreateBuilder().Build(); var env = engine.ApplicationServices.GetRequiredService(); Assert.Equal("Development", env.EnvironmentName); } [Fact] - public void EnvDefaultsToDevelopmentConfigValueIfSpecified() + public void EnvDefaultsToDevelopmentConfigValueIfSpecifiedWithOldKey() { var vals = new Dictionary { @@ -107,7 +142,23 @@ namespace Microsoft.AspNet.Hosting var config = new Configuration() .Add(new MemoryConfigurationSource(vals)); - var engine = WebHost.CreateEngine(config); + var engine = CreateBuilder(config).Build(); + var env = engine.ApplicationServices.GetRequiredService(); + Assert.Equal("Staging", env.EnvironmentName); + } + + [Fact] + public void EnvDefaultsToDevelopmentConfigValueIfSpecified() + { + var vals = new Dictionary + { + { "Hosting:Environment", "Staging" } + }; + + var config = new Configuration() + .Add(new MemoryConfigurationSource(vals)); + + var engine = CreateBuilder(config).Build(); var env = engine.ApplicationServices.GetRequiredService(); Assert.Equal("Staging", env.EnvironmentName); } @@ -115,7 +166,7 @@ namespace Microsoft.AspNet.Hosting [Fact] public void WebRootCanBeResolvedFromTheProjectJson() { - var engine = WebHost.CreateEngine().UseServer(this); + var engine = CreateBuilder().UseServer(this).Build(); var env = engine.ApplicationServices.GetRequiredService(); Assert.Equal(Path.GetFullPath("testroot"), env.WebRootPath); Assert.True(env.WebRootFileProvider.GetFileInfo("TextFile.txt").Exists); @@ -124,8 +175,7 @@ namespace Microsoft.AspNet.Hosting [Fact] public void IsEnvironment_Extension_Is_Case_Insensitive() { - var engine = WebHost.CreateEngine().UseServer(this); - + var engine = CreateBuilder().UseServer(this).Build(); using (engine.Start()) { var env = engine.ApplicationServices.GetRequiredService(); @@ -164,8 +214,7 @@ namespace Microsoft.AspNet.Hosting httpContext = innerHttpContext; return Task.FromResult(0); }); - var featuresSupportedByHost = new FeatureCollection(); - var hostingEngine = CreateHostingEngine(featuresSupportedByHost, requestDelegate); + var hostingEngine = CreateHostingEngine(requestDelegate); // Act var disposable = hostingEngine.Start(); @@ -192,7 +241,9 @@ namespace Microsoft.AspNet.Hosting featuresSupportedByHost .Setup(fc => fc.Add(new KeyValuePair(It.IsAny(), It.IsAny()))) .Throws(new NotImplementedException()); - var hostingEngine = CreateHostingEngine(featuresSupportedByHost.Object, requestDelegate); + _featuresSupportedByThisHost = featuresSupportedByHost.Object; + + var hostingEngine = CreateHostingEngine(requestDelegate); // Act var disposable = hostingEngine.Start(); @@ -212,10 +263,9 @@ namespace Microsoft.AspNet.Hosting httpContext = innerHttpContext; return Task.FromResult(0); }); - var featuresSupportedByHost = new FeatureCollection(); var requestIdentifierFeature = new Mock().Object; - featuresSupportedByHost.Add(typeof(IRequestIdentifierFeature), requestIdentifierFeature); - var hostingEngine = CreateHostingEngine(featuresSupportedByHost, requestDelegate); + _featuresSupportedByThisHost.Add(typeof(IRequestIdentifierFeature), requestIdentifierFeature); + var hostingEngine = CreateHostingEngine(requestDelegate); // Act var disposable = hostingEngine.Start(); @@ -225,9 +275,7 @@ namespace Microsoft.AspNet.Hosting Assert.Same(requestIdentifierFeature, httpContext.GetFeature()); } - private IHostingEngine CreateHostingEngine( - IFeatureCollection featuresSupportedByHost, - RequestDelegate requestDelegate) + private IHostingEngine CreateHostingEngine(RequestDelegate requestDelegate) { var applicationBuilder = new Mock(); applicationBuilder.Setup(appBuilder => appBuilder.Build()).Returns(requestDelegate); @@ -236,36 +284,25 @@ namespace Microsoft.AspNet.Hosting .Setup(abf => abf.CreateBuilder(It.IsAny())) .Returns(applicationBuilder.Object); - var serviceCollection = new ServiceCollection(); - serviceCollection.Add( - new ServiceDescriptor(typeof(IApplicationBuilderFactory), applicationBuilderFactory.Object)); - serviceCollection.Add( - new ServiceDescriptor(typeof(ILogger), new Mock>().Object)); - serviceCollection.Add( - new ServiceDescriptor(typeof(IHttpContextFactory), new HttpContextFactory())); - serviceCollection.Add( - new ServiceDescriptor(typeof(IHttpContextAccessor), new Mock().Object)); - - var startupLoader = new Mock(); - var startupMethods = new StartupMethods( - (appBuilder) => { }, - (configureServices) => configureServices.BuildServiceProvider()); - startupLoader.Setup(sl => sl.Load(It.IsAny(), It.IsAny(), It.IsAny>())) - .Returns(startupMethods); - - var hostingEngine = new HostingEngine( - serviceCollection, - startupLoader.Object, - new Mock().Object, - new Mock().Object, - "TestAppName"); - - return hostingEngine.UseServer(new TestServerFactory(featuresSupportedByHost)); + var host = CreateBuilder() + .UseServer(this) + .UseServices(s => + { + s.AddInstance(applicationBuilderFactory.Object); + s.AddInstance(new Mock>().Object); + s.AddSingleton(); + s.AddInstance(new Mock().Object); + s.AddInstance(new Mock().Object); + }) + .UseStartup( + appBuilder => { }, + configureServices => configureServices.BuildServiceProvider()); + return host.Build(); } private void RunMapPath(string virtualPath, string expectedSuffix) { - var engine = WebHost.CreateEngine().UseServer(this); + var engine = CreateBuilder().UseServer(this).Build(); using (engine.Start()) { @@ -276,6 +313,11 @@ namespace Microsoft.AspNet.Hosting } } + private WebHostBuilder CreateBuilder(IConfiguration config = null) + { + return new WebHostBuilder(CallContextServiceLocator.Locator.ServiceProvider, config ?? new Configuration()); + } + public IServerInformation Initialize(IConfiguration configuration) { return null; @@ -285,6 +327,7 @@ namespace Microsoft.AspNet.Hosting { var startInstance = new StartInstance(application); _startInstances.Add(startInstance); + application(_featuresSupportedByThisHost); return startInstance; } @@ -307,39 +350,15 @@ namespace Microsoft.AspNet.Hosting private class TestLoader : IStartupLoader { - public StartupMethods Load(string startupAssemblyName, string environmentName, IList diagnosticMessages) + public Type FindStartupType(string startupAssemblyName, IList diagnosticMessages) { throw new NotImplementedException(); } - } - private class TestEngineFactory : IHostingFactory - { - public IHostingEngine Create(IConfiguration config) + public StartupMethods LoadMethods(Type startupType, IList diagnosticMessages) { throw new NotImplementedException(); } } - - private class TestServerFactory : IServerFactory - { - private readonly IFeatureCollection _featuresSupportedByThisHost; - - public TestServerFactory(IFeatureCollection featuresSupportedByThisHost) - { - _featuresSupportedByThisHost = featuresSupportedByThisHost; - } - - public IServerInformation Initialize(IConfiguration configuration) - { - return null; - } - - public IDisposable Start(IServerInformation serverInformation, Func application) - { - application(_featuresSupportedByThisHost).Wait(); - return null; - } - } } } diff --git a/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs b/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs index cce2931e22..ca803c6831 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Reflection; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting.Fakes; @@ -26,7 +25,10 @@ namespace Microsoft.AspNet.Hosting.Tests var services = serviceCollection.BuildServiceProvider(); var diagnosticMessages = new List(); - var startup = new StartupLoader(services).Load("Microsoft.AspNet.Hosting.Tests", "WithServices", diagnosticMessages); + var hostingEnv = new HostingEnvironment { EnvironmentName = "WithServices" }; + var loader = new StartupLoader(services, hostingEnv); + var type = loader.FindStartupType("Microsoft.AspNet.Hosting.Tests", diagnosticMessages); + var startup = loader.LoadMethods(type, diagnosticMessages); var app = new ApplicationBuilder(services); app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection); @@ -47,9 +49,12 @@ namespace Microsoft.AspNet.Hosting.Tests public void StartupClassAddsConfigureServicesToApplicationServices(string environment) { var services = new ServiceCollection().BuildServiceProvider(); - var diagnosticMesssages = new List(); - var startup = new StartupLoader(services).Load("Microsoft.AspNet.Hosting.Tests", environment ?? "", diagnosticMesssages); + var diagnosticMessages = new List(); + var hostingEnv = new HostingEnvironment { EnvironmentName = environment }; + var loader = new StartupLoader(services, hostingEnv); + var type = loader.FindStartupType("Microsoft.AspNet.Hosting.Tests", diagnosticMessages); + var startup = loader.LoadMethods(type, diagnosticMessages); var app = new ApplicationBuilder(services); app.ApplicationServices = startup.ConfigureServicesDelegate(new ServiceCollection()); @@ -67,9 +72,13 @@ namespace Microsoft.AspNet.Hosting.Tests var serviceCollection = new ServiceCollection(); serviceCollection.AddInstance(this); var services = serviceCollection.BuildServiceProvider(); - var diagnosticMessages = new List(); - var ex = Assert.Throws(() => new StartupLoader(services).Load("Microsoft.AspNet.Hosting.Tests", "Boom", diagnosticMessages)); + var diagnosticMessages = new List(); + var hostingEnv = new HostingEnvironment { EnvironmentName = "Boom" }; + var loader = new StartupLoader(services, hostingEnv); + var type = loader.FindStartupType("Microsoft.AspNet.Hosting.Tests", diagnosticMessages); + + var ex = Assert.Throws(() => loader.LoadMethods(type, diagnosticMessages)); Assert.Equal("A method named 'ConfigureBoom' or 'Configure' in the type 'Microsoft.AspNet.Hosting.Fakes.StartupBoom' could not be found.", ex.Message); } @@ -80,7 +89,10 @@ namespace Microsoft.AspNet.Hosting.Tests var services = serviceCollection.BuildServiceProvider(); var diagnosticMessages = new List(); - var startup = new StartupLoader(services).Load("Microsoft.AspNet.Hosting.Tests", "WithNullConfigureServices", diagnosticMessages); + var hostingEnv = new HostingEnvironment { EnvironmentName = "WithNullConfigureServices" }; + var loader = new StartupLoader(services, hostingEnv); + var type = loader.FindStartupType("Microsoft.AspNet.Hosting.Tests", diagnosticMessages); + var startup = loader.LoadMethods(type, diagnosticMessages); var app = new ApplicationBuilder(services); app.ApplicationServices = startup.ConfigureServicesDelegate(new ServiceCollection()); @@ -96,7 +108,10 @@ namespace Microsoft.AspNet.Hosting.Tests var services = serviceCollection.BuildServiceProvider(); var diagnosticMessages = new List(); - var startup = new StartupLoader(services).Load("Microsoft.AspNet.Hosting.Tests", "WithConfigureServices", diagnosticMessages); + var hostingEnv = new HostingEnvironment { EnvironmentName = "WithConfigureServices" }; + var loader = new StartupLoader(services, hostingEnv); + var type = loader.FindStartupType("Microsoft.AspNet.Hosting.Tests", diagnosticMessages); + var startup = loader.LoadMethods(type, diagnosticMessages); var app = new ApplicationBuilder(services); app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection); @@ -113,7 +128,9 @@ namespace Microsoft.AspNet.Hosting.Tests var services = serviceCollection.BuildServiceProvider(); var diagnosticMessages = new List(); - var startup = new StartupLoader(services).Load(typeof(TestStartup), "", diagnosticMessages); + var hostingEnv = new HostingEnvironment(); + var loader = new StartupLoader(services, hostingEnv); + var startup = loader.LoadMethods(typeof(TestStartup), diagnosticMessages); var app = new ApplicationBuilder(services); app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection); @@ -130,7 +147,9 @@ namespace Microsoft.AspNet.Hosting.Tests var services = serviceCollection.BuildServiceProvider(); var diagnosticMessages = new List(); - var startup = new StartupLoader(services).Load(typeof(TestStartup), "No", diagnosticMessages); + var hostingEnv = new HostingEnvironment { EnvironmentName = "No" }; + var loader = new StartupLoader(services, hostingEnv); + var startup = loader.LoadMethods(typeof(TestStartup), diagnosticMessages); var app = new ApplicationBuilder(services); app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection); diff --git a/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs b/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs index 72f7277990..fcbd153e8a 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs +++ b/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs @@ -2,20 +2,16 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Diagnostics; using System.IO; using System.Net; using System.Net.Http; -using System.Runtime.Versioning; using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.Hosting.Startup; using Microsoft.AspNet.Http; using Microsoft.Framework.ConfigurationModel; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Logging; -using Microsoft.Framework.Runtime; using Microsoft.Framework.Runtime.Infrastructure; using Xunit; @@ -56,54 +52,6 @@ namespace Microsoft.AspNet.TestHost Assert.Equal("RequestServices:True", result); } - [Fact] - public async Task CanChangeApplicationName() - { - var fallbackServices = CallContextServiceLocator.Locator.ServiceProvider; - var appName = "gobblegobble"; - - var builder = TestServer.CreateBuilder(fallbackServices, new Configuration(), - app => - { - app.Run(context => - { - var appEnv = app.ApplicationServices.GetRequiredService(); - return context.Response.WriteAsync("AppName:" + appEnv.ApplicationName); - }); - }, - configureServices: null); - - builder.ApplicationName = appName; - var server = builder.Build(); - - string result = await server.CreateClient().GetStringAsync("/path"); - Assert.Equal("AppName:" + appName, result); - } - - [Fact] - public async Task CanChangeAppPath() - { - var fallbackServices = CallContextServiceLocator.Locator.ServiceProvider; - var appPath = "."; - - var builder = TestServer.CreateBuilder(fallbackServices, new Configuration(), - app => - { - app.Run(context => - { - var env = app.ApplicationServices.GetRequiredService(); - return context.Response.WriteAsync("AppPath:" + env.ApplicationBasePath); - }); - }, - configureServices: null); - - builder.ApplicationBasePath = appPath; - var server = builder.Build(); - - string result = await server.CreateClient().GetStringAsync("/path"); - Assert.Equal("AppPath:" + appPath, result); - } - [Fact] public async Task CanAccessLogger() { @@ -242,7 +190,7 @@ namespace Microsoft.AspNet.TestHost [Fact] public async Task CanCreateViaStartupType() { - TestServer server = TestServer.Create(); + TestServer server = new TestServer(TestServer.CreateBuilder().UseStartup()); HttpResponseMessage result = await server.CreateClient().GetAsync("/"); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal("FoundService:True", await result.Content.ReadAsStringAsync()); @@ -251,9 +199,9 @@ namespace Microsoft.AspNet.TestHost [Fact] public async Task CanCreateViaStartupTypeAndSpecifyEnv() { - var builder = TestServer.CreateBuilder(); - builder.Environment = "Foo"; - var server = builder.Build(); + TestServer server = new TestServer(TestServer.CreateBuilder() + .UseStartup() + .UseEnvironment("Foo")); HttpResponseMessage result = await server.CreateClient().GetAsync("/"); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal("FoundFoo:False", await result.Content.ReadAsStringAsync());