diff --git a/Hosting.sln b/Hosting.sln index 0c93390a49..a04fd5e533 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.22803.0 +VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E0497F39-AFFB-4819-A116-E39E361915AB}" EndProject @@ -26,6 +26,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Hosting.Se EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.Testing", "src\Microsoft.AspNet.Server.Testing\Microsoft.AspNet.Server.Testing.xproj", "{3DA89347-6731-4366-80C4-548F24E8607B}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{9C7520A0-F2EB-411C-8BB2-80B39C937217}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SampleStartups", "samples\SampleStartups\SampleStartups.xproj", "{485B6745-7648-400A-A969-F68FCF194E46}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -112,6 +116,18 @@ Global {3DA89347-6731-4366-80C4-548F24E8607B}.Release|Mixed Platforms.Build.0 = Release|Any CPU {3DA89347-6731-4366-80C4-548F24E8607B}.Release|x86.ActiveCfg = Release|Any CPU {3DA89347-6731-4366-80C4-548F24E8607B}.Release|x86.Build.0 = Release|Any CPU + {485B6745-7648-400A-A969-F68FCF194E46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {485B6745-7648-400A-A969-F68FCF194E46}.Debug|Any CPU.Build.0 = Debug|Any CPU + {485B6745-7648-400A-A969-F68FCF194E46}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {485B6745-7648-400A-A969-F68FCF194E46}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {485B6745-7648-400A-A969-F68FCF194E46}.Debug|x86.ActiveCfg = Debug|Any CPU + {485B6745-7648-400A-A969-F68FCF194E46}.Debug|x86.Build.0 = Debug|Any CPU + {485B6745-7648-400A-A969-F68FCF194E46}.Release|Any CPU.ActiveCfg = Release|Any CPU + {485B6745-7648-400A-A969-F68FCF194E46}.Release|Any CPU.Build.0 = Release|Any CPU + {485B6745-7648-400A-A969-F68FCF194E46}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {485B6745-7648-400A-A969-F68FCF194E46}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {485B6745-7648-400A-A969-F68FCF194E46}.Release|x86.ActiveCfg = Release|Any CPU + {485B6745-7648-400A-A969-F68FCF194E46}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -124,5 +140,6 @@ Global {BB780FBB-7842-4759-8DE7-96FA2E5571C1} = {E0497F39-AFFB-4819-A116-E39E361915AB} {FDBBA081-5248-4FC0-9E08-B46BEF3FA438} = {E0497F39-AFFB-4819-A116-E39E361915AB} {3DA89347-6731-4366-80C4-548F24E8607B} = {E0497F39-AFFB-4819-A116-E39E361915AB} + {485B6745-7648-400A-A969-F68FCF194E46} = {9C7520A0-F2EB-411C-8BB2-80B39C937217} EndGlobalSection EndGlobal diff --git a/samples/SampleStartups/SampleStartups.xproj b/samples/SampleStartups/SampleStartups.xproj new file mode 100644 index 0000000000..c22f75c6a2 --- /dev/null +++ b/samples/SampleStartups/SampleStartups.xproj @@ -0,0 +1,25 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 485b6745-7648-400a-a969-f68fcf194e46 + SampleStartups + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + + + + + + diff --git a/samples/SampleStartups/StartupBlockingOnStart.cs b/samples/SampleStartups/StartupBlockingOnStart.cs new file mode 100644 index 0000000000..39db2830c4 --- /dev/null +++ b/samples/SampleStartups/StartupBlockingOnStart.cs @@ -0,0 +1,44 @@ +using System; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; +using Microsoft.AspNet.Http; +using Microsoft.Extensions.DependencyInjection; + +// Note that this sample will not run. It is only here to illustrate usage patterns. + +namespace SampleStartups +{ + public class StartupBlockingOnStart + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app) + { + app.Run(async (context) => + { + await context.Response.WriteAsync("Hello World!"); + }); + } + + // Entry point for the application. + public static void Main(string[] args) + { + var config = WebApplicationConfiguration.GetDefault(args); + + var application = new WebApplicationBuilder() + .UseConfiguration(config) + .UseStartup() + .Build(); + + using (application.Start()) + { + Console.ReadLine(); + } + } + } +} diff --git a/samples/SampleStartups/StartupConfigureAddresses.cs b/samples/SampleStartups/StartupConfigureAddresses.cs new file mode 100644 index 0000000000..0fff30e2f8 --- /dev/null +++ b/samples/SampleStartups/StartupConfigureAddresses.cs @@ -0,0 +1,44 @@ +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; +using Microsoft.AspNet.Http; +using Microsoft.Extensions.DependencyInjection; + +// Note that this sample will not run. It is only here to illustrate usage patterns. + +namespace SampleStartups +{ + public class StartupConfigureAddresses + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app) + { + app.Run(async (context) => + { + await context.Response.WriteAsync("Hello World!"); + }); + } + + // Entry point for the application. + public static void Main(string[] args) + { + var config = WebApplicationConfiguration.GetDefault(args); + + var application = new WebApplicationBuilder() + .UseConfiguration(config) + .UseStartup() + .Build(); + + var addresses = application.GetAddresses(); + addresses.Add("http://localhost:5000"); + addresses.Add("http://localhost:5001"); + + application.Run(); + } + } +} diff --git a/samples/SampleStartups/StartupExternallyControlled.cs b/samples/SampleStartups/StartupExternallyControlled.cs new file mode 100644 index 0000000000..dc7ce9d8b4 --- /dev/null +++ b/samples/SampleStartups/StartupExternallyControlled.cs @@ -0,0 +1,56 @@ +using System; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; +using Microsoft.AspNet.Http; +using Microsoft.Extensions.DependencyInjection; + +// Note that this sample will not run. It is only here to illustrate usage patterns. + +namespace SampleStartups +{ + public class StartupExternallyControlled + { + private readonly IWebApplication _host; + private IDisposable _application; + + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app) + { + app.Run(async (context) => + { + await context.Response.WriteAsync("Hello World!"); + }); + } + + public StartupExternallyControlled() + { + _host = new WebApplicationBuilder().UseStartup().Build(); + + // Clear all configured addresses + _host.GetAddresses().Clear(); + } + + public void Start() + { + _application = _host.Start(); + } + + public void Stop() + { + _application.Dispose(); + } + + public void AddUrl(string url) + { + var addresses = _host.GetAddresses(); + + addresses.Add(url); + } + } +} diff --git a/samples/SampleStartups/StartupFullControl.cs b/samples/SampleStartups/StartupFullControl.cs new file mode 100644 index 0000000000..34a00a5a46 --- /dev/null +++ b/samples/SampleStartups/StartupFullControl.cs @@ -0,0 +1,68 @@ +using System; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +// Note that this sample will not run. It is only here to illustrate usage patterns. + +namespace SampleStartups +{ + public class StartupFullControl + { + public static void Main(string[] args) + { + var application = new WebApplicationBuilder() + .UseServerFactory("Microsoft.AspNet.Server.Kestrel") // Set the server manually + .UseEnvironment("Development") + .UseWebRoot("public") + .ConfigureLogging(loggerFactory => + { + loggerFactory.AddProvider(new MyHostLoggerProvider()); + }) + .ConfigureServices(services => + { + // Configure services that the application can see + services.AddSingleton(); + }) + .Configure(app => + { + // Write the application inline, this won't call any startup class in the assembly + + app.Use(next => context => + { + return next(context); + }); + }) + .Build(); + + application.Run(); + } + } + + public class MyHostLoggerProvider : ILoggerProvider + { + public ILogger CreateLogger(string categoryName) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + throw new NotImplementedException(); + } + } + + public interface IMyCustomService + { + void Go(); + } + + public class MyCustomService : IMyCustomService + { + public void Go() + { + throw new NotImplementedException(); + } + } +} diff --git a/samples/SampleStartups/StartupHelloWorld.cs b/samples/SampleStartups/StartupHelloWorld.cs new file mode 100644 index 0000000000..4ee08e2f16 --- /dev/null +++ b/samples/SampleStartups/StartupHelloWorld.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; +using Microsoft.AspNet.Http; +using Microsoft.Extensions.DependencyInjection; + +// Note that this sample will not run. It is only here to illustrate usage patterns. + +namespace SampleStartups +{ + public class StartupHelloWorld + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app) + { + app.Run(async (context) => + { + await context.Response.WriteAsync("Hello World!"); + }); + } + + // Entry point for the application. + public static void Main(string[] args) + { + var config = WebApplicationConfiguration.GetDefault(args); + + var application = new WebApplicationBuilder() + .UseConfiguration(config) + .UseStartup() + .Build(); + + application.Run(); + } + } +} diff --git a/samples/SampleStartups/project.json b/samples/SampleStartups/project.json new file mode 100644 index 0000000000..4fb88a1477 --- /dev/null +++ b/samples/SampleStartups/project.json @@ -0,0 +1,10 @@ +{ + "version": "1.0.0-*", + "dependencies": { + "Microsoft.AspNet.Hosting": "1.0.0-*" + }, + "frameworks": { + "dnx451": { }, + "dnxcore50": { } + } +} diff --git a/src/Microsoft.AspNet.Hosting/IWebApplication.cs b/src/Microsoft.AspNet.Hosting/IWebApplication.cs new file mode 100644 index 0000000000..0db082a45f --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/IWebApplication.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation. 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.Http.Features; + +namespace Microsoft.AspNet.Hosting +{ + /// + /// Represents a configured web application + /// + public interface IWebApplication + { + /// + /// The exposed by the configured server. + /// + IFeatureCollection ServerFeatures { get; } + + /// + /// The for the application. + /// + IServiceProvider Services { get; } + + /// + /// Starts listening on the configured addresses. + /// + /// + IDisposable Start(); + } +} diff --git a/src/Microsoft.AspNet.Hosting/Internal/Application.cs b/src/Microsoft.AspNet.Hosting/Internal/Application.cs deleted file mode 100644 index ecbb916a6e..0000000000 --- a/src/Microsoft.AspNet.Hosting/Internal/Application.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) .NET Foundation. 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.Http.Features; - -namespace Microsoft.AspNet.Hosting.Internal -{ - public class Application : IApplication - { - private readonly IDisposable _stop; - private readonly IServiceProvider _services; - private readonly IFeatureCollection _server; - - public Application(IServiceProvider services, IFeatureCollection server, IDisposable stop) - { - _services = services; - _server = server; - _stop = stop; - } - - public IFeatureCollection ServerFeatures - { - get { return _server; } - } - - public IServiceProvider Services - { - get { return _services; } - } - - public void Dispose() - { - _stop.Dispose(); - } - } -} diff --git a/src/Microsoft.AspNet.Hosting/ApplicationLifetime.cs b/src/Microsoft.AspNet.Hosting/Internal/ApplicationLifetime.cs similarity index 98% rename from src/Microsoft.AspNet.Hosting/ApplicationLifetime.cs rename to src/Microsoft.AspNet.Hosting/Internal/ApplicationLifetime.cs index 230b4fd4e3..8955cf8d1e 100644 --- a/src/Microsoft.AspNet.Hosting/ApplicationLifetime.cs +++ b/src/Microsoft.AspNet.Hosting/Internal/ApplicationLifetime.cs @@ -4,7 +4,7 @@ using System; using System.Threading; -namespace Microsoft.AspNet.Hosting +namespace Microsoft.AspNet.Hosting.Internal { /// /// Allows consumers to perform cleanup during a graceful shutdown. diff --git a/src/Microsoft.AspNet.Hosting/HostingEnvironment.cs b/src/Microsoft.AspNet.Hosting/Internal/HostingEnvironment.cs similarity index 93% rename from src/Microsoft.AspNet.Hosting/HostingEnvironment.cs rename to src/Microsoft.AspNet.Hosting/Internal/HostingEnvironment.cs index e7254247a2..0428ce490b 100644 --- a/src/Microsoft.AspNet.Hosting/HostingEnvironment.cs +++ b/src/Microsoft.AspNet.Hosting/Internal/HostingEnvironment.cs @@ -4,7 +4,7 @@ using Microsoft.AspNet.FileProviders; using Microsoft.Extensions.Configuration; -namespace Microsoft.AspNet.Hosting +namespace Microsoft.AspNet.Hosting.Internal { public class HostingEnvironment : IHostingEnvironment { diff --git a/src/Microsoft.AspNet.Hosting/HostingEnvironmentExtensions.cs b/src/Microsoft.AspNet.Hosting/Internal/HostingEnvironmentExtensions.cs similarity index 92% rename from src/Microsoft.AspNet.Hosting/HostingEnvironmentExtensions.cs rename to src/Microsoft.AspNet.Hosting/Internal/HostingEnvironmentExtensions.cs index 6b46ba7214..cf4e1303bc 100644 --- a/src/Microsoft.AspNet.Hosting/HostingEnvironmentExtensions.cs +++ b/src/Microsoft.AspNet.Hosting/Internal/HostingEnvironmentExtensions.cs @@ -7,11 +7,11 @@ using Microsoft.AspNet.FileProviders; using Microsoft.AspNet.Hosting.Internal; using Microsoft.Extensions.Configuration; -namespace Microsoft.AspNet.Hosting +namespace Microsoft.AspNet.Hosting.Internal { public static class HostingEnvironmentExtensions { - public static void Initialize(this IHostingEnvironment hostingEnvironment, string applicationBasePath, WebHostOptions options, IConfiguration configuration) + public static void Initialize(this IHostingEnvironment hostingEnvironment, string applicationBasePath, WebApplicationOptions options, IConfiguration configuration) { if (options == null) { diff --git a/src/Microsoft.AspNet.Hosting/Internal/IApplication.cs b/src/Microsoft.AspNet.Hosting/Internal/IApplication.cs deleted file mode 100644 index 99f807e10c..0000000000 --- a/src/Microsoft.AspNet.Hosting/Internal/IApplication.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) .NET Foundation. 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.Http.Features; - -namespace Microsoft.AspNet.Hosting.Internal -{ - public interface IApplication : IDisposable - { - IFeatureCollection ServerFeatures { get; } - - IServiceProvider Services { get; } - } -} diff --git a/src/Microsoft.AspNet.Hosting/Internal/IHostingEngine.cs b/src/Microsoft.AspNet.Hosting/Internal/IHostingEngine.cs deleted file mode 100644 index 4b8789a9ca..0000000000 --- a/src/Microsoft.AspNet.Hosting/Internal/IHostingEngine.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) .NET Foundation. 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 - { - IApplication Start(); - - // Accessing this will block Use methods - IServiceProvider ApplicationServices { get; } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs b/src/Microsoft.AspNet.Hosting/Internal/WebApplication.cs similarity index 87% rename from src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs rename to src/Microsoft.AspNet.Hosting/Internal/WebApplication.cs index 6236fa2e8c..0014537a7b 100644 --- a/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs +++ b/src/Microsoft.AspNet.Hosting/Internal/WebApplication.cs @@ -19,7 +19,7 @@ using Microsoft.Extensions.PlatformAbstractions; namespace Microsoft.AspNet.Hosting.Internal { - public class HostingEngine : IHostingEngine + public class WebApplication : IWebApplication { // This is defined by IIS's HttpPlatformHandler. private static readonly string ServerPort = "HTTP_PLATFORM_PORT"; @@ -27,11 +27,11 @@ namespace Microsoft.AspNet.Hosting.Internal private readonly IServiceCollection _applicationServiceCollection; private readonly IStartupLoader _startupLoader; private readonly ApplicationLifetime _applicationLifetime; - private readonly WebHostOptions _options; + private readonly WebApplicationOptions _options; private readonly IConfiguration _config; - private readonly bool _captureStartupErrors; private IServiceProvider _applicationServices; + private RequestDelegate _application; // Only one of these should be set internal string StartupAssemblyName { get; set; } @@ -43,12 +43,11 @@ namespace Microsoft.AspNet.Hosting.Internal internal string ServerFactoryLocation { get; set; } internal IServer Server { get; set; } - public HostingEngine( + public WebApplication( IServiceCollection appServices, IStartupLoader startupLoader, - WebHostOptions options, - IConfiguration config, - bool captureStartupErrors) + WebApplicationOptions options, + IConfiguration config) { if (appServices == null) { @@ -69,12 +68,11 @@ namespace Microsoft.AspNet.Hosting.Internal _options = options; _applicationServiceCollection = appServices; _startupLoader = startupLoader; - _captureStartupErrors = captureStartupErrors; _applicationLifetime = new ApplicationLifetime(); _applicationServiceCollection.AddSingleton(_applicationLifetime); } - public IServiceProvider ApplicationServices + public IServiceProvider Services { get { @@ -83,29 +81,45 @@ namespace Microsoft.AspNet.Hosting.Internal } } - public virtual IApplication Start() + public IFeatureCollection ServerFeatures { - var application = BuildApplication(); + get + { + return Server?.Features; + } + } - var logger = _applicationServices.GetRequiredService>(); + public void Initialize() + { + if (_application == null) + { + _application = BuildApplication(); + } + } + + public virtual IDisposable Start() + { + Initialize(); + + var logger = _applicationServices.GetRequiredService>(); var diagnosticSource = _applicationServices.GetRequiredService(); var httpContextFactory = _applicationServices.GetRequiredService(); logger.Starting(); - Server.Start(new HostingApplication(application, logger, diagnosticSource, httpContextFactory)); + Server.Start(new HostingApplication(_application, logger, diagnosticSource, httpContextFactory)); _applicationLifetime.NotifyStarted(); logger.Started(); - return new Application(ApplicationServices, Server.Features, new Disposable(() => - { - logger.Shutdown(); - _applicationLifetime.StopApplication(); - Server.Dispose(); - _applicationLifetime.NotifyStopped(); - (_applicationServices as IDisposable)?.Dispose(); - })); + return new Disposable(() => + { + logger.Shutdown(); + _applicationLifetime.StopApplication(); + Server.Dispose(); + _applicationLifetime.NotifyStopped(); + (_applicationServices as IDisposable)?.Dispose(); + }); } private void EnsureApplicationServices() @@ -168,7 +182,7 @@ namespace Microsoft.AspNet.Hosting.Internal return builder.Build(); } - catch (Exception ex) when (_captureStartupErrors) + catch (Exception ex) when (_options.CaptureStartupErrors) { // EnsureApplicationServices may have failed due to a missing or throwing Startup class. if (_applicationServices == null) @@ -180,7 +194,7 @@ namespace Microsoft.AspNet.Hosting.Internal // Write errors to standard out so they can be retrieved when not in development mode. Console.Out.WriteLine("Application startup exception: " + ex.ToString()); - var logger = _applicationServices.GetRequiredService>(); + var logger = _applicationServices.GetRequiredService>(); logger.ApplicationError(ex); // Generate an HTML error page. diff --git a/src/Microsoft.AspNet.Hosting/Internal/WebApplicationOptions.cs b/src/Microsoft.AspNet.Hosting/Internal/WebApplicationOptions.cs new file mode 100644 index 0000000000..ef76bcdb8f --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/Internal/WebApplicationOptions.cs @@ -0,0 +1,50 @@ +// Copyright (c) .NET Foundation. 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.Extensions.Configuration; + +namespace Microsoft.AspNet.Hosting.Internal +{ + public class WebApplicationOptions + { + private const string OldEnvironmentKey = "ENV"; + + public WebApplicationOptions() + { + } + + public WebApplicationOptions(IConfiguration configuration) + { + if (configuration == null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + Application = configuration[WebApplicationConfiguration.ApplicationKey]; + DetailedErrors = ParseBool(configuration, WebApplicationConfiguration.DetailedErrorsKey); + CaptureStartupErrors = ParseBool(configuration, WebApplicationConfiguration.CaptureStartupErrorsKey); + Environment = configuration[WebApplicationConfiguration.EnvironmentKey] ?? configuration[OldEnvironmentKey]; + ServerFactoryLocation = configuration[WebApplicationConfiguration.ServerKey]; + WebRoot = configuration[WebApplicationConfiguration.WebRootKey]; + } + + public string Application { get; set; } + + public bool DetailedErrors { get; set; } + + public bool CaptureStartupErrors { get; set; } + + public string Environment { get; set; } + + public string ServerFactoryLocation { get; set; } + + public string WebRoot { get; set; } + + private static bool ParseBool(IConfiguration configuration, string key) + { + return string.Equals("true", configuration[key], StringComparison.OrdinalIgnoreCase) + || string.Equals("1", configuration[key], StringComparison.OrdinalIgnoreCase); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/Program.cs b/src/Microsoft.AspNet.Hosting/Program.cs deleted file mode 100644 index 80fa43f73f..0000000000 --- a/src/Microsoft.AspNet.Hosting/Program.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNet.Hosting -{ - public class Program - { - public static void Main(string[] args) - { - WebApplication.Run(args); - } - } -} diff --git a/src/Microsoft.AspNet.Hosting/WebApplication.cs b/src/Microsoft.AspNet.Hosting/WebApplication.cs deleted file mode 100644 index f819fcec7a..0000000000 --- a/src/Microsoft.AspNet.Hosting/WebApplication.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) .NET Foundation. 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.Http.Features; -using Microsoft.AspNet.Server.Features; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.AspNet.Hosting -{ - public class WebApplication - { - private const string HostingJsonFile = "hosting.json"; - private const string EnvironmentVariablesPrefix = "ASPNET_"; - private const string ConfigFileKey = "config"; - - public static void Run(string[] args) - { - Run(startupType: null, args: args); - } - - public static void Run() - { - Run(typeof(TStartup), null); - } - - public static void Run(string[] args) - { - Run(typeof(TStartup), args); - } - - public static void Run(Type startupType) - { - Run(startupType, null); - } - - public static void Run(Type startupType, string[] args) - { - // Allow the location of the json file to be specified via a --config command line arg - var tempBuilder = new ConfigurationBuilder().AddCommandLine(args); - var tempConfig = tempBuilder.Build(); - var configFilePath = tempConfig[ConfigFileKey] ?? HostingJsonFile; - var config = LoadHostingConfiguration(configFilePath, args); - - var hostBuilder = new WebHostBuilder(config, captureStartupErrors: true); - if (startupType != null) - { - hostBuilder.UseStartup(startupType); - } - var host = hostBuilder.Build(); - using (var app = host.Start()) - { - var hostingEnv = app.Services.GetRequiredService(); - Console.WriteLine("Hosting environment: " + hostingEnv.EnvironmentName); - - var serverAddresses = app.ServerFeatures.Get(); - if (serverAddresses != null) - { - foreach (var address in serverAddresses.Addresses) - { - Console.WriteLine("Now listening on: " + address); - } - } - - Console.WriteLine("Application started. Press Ctrl+C to shut down."); - - var appLifetime = app.Services.GetRequiredService(); - - Console.CancelKeyPress += (sender, eventArgs) => - { - appLifetime.StopApplication(); - // Don't terminate the process immediately, wait for the Main thread to exit gracefully. - eventArgs.Cancel = true; - }; - - appLifetime.ApplicationStopping.WaitHandle.WaitOne(); - } - } - - internal static IConfiguration LoadHostingConfiguration(string configJsonPath, string[] args) - { - // We are adding all environment variables first and then adding the ASPNET_ ones - // with the prefix removed to unify with the command line and config file formats - return new ConfigurationBuilder() - .AddJsonFile(configJsonPath, optional: true) - .AddEnvironmentVariables() - .AddEnvironmentVariables(prefix: EnvironmentVariablesPrefix) - .AddCommandLine(args) - .Build(); - } - } -} diff --git a/src/Microsoft.AspNet.Hosting/WebHostBuilder.cs b/src/Microsoft.AspNet.Hosting/WebApplicationBuilder.cs similarity index 65% rename from src/Microsoft.AspNet.Hosting/WebHostBuilder.cs rename to src/Microsoft.AspNet.Hosting/WebApplicationBuilder.cs index 5f4d3a1dd1..4350a2b35b 100644 --- a/src/Microsoft.AspNet.Hosting/WebHostBuilder.cs +++ b/src/Microsoft.AspNet.Hosting/WebApplicationBuilder.cs @@ -18,49 +18,180 @@ using Microsoft.Extensions.PlatformAbstractions; namespace Microsoft.AspNet.Hosting { - public class WebHostBuilder + public class WebApplicationBuilder { private readonly IHostingEnvironment _hostingEnvironment; private readonly ILoggerFactory _loggerFactory; - private readonly IConfiguration _config; - private readonly WebHostOptions _options; + + private IConfiguration _config; + private WebApplicationOptions _options; private Action _configureServices; private string _environmentName; + private string _webRoot; // Only one of these should be set private StartupMethods _startup; private Type _startupType; private string _startupAssemblyName; - private readonly bool _captureStartupErrors; // Only one of these should be set private string _serverFactoryLocation; private IServerFactory _serverFactory; private IServer _server; - public WebHostBuilder() - : this(config: new ConfigurationBuilder().Build()) + public WebApplicationBuilder() { - } - - public WebHostBuilder(IConfiguration config) - : this(config: config, captureStartupErrors: false) - { - } - - public WebHostBuilder(IConfiguration config, bool captureStartupErrors) - { - if (config == null) - { - throw new ArgumentNullException(nameof(config)); - } - _hostingEnvironment = new HostingEnvironment(); _loggerFactory = new LoggerFactory(); - _config = config; - _options = new WebHostOptions(config); - _captureStartupErrors = captureStartupErrors; + } + + public WebApplicationBuilder UseConfiguration(IConfiguration configuration) + { + _config = configuration; + return this; + } + + public WebApplicationBuilder UseEnvironment(string environment) + { + if (environment == null) + { + throw new ArgumentNullException(nameof(environment)); + } + + _environmentName = environment; + return this; + } + + public WebApplicationBuilder UseWebRoot(string webRoot) + { + if (webRoot == null) + { + throw new ArgumentNullException(nameof(webRoot)); + } + _webRoot = webRoot; + return this; + } + + public WebApplicationBuilder UseServer(IServer server) + { + if (server == null) + { + throw new ArgumentNullException(nameof(server)); + } + + _server = server; + return this; + } + + public WebApplicationBuilder UseServerFactory(string assemblyName) + { + if (assemblyName == null) + { + throw new ArgumentNullException(nameof(assemblyName)); + } + + _serverFactoryLocation = assemblyName; + return this; + } + + public WebApplicationBuilder UseServerFactory(IServerFactory factory) + { + if (factory == null) + { + throw new ArgumentNullException(nameof(factory)); + } + + _serverFactory = factory; + return this; + } + + public WebApplicationBuilder UseStartup(string startupAssemblyName) + { + if (startupAssemblyName == null) + { + throw new ArgumentNullException(nameof(startupAssemblyName)); + } + + _startupAssemblyName = startupAssemblyName; + return this; + } + + public WebApplicationBuilder UseStartup(Type startupType) + { + if (startupType == null) + { + throw new ArgumentNullException(nameof(startupType)); + } + + _startupType = startupType; + return this; + } + + public WebApplicationBuilder UseStartup() where TStartup : class + { + return UseStartup(typeof(TStartup)); + } + + public WebApplicationBuilder ConfigureServices(Action configureServices) + { + _configureServices = configureServices; + return this; + } + + public WebApplicationBuilder Configure(Action configureApp) + { + if (configureApp == null) + { + throw new ArgumentNullException(nameof(configureApp)); + } + + _startup = new StartupMethods(configureApp); + return this; + } + + public WebApplicationBuilder ConfigureLogging(Action configureLogging) + { + configureLogging(_loggerFactory); + return this; + } + + public IWebApplication Build() + { + var hostingServices = BuildHostingServices(); + + var hostingContainer = hostingServices.BuildServiceProvider(); + + var appEnvironment = hostingContainer.GetRequiredService(); + var startupLoader = hostingContainer.GetRequiredService(); + + _config = _config ?? WebApplicationConfiguration.GetDefault(); + _options = new WebApplicationOptions(_config); + + // Initialize the hosting environment + _options.WebRoot = _webRoot ?? _options.WebRoot; + _hostingEnvironment.Initialize(appEnvironment.ApplicationBasePath, _options, _config); + + if (!string.IsNullOrEmpty(_environmentName)) + { + _hostingEnvironment.EnvironmentName = _environmentName; + } + + var application = new WebApplication(hostingServices, startupLoader, _options, _config); + + // Only one of these should be set, but they are used in priority + application.Server = _server; + application.ServerFactory = _serverFactory; + application.ServerFactoryLocation = _options.ServerFactoryLocation ?? _serverFactoryLocation; + + // Only one of these should be set, but they are used in priority + application.Startup = _startup; + application.StartupType = _startupType; + application.StartupAssemblyName = _startupAssemblyName ?? _options.Application; + + application.Initialize(); + + return application; } private IServiceCollection BuildHostingServices() @@ -83,11 +214,6 @@ namespace Microsoft.AspNet.Hosting // Conjure up a RequestServices services.AddTransient(); - if (_configureServices != null) - { - _configureServices(services); - } - var defaultPlatformServices = PlatformServices.Default; if (defaultPlatformServices != null) { @@ -102,153 +228,12 @@ namespace Microsoft.AspNet.Hosting } } + 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, _options, _config); - if (!string.IsNullOrEmpty(_environmentName)) - { - _hostingEnvironment.EnvironmentName = _environmentName; - } - var engine = new HostingEngine(hostingServices, startupLoader, _options, _config, _captureStartupErrors); - - // Only one of these should be set, but they are used in priority - engine.Server = _server; - engine.ServerFactory = _serverFactory; - engine.ServerFactoryLocation = _options.Server ?? _serverFactoryLocation; - - // Only one of these should be set, but they are used in priority - engine.Startup = _startup; - engine.StartupType = _startupType; - engine.StartupAssemblyName = _startupAssemblyName ?? _options.Application ?? appEnvironment.ApplicationName; - - return engine; - } - - public WebHostBuilder UseServices(Action configureServices) - { - _configureServices = configureServices; - return this; - } - - public WebHostBuilder UseEnvironment(string environment) - { - if (environment == null) - { - throw new ArgumentNullException(nameof(environment)); - } - - _environmentName = environment; - return this; - } - - public WebHostBuilder UseServer(IServer server) - { - if (server == null) - { - throw new ArgumentNullException(nameof(server)); - } - - _server = server; - return this; - } - - public WebHostBuilder UseServerFactory(string assemblyName) - { - if (assemblyName == null) - { - throw new ArgumentNullException(nameof(assemblyName)); - } - - _serverFactoryLocation = assemblyName; - return this; - } - - public WebHostBuilder UseServerFactory(IServerFactory factory) - { - if (factory == null) - { - throw new ArgumentNullException(nameof(factory)); - } - - _serverFactory = factory; - return this; - } - - public WebHostBuilder UseStartup(string startupAssemblyName) - { - if (startupAssemblyName == null) - { - throw new ArgumentNullException(nameof(startupAssemblyName)); - } - - _startupAssemblyName = startupAssemblyName; - return this; - } - - public WebHostBuilder UseStartup(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(Action configureApp) - { - if (configureApp == null) - { - throw new ArgumentNullException(nameof(configureApp)); - } - - return UseStartup(configureApp, configureServices: null); - } - - public WebHostBuilder UseStartup(Action configureApp, Func configureServices) - { - if (configureApp == null) - { - throw new ArgumentNullException(nameof(configureApp)); - } - - _startup = new StartupMethods(configureApp, configureServices); - return this; - } - - public WebHostBuilder UseStartup(Action configureApp, Action configureServices) - { - if (configureApp == null) - { - throw new ArgumentNullException(nameof(configureApp)); - } - - _startup = new StartupMethods(configureApp, - services => - { - if (configureServices != null) - { - configureServices(services); - } - return services.BuildServiceProvider(); - }); - return this; - } } } diff --git a/src/Microsoft.AspNet.Hosting/WebApplicationConfiguration.cs b/src/Microsoft.AspNet.Hosting/WebApplicationConfiguration.cs new file mode 100644 index 0000000000..0d71dafc2d --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/WebApplicationConfiguration.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.Configuration; + +namespace Microsoft.AspNet.Hosting +{ + public class WebApplicationConfiguration + { + public static readonly string ApplicationKey = "app"; + public static readonly string DetailedErrorsKey = "detailedErrors"; + public static readonly string EnvironmentKey = "environment"; + public static readonly string ServerKey = "server"; + public static readonly string WebRootKey = "webroot"; + public static readonly string CaptureStartupErrorsKey = "captureStartupErrors"; + + public static readonly string HostingJsonFile = "hosting.json"; + public static readonly string EnvironmentVariablesPrefix = "ASPNET_"; + + public static IConfiguration GetDefault() + { + return GetDefault(args: null); + } + + public static IConfiguration GetDefault(string[] args) + { + // We are adding all environment variables first and then adding the ASPNET_ ones + // with the prefix removed to unify with the command line and config file formats + var configBuilder = new ConfigurationBuilder() + .AddJsonFile(HostingJsonFile, optional: true) + .AddEnvironmentVariables() + .AddEnvironmentVariables(prefix: EnvironmentVariablesPrefix); + + if (args != null) + { + configBuilder.AddCommandLine(args); + } + + return configBuilder.Build(); + } + } + +} diff --git a/src/Microsoft.AspNet.Hosting/WebApplicationExtensions.cs b/src/Microsoft.AspNet.Hosting/WebApplicationExtensions.cs new file mode 100644 index 0000000000..a0b0f0b3f6 --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/WebApplicationExtensions.cs @@ -0,0 +1,60 @@ +// Copyright (c) .NET Foundation. 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.Http.Features; +using Microsoft.AspNet.Server.Features; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.AspNet.Hosting +{ + public static class WebApplicationExtensions + { + /// + /// Retruns the server addresses the web application is going to listen on. + /// + /// + /// An which the addresses the server will listen to + public static ICollection GetAddresses(this IWebApplication application) + { + return application.ServerFeatures.Get()?.Addresses; + } + + /// + /// Runs a web application and block the calling thread until host shutdown. + /// + /// + public static void Run(this IWebApplication application) + { + using (application.Start()) + { + var hostingEnvironment = application.Services.GetService(); + var applicationLifetime = application.Services.GetService(); + + Console.WriteLine("Hosting environment: " + hostingEnvironment.EnvironmentName); + + var serverAddresses = application.GetAddresses(); + if (serverAddresses != null) + { + foreach (var address in serverAddresses) + { + Console.WriteLine("Now listening on: " + address); + } + } + + Console.WriteLine("Application started. Press Ctrl+C to shut down."); + + Console.CancelKeyPress += (sender, eventArgs) => + { + applicationLifetime.StopApplication(); + + // Don't terminate the process immediately, wait for the Main thread to exit gracefully. + eventArgs.Cancel = true; + }; + + applicationLifetime.ApplicationStopping.WaitHandle.WaitOne(); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Hosting/WebHostOptions.cs b/src/Microsoft.AspNet.Hosting/WebHostOptions.cs deleted file mode 100644 index 89a0aad6bc..0000000000 --- a/src/Microsoft.AspNet.Hosting/WebHostOptions.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) .NET Foundation. 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.Extensions.Configuration; - -namespace Microsoft.AspNet.Hosting -{ - public class WebHostOptions - { - private const string ApplicationKey = "app"; - private const string DetailedErrorsKey = "detailedErrors"; - private const string EnvironmentKey = "environment"; - private const string ServerKey = "server"; - private const string WebRootKey = "webroot"; - private const string OldEnvironmentKey = "ENV"; - - public WebHostOptions() - { - } - - public WebHostOptions(IConfiguration configuration) - { - if (configuration == null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - Application = configuration[ApplicationKey]; - DetailedErrors = string.Equals("true", configuration[DetailedErrorsKey], StringComparison.OrdinalIgnoreCase) - || string.Equals("1", configuration[DetailedErrorsKey], StringComparison.OrdinalIgnoreCase); - Environment = configuration[EnvironmentKey] ?? configuration[OldEnvironmentKey]; - Server = configuration[ServerKey]; - WebRoot = configuration[WebRootKey]; - } - - public string Application { get; set; } - - public bool DetailedErrors { get; set; } - - public string Environment { get; set; } - - public string Server { get; set; } - - public string WebRoot { get; set; } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.TestHost/TestServer.cs b/src/Microsoft.AspNet.TestHost/TestServer.cs index efeefac128..51980617cf 100644 --- a/src/Microsoft.AspNet.TestHost/TestServer.cs +++ b/src/Microsoft.AspNet.TestHost/TestServer.cs @@ -4,13 +4,10 @@ using System; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; using Context = Microsoft.AspNet.Hosting.Internal.HostingApplication.Context; namespace Microsoft.AspNet.TestHost @@ -23,78 +20,16 @@ namespace Microsoft.AspNet.TestHost private bool _disposed = false; private IHttpApplication _application; - public TestServer(WebHostBuilder builder) + public TestServer(WebApplicationBuilder builder) { - var hostingEngine = builder.UseServer(this).Build(); - _appInstance = hostingEngine.Start(); + var application = builder.UseServer(this).Build(); + _appInstance = application.Start(); } public Uri BaseAddress { get; set; } = new Uri("http://localhost/"); IFeatureCollection IServer.Features { get; } - public static TestServer Create() - { - return Create(config: null, configureApp: null, configureServices: null); - } - - public static TestServer Create(Action configureApp) - { - return Create(config: null, configureApp: configureApp, configureServices: null); - } - - public static TestServer Create(Action configureApp, Action configureServices) - { - return Create(config: null, configureApp: configureApp, configureServices: configureServices); - } - - public static TestServer Create(Action configureApp, Func configureServices) - { - return new TestServer(CreateBuilder(config: null, configureApp: configureApp, configureServices: configureServices, configureHostServices: null)); - } - public static TestServer Create(Action configureApp, Func configureServices, Action configureHostServices) - { - return new TestServer(CreateBuilder(config: null, configureApp: configureApp, configureServices: configureServices, configureHostServices: configureHostServices)); - } - - public static TestServer Create(IConfiguration config, Action configureApp, Action configureServices) - { - return new TestServer(CreateBuilder(config, configureApp, configureServices)); - } - - public static WebHostBuilder CreateBuilder(IConfiguration config, Action configureApp, Action configureServices) - { - return CreateBuilder(config, configureApp, - s => - { - if (configureServices != null) - { - configureServices(s); - } - return s.BuildServiceProvider(); - }, null); - } - public static WebHostBuilder CreateBuilder(IConfiguration config, Action configureApp, Func configureServices) - { - return CreateBuilder(config, configureApp, configureServices, null); - } - - public static WebHostBuilder CreateBuilder(IConfiguration config, Action configureApp, Func configureServices, Action configureHostServices) - { - return CreateBuilder(config).UseStartup(configureApp, configureServices).UseServices(configureHostServices); - } - - public static WebHostBuilder CreateBuilder(IConfiguration config) - { - return new WebHostBuilder( - config ?? new ConfigurationBuilder().Build()); - } - - public static WebHostBuilder CreateBuilder() - { - return CreateBuilder(config: null); - } - public HttpMessageHandler CreateHandler() { var pathBase = BaseAddress == null ? PathString.Empty : PathString.FromUriComponent(BaseAddress); @@ -141,8 +76,8 @@ namespace Microsoft.AspNet.TestHost private class ApplicationWrapper : IHttpApplication { - IHttpApplication _application; - Action _preProcessRequestAsync; + private readonly IHttpApplication _application; + private readonly Action _preProcessRequestAsync; public ApplicationWrapper(IHttpApplication application, Action preProcessRequestAsync) { diff --git a/test/Microsoft.AspNet.Hosting.Tests/HostingEnvironmentExtensionsTests.cs b/test/Microsoft.AspNet.Hosting.Tests/HostingEnvironmentExtensionsTests.cs index 727130ded8..be2072bf9a 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/HostingEnvironmentExtensionsTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/HostingEnvironmentExtensionsTests.cs @@ -4,7 +4,6 @@ using System; using System.IO; using Microsoft.AspNet.FileProviders; -using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Hosting.Internal; using Microsoft.Extensions.Configuration; using Xunit; @@ -18,7 +17,7 @@ namespace Microsoft.AspNet.Hosting.Tests { var env = new HostingEnvironment(); - env.Initialize(".", new WebHostOptions() {WebRoot = "testroot"}, null); + env.Initialize(".", new WebApplicationOptions() {WebRoot = "testroot"}, null); Assert.Equal(Path.GetFullPath("testroot"), env.WebRootPath); Assert.IsAssignableFrom(env.WebRootFileProvider); @@ -29,7 +28,7 @@ namespace Microsoft.AspNet.Hosting.Tests { var env = new HostingEnvironment(); - env.Initialize("testroot", new WebHostOptions(), null); + env.Initialize("testroot", new WebApplicationOptions(), null); Assert.Equal(Path.GetFullPath(Path.Combine("testroot","wwwroot")), env.WebRootPath); Assert.IsAssignableFrom(env.WebRootFileProvider); @@ -40,7 +39,7 @@ namespace Microsoft.AspNet.Hosting.Tests { var env = new HostingEnvironment(); - env.Initialize(Path.Combine("testroot", "wwwroot"), new WebHostOptions(), null); + env.Initialize(Path.Combine("testroot", "wwwroot"), new WebApplicationOptions(), null); Assert.Null(env.WebRootPath); Assert.IsAssignableFrom(env.WebRootFileProvider); @@ -52,7 +51,7 @@ namespace Microsoft.AspNet.Hosting.Tests var config = new ConfigurationBuilder().Build(); var env = new HostingEnvironment(); - env.Initialize(".", new WebHostOptions(), config); + env.Initialize(".", new WebApplicationOptions(), config); Assert.Same(config, env.Configuration); } @@ -63,7 +62,7 @@ namespace Microsoft.AspNet.Hosting.Tests var env = new HostingEnvironment(); env.EnvironmentName = "SomeName"; - env.Initialize(".", new WebHostOptions() { Environment = "NewName" }, null); + env.Initialize(".", new WebApplicationOptions() { Environment = "NewName" }, null); Assert.Equal("NewName", env.EnvironmentName); } @@ -73,7 +72,7 @@ namespace Microsoft.AspNet.Hosting.Tests { var env = new HostingEnvironment(); - env.Initialize(".", new WebHostOptions(), null); + env.Initialize(".", new WebApplicationOptions(), null); Assert.Throws(() => env.MapPath("file.txt")); } diff --git a/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs b/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs index 0272e66a81..8b0c67652d 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs @@ -7,6 +7,7 @@ using System.Reflection; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Builder.Internal; using Microsoft.AspNet.Hosting.Fakes; +using Microsoft.AspNet.Hosting.Internal; using Microsoft.AspNet.Hosting.Startup; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.OptionsModel; diff --git a/test/Microsoft.AspNet.Hosting.Tests/WebHostBuilderTests.cs b/test/Microsoft.AspNet.Hosting.Tests/WebApplicationBuilderTests.cs similarity index 66% rename from test/Microsoft.AspNet.Hosting.Tests/WebHostBuilderTests.cs rename to test/Microsoft.AspNet.Hosting.Tests/WebApplicationBuilderTests.cs index cd7c1ee3b4..edeaffb499 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/WebHostBuilderTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/WebApplicationBuilderTests.cs @@ -17,35 +17,25 @@ using Xunit; namespace Microsoft.AspNet.Hosting { - public class WebHostBuilderTests + public class WebApplicationBuilderTests { - [Fact] - public void Build_uses_application_for_startup_assembly_by_default() - { - var builder = CreateWebHostBuilder(); - - var engine = (HostingEngine)builder.Build(); - - Assert.Equal("Microsoft.AspNet.Hosting.Tests", engine.StartupAssemblyName); - } - [Fact] public void Build_honors_UseStartup_with_string() { - var builder = CreateWebHostBuilder(); + var builder = CreateWebApplicationBuilder().UseServer(new TestServer()); - var engine = (HostingEngine)builder.UseStartup("MyStartupAssembly").Build(); + var application = (WebApplication)builder.UseStartup("MyStartupAssembly").Build(); - Assert.Equal("MyStartupAssembly", engine.StartupAssemblyName); + Assert.Equal("MyStartupAssembly", application.StartupAssemblyName); } [Fact] public async Task StartupMissing_Fallback() { - var builder = CreateWebHostBuilder(); + var builder = CreateWebApplicationBuilder(); var server = new TestServer(); - var engine = builder.UseServer(server).UseStartup("MissingStartupAssembly").Build(); - using (engine.Start()) + var application = builder.UseServer(server).UseStartup("MissingStartupAssembly").Build(); + using (application.Start()) { await AssertResponseContains(server.RequestDelegate, "MissingStartupAssembly"); } @@ -54,10 +44,10 @@ namespace Microsoft.AspNet.Hosting [Fact] public async Task StartupStaticCtorThrows_Fallback() { - var builder = CreateWebHostBuilder(); + var builder = CreateWebApplicationBuilder(); var server = new TestServer(); - var engine = builder.UseServer(server).UseStartup().Build(); - using (engine.Start()) + var application = builder.UseServer(server).UseStartup().Build(); + using (application.Start()) { await AssertResponseContains(server.RequestDelegate, "Exception from static constructor"); } @@ -66,10 +56,10 @@ namespace Microsoft.AspNet.Hosting [Fact] public async Task StartupCtorThrows_Fallback() { - var builder = CreateWebHostBuilder(); + var builder = CreateWebApplicationBuilder(); var server = new TestServer(); - var engine = builder.UseServer(server).UseStartup().Build(); - using (engine.Start()) + var application = builder.UseServer(server).UseStartup().Build(); + using (application.Start()) { await AssertResponseContains(server.RequestDelegate, "Exception from constructor"); } @@ -78,10 +68,10 @@ namespace Microsoft.AspNet.Hosting [Fact] public async Task StartupCtorThrows_TypeLoadException() { - var builder = CreateWebHostBuilder(); + var builder = CreateWebApplicationBuilder(); var server = new TestServer(); - var engine = builder.UseServer(server).UseStartup().Build(); - using (engine.Start()) + var application = builder.UseServer(server).UseStartup().Build(); + using (application.Start()) { await AssertResponseContains(server.RequestDelegate, "Message from the LoaderException"); } @@ -90,12 +80,12 @@ namespace Microsoft.AspNet.Hosting [Fact] public async Task IApplicationLifetimeRegisteredEvenWhenStartupCtorThrows_Fallback() { - var builder = CreateWebHostBuilder(); + var builder = CreateWebApplicationBuilder(); var server = new TestServer(); - var engine = builder.UseServer(server).UseStartup().Build(); - using (engine.Start()) + var application = builder.UseServer(server).UseStartup().Build(); + using (application.Start()) { - var service = engine.ApplicationServices.GetServices(); + var service = application.Services.GetServices(); Assert.NotNull(service); await AssertResponseContains(server.RequestDelegate, "Exception from constructor"); } @@ -104,10 +94,10 @@ namespace Microsoft.AspNet.Hosting [Fact] public async Task StartupConfigureServicesThrows_Fallback() { - var builder = CreateWebHostBuilder(); + var builder = CreateWebApplicationBuilder(); var server = new TestServer(); - var engine = builder.UseServer(server).UseStartup().Build(); - using (engine.Start()) + var application = builder.UseServer(server).UseStartup().Build(); + using (application.Start()) { await AssertResponseContains(server.RequestDelegate, "Exception from ConfigureServices"); } @@ -116,10 +106,10 @@ namespace Microsoft.AspNet.Hosting [Fact] public async Task StartupConfigureThrows_Fallback() { - var builder = CreateWebHostBuilder(); + var builder = CreateWebApplicationBuilder(); var server = new TestServer(); - var engine = builder.UseServer(server).UseStartup().Build(); - using (engine.Start()) + var application = builder.UseServer(server).UseStartup().Build(); + using (application.Start()) { await AssertResponseContains(server.RequestDelegate, "Exception from Configure"); } @@ -137,22 +127,27 @@ namespace Microsoft.AspNet.Hosting var config = builder.Build(); var expected = "MY_TEST_ENVIRONMENT"; - var webHost = new WebHostBuilder(config, captureStartupErrors: true).UseEnvironment(expected).Build(); + var application = new WebApplicationBuilder() + .UseConfiguration(config) + .UseEnvironment(expected) + .UseServer(new TestServer()) + .UseStartup("Microsoft.AspNet.Hosting.Tests") + .Build(); - Assert.Equal(expected, webHost.ApplicationServices.GetService().EnvironmentName); + Assert.Equal(expected, application.Services.GetService().EnvironmentName); } - private WebHostBuilder CreateWebHostBuilder() + private WebApplicationBuilder CreateWebApplicationBuilder() { var vals = new Dictionary { - { "server", "Microsoft.AspNet.Hosting.Tests" }, { "DetailedErrors", "true" }, + { "captureStartupErrors", "true" } }; var builder = new ConfigurationBuilder() .AddInMemoryCollection(vals); var config = builder.Build(); - return new WebHostBuilder(config, captureStartupErrors: true); + return new WebApplicationBuilder().UseConfiguration(config); } private async Task AssertResponseContains(RequestDelegate app, string expectedText) diff --git a/test/Microsoft.AspNet.Hosting.Tests/WebHostConfigurationsTests.cs b/test/Microsoft.AspNet.Hosting.Tests/WebApplicationConfigurationsTests.cs similarity index 66% rename from test/Microsoft.AspNet.Hosting.Tests/WebHostConfigurationsTests.cs rename to test/Microsoft.AspNet.Hosting.Tests/WebApplicationConfigurationsTests.cs index ea3b314bbd..3e935c68cd 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/WebHostConfigurationsTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/WebApplicationConfigurationsTests.cs @@ -1,23 +1,14 @@ // Copyright (c) .NET Foundation. 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; using System.Collections.Generic; -using System.IO; -using System.Reflection; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Builder.Internal; -using Microsoft.AspNet.Hosting.Fakes; -using Microsoft.AspNet.Hosting.Startup; +using Microsoft.AspNet.Hosting.Internal; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.OptionsModel; using Xunit; namespace Microsoft.AspNet.Hosting.Tests { - public class WebHostConfigurationTests + public class WebApplicationConfigurationTests { [Fact] public void ReadsParametersCorrectly() @@ -29,22 +20,24 @@ namespace Microsoft.AspNet.Hosting.Tests {"app", "MyProjectReference"}, {"environment", "Development"}, {"detailederrors", "true"}, + { "captureStartupErrors", "true" } }; - var config = new WebHostOptions(new ConfigurationBuilder().AddInMemoryCollection(parameters).Build()); + var config = new WebApplicationOptions(new ConfigurationBuilder().AddInMemoryCollection(parameters).Build()); Assert.Equal("wwwroot", config.WebRoot); - Assert.Equal("Microsoft.AspNet.Server.Kestrel", config.Server); + Assert.Equal("Microsoft.AspNet.Server.Kestrel", config.ServerFactoryLocation); Assert.Equal("MyProjectReference", config.Application); Assert.Equal("Development", config.Environment); - Assert.Equal(true, config.DetailedErrors); + Assert.True(config.CaptureStartupErrors); + Assert.True(config.DetailedErrors); } [Fact] public void ReadsOldEnvKey() { var parameters = new Dictionary() { { "ENV", "Development" } }; - var config = new WebHostOptions(new ConfigurationBuilder().AddInMemoryCollection(parameters).Build()); + var config = new WebApplicationOptions(new ConfigurationBuilder().AddInMemoryCollection(parameters).Build()); Assert.Equal("Development", config.Environment); } @@ -55,7 +48,7 @@ namespace Microsoft.AspNet.Hosting.Tests public void AllowsNumberForDetailedErrors(string value, bool expected) { var parameters = new Dictionary() { { "detailedErrors", value } }; - var config = new WebHostOptions(new ConfigurationBuilder().AddInMemoryCollection(parameters).Build()); + var config = new WebApplicationOptions(new ConfigurationBuilder().AddInMemoryCollection(parameters).Build()); Assert.Equal(expected, config.DetailedErrors); } diff --git a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs b/test/Microsoft.AspNet.Hosting.Tests/WebApplicationTests.cs similarity index 77% rename from test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs rename to test/Microsoft.AspNet.Hosting.Tests/WebApplicationTests.cs index da2dd15336..d66419639f 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/WebApplicationTests.cs @@ -9,7 +9,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting.Fakes; -using Microsoft.AspNet.Hosting.Internal; using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Hosting.Startup; using Microsoft.AspNet.Http; @@ -25,7 +24,7 @@ using Xunit; namespace Microsoft.AspNet.Hosting { - public class HostingEngineTests : IServerFactory, IServer + public class WebApplicationTests : IServerFactory, IServer { private readonly IList _startInstances = new List(); private IFeatureCollection _featuresSupportedByThisHost = NewFeatureCollection(); @@ -63,7 +62,7 @@ namespace Microsoft.AspNet.Hosting } [Fact] - public void HostingEngineThrowsWithNoServer() + public void WebApplicationThrowsWithNoServer() { var ex = Assert.Throws(() => CreateBuilder().Build().Start()); Assert.True(ex.Message.Contains("UseServer()")); @@ -86,9 +85,9 @@ namespace Microsoft.AspNet.Hosting var builder = new ConfigurationBuilder() .AddInMemoryCollection(vals); var config = builder.Build(); - var host = CreateBuilder(config).Build(); - host.Start(); - Assert.NotNull(host.ApplicationServices.GetRequiredService()); + var application = CreateBuilder(config).Build(); + application.Start(); + Assert.NotNull(application.Services.GetService()); } [Fact] @@ -102,9 +101,9 @@ namespace Microsoft.AspNet.Hosting var builder = new ConfigurationBuilder() .AddInMemoryCollection(vals); var config = builder.Build(); - var host = CreateBuilder(config).Build(); - host.Start(); - Assert.NotNull(host.ApplicationServices.GetRequiredService()); + var application = CreateBuilder(config).Build(); + application.Start(); + Assert.NotNull(application.Services.GetService()); } [Fact] @@ -119,10 +118,10 @@ namespace Microsoft.AspNet.Hosting var builder = new ConfigurationBuilder() .AddInMemoryCollection(vals); var config = builder.Build(); - var host = CreateBuilder(config).Build(); - var app = host.Start(); - Assert.NotNull(host.ApplicationServices.GetRequiredService()); - Assert.Equal("http://localhost:abc123", app.ServerFeatures.Get().Addresses.First()); + var application = CreateBuilder(config).Build(); + var app = application.Start(); + Assert.NotNull(application.Services.GetService()); + Assert.Equal("http://localhost:abc123", application.ServerFeatures.Get().Addresses.First()); } [Fact] @@ -136,10 +135,10 @@ namespace Microsoft.AspNet.Hosting var builder = new ConfigurationBuilder() .AddInMemoryCollection(vals); var config = builder.Build(); - var host = CreateBuilder(config).Build(); - var app = host.Start(); - Assert.NotNull(host.ApplicationServices.GetRequiredService()); - Assert.Equal("http://localhost:5000", app.ServerFeatures.Get().Addresses.First()); + var application = CreateBuilder(config).Build(); + var app = application.Start(); + Assert.NotNull(application.Services.GetService()); + Assert.Equal("http://localhost:5000", application.GetAddresses().First()); } [Fact] @@ -153,84 +152,85 @@ namespace Microsoft.AspNet.Hosting var builder = new ConfigurationBuilder() .AddInMemoryCollection(vals); var config = builder.Build(); - var host = CreateBuilder(config).Build(); - var app = host.Start(); - var hostingEnvironment = host.ApplicationServices.GetRequiredService(); + var application = CreateBuilder(config).Build(); + var app = application.Start(); + var hostingEnvironment = application.Services.GetService(); Assert.NotNull(hostingEnvironment.Configuration); Assert.Equal("Microsoft.AspNet.Hosting.Tests", hostingEnvironment.Configuration["Server"]); } [Fact] - public void HostingEngineCanBeStarted() + public void WebApplicationCanBeStarted() { - var engine = CreateBuilder() + var app = CreateBuilder() .UseServer(this) .UseStartup("Microsoft.AspNet.Hosting.Tests") .Build() .Start(); - Assert.NotNull(engine); + Assert.NotNull(app); Assert.Equal(1, _startInstances.Count); Assert.Equal(0, _startInstances[0].DisposeCalls); - engine.Dispose(); + app.Dispose(); Assert.Equal(1, _startInstances[0].DisposeCalls); } [Fact] - public void HostingEngineDisposesServiceProvider() + public void WebApplicationDisposesServiceProvider() { - var engine = CreateBuilder() + var application = CreateBuilder() .UseServer(this) - .UseServices(s => + .ConfigureServices(s => { s.AddTransient(); s.AddSingleton(); }) .UseStartup("Microsoft.AspNet.Hosting.Tests") - .Build() - .Start(); + .Build(); - var singleton = (FakeService)engine.Services.GetService(); - var transient = (FakeService)engine.Services.GetService(); + var app = application.Start(); + + var singleton = (FakeService)application.Services.GetService(); + var transient = (FakeService)application.Services.GetService(); Assert.False(singleton.Disposed); Assert.False(transient.Disposed); - engine.Dispose(); + app.Dispose(); Assert.True(singleton.Disposed); Assert.True(transient.Disposed); } [Fact] - public void HostingEngineNotifiesApplicationStarted() + public void WebApplicationNotifiesApplicationStarted() { - var host = CreateBuilder() + var application = CreateBuilder() .UseServer(this) .Build(); - var applicationLifetime = host.ApplicationServices.GetRequiredService(); + var applicationLifetime = application.Services.GetService(); Assert.False(applicationLifetime.ApplicationStarted.IsCancellationRequested); - using (host.Start()) + using (application.Start()) { Assert.True(applicationLifetime.ApplicationStarted.IsCancellationRequested); } } [Fact] - public void HostingEngineInjectsHostingEnvironment() + public void WebApplicationInjectsHostingEnvironment() { - var engine = CreateBuilder() + var application = CreateBuilder() .UseServer(this) .UseStartup("Microsoft.AspNet.Hosting.Tests") .UseEnvironment("WithHostingEnvironment") .Build(); - using (var server = engine.Start()) + using (application.Start()) { - var env = engine.ApplicationServices.GetRequiredService(); + var env = application.Services.GetService(); Assert.Equal("Changed", env.EnvironmentName); } } @@ -238,26 +238,29 @@ namespace Microsoft.AspNet.Hosting [Fact] public void CanReplaceStartupLoader() { - var engine = CreateBuilder().UseServices(services => services.AddTransient()) + var builder = CreateBuilder() + .ConfigureServices(services => + { + services.AddTransient(); + }) .UseServer(this) - .UseStartup("Microsoft.AspNet.Hosting.Tests") - .Build(); + .UseStartup("Microsoft.AspNet.Hosting.Tests"); - Assert.Throws(() => engine.Start()); + Assert.Throws(() => builder.Build()); } [Fact] public void CanCreateApplicationServicesWithAddedServices() { - var host = CreateBuilder().UseServices(services => services.AddOptions()).Build(); - Assert.NotNull(host.ApplicationServices.GetRequiredService>()); + var application = CreateBuilder().UseServer(this).ConfigureServices(services => services.AddOptions()).Build(); + Assert.NotNull(application.Services.GetRequiredService>()); } [Fact] public void EnvDefaultsToProductionIfNoConfig() { - var engine = CreateBuilder().Build(); - var env = engine.ApplicationServices.GetRequiredService(); + var application = CreateBuilder().UseServer(this).Build(); + var env = application.Services.GetService(); Assert.Equal(EnvironmentName.Production, env.EnvironmentName); } @@ -266,7 +269,7 @@ namespace Microsoft.AspNet.Hosting { var vals = new Dictionary { - // Old key is actualy ASPNET_ENV but WebHostConfiguration expects environment + // Old key is actualy ASPNET_ENV but WebApplicationConfiguration expects environment // variable names stripped from ASPNET_ prefix so using just ENV here { "ENV", "Staging" } }; @@ -275,8 +278,8 @@ namespace Microsoft.AspNet.Hosting .AddInMemoryCollection(vals); var config = builder.Build(); - var engine = CreateBuilder(config).Build(); - var env = engine.ApplicationServices.GetRequiredService(); + var application = CreateBuilder(config).UseServer(this).Build(); + var env = application.Services.GetService(); Assert.Equal("Staging", env.EnvironmentName); } @@ -292,8 +295,8 @@ namespace Microsoft.AspNet.Hosting .AddInMemoryCollection(vals); var config = builder.Build(); - var engine = CreateBuilder(config).Build(); - var env = engine.ApplicationServices.GetRequiredService(); + var application = CreateBuilder(config).UseServer(this).Build(); + var env = application.Services.GetService(); Assert.Equal("Staging", env.EnvironmentName); } @@ -309,8 +312,8 @@ namespace Microsoft.AspNet.Hosting .AddInMemoryCollection(vals); var config = builder.Build(); - var engine = CreateBuilder(config).UseServer(this).Build(); - var env = engine.ApplicationServices.GetRequiredService(); + var application = CreateBuilder(config).UseServer(this).Build(); + var env = application.Services.GetService(); Assert.Equal(Path.GetFullPath("testroot"), env.WebRootPath); Assert.True(env.WebRootFileProvider.GetFileInfo("TextFile.txt").Exists); } @@ -318,10 +321,10 @@ namespace Microsoft.AspNet.Hosting [Fact] public void IsEnvironment_Extension_Is_Case_Insensitive() { - var engine = CreateBuilder().UseServer(this).Build(); - using (engine.Start()) + var application = CreateBuilder().UseServer(this).Build(); + using (application.Start()) { - var env = engine.ApplicationServices.GetRequiredService(); + var env = application.Services.GetRequiredService(); Assert.True(env.IsEnvironment(EnvironmentName.Production)); Assert.True(env.IsEnvironment("producTion")); } @@ -349,7 +352,7 @@ namespace Microsoft.AspNet.Hosting } [Fact] - public void HostingEngine_CreatesDefaultRequestIdentifierFeature_IfNotPresent() + public void WebApplication_CreatesDefaultRequestIdentifierFeature_IfNotPresent() { // Arrange HttpContext httpContext = null; @@ -358,10 +361,10 @@ namespace Microsoft.AspNet.Hosting httpContext = innerHttpContext; return Task.FromResult(0); }); - var hostingEngine = CreateHostingEngine(requestDelegate); + var application = CreateApplication(requestDelegate); // Act - var disposable = hostingEngine.Start(); + var disposable = application.Start(); // Assert Assert.NotNull(httpContext); @@ -371,7 +374,7 @@ namespace Microsoft.AspNet.Hosting } [Fact] - public void HostingEngine_DoesNot_CreateDefaultRequestIdentifierFeature_IfPresent() + public void WebApplication_DoesNot_CreateDefaultRequestIdentifierFeature_IfPresent() { // Arrange HttpContext httpContext = null; @@ -382,10 +385,10 @@ namespace Microsoft.AspNet.Hosting }); var requestIdentifierFeature = new StubHttpRequestIdentifierFeature(); _featuresSupportedByThisHost[typeof(IHttpRequestIdentifierFeature)] = requestIdentifierFeature; - var hostingEngine = CreateHostingEngine(requestDelegate); + var application = CreateApplication(requestDelegate); // Act - var disposable = hostingEngine.Start(); + var disposable = application.Start(); // Assert Assert.NotNull(httpContext); @@ -393,16 +396,16 @@ namespace Microsoft.AspNet.Hosting } [Fact] - public void HostingEngine_InvokesConfigureMethodsOnlyOnce() + public void WebApplication_InvokesConfigureMethodsOnlyOnce() { - var engine = CreateBuilder() + var application = CreateBuilder() .UseServer(this) .UseStartup() .Build(); - using (engine.Start()) + using (application.Start()) { - var services = engine.ApplicationServices; - var services2 = engine.ApplicationServices; + var services = application.Services; + var services2 = application.Services; Assert.Equal(1, CountStartup.ConfigureCount); Assert.Equal(1, CountStartup.ConfigureServicesCount); } @@ -425,13 +428,13 @@ namespace Microsoft.AspNet.Hosting } [Fact] - public void HostingEngine_ThrowsForBadConfigureServiceSignature() + public void WebApplication_ThrowsForBadConfigureServiceSignature() { - var engine = CreateBuilder() + var builder = CreateBuilder() .UseServer(this) - .UseStartup() - .Build(); - var ex = Assert.Throws(() => engine.Start()); + .UseStartup(); + + var ex = Assert.Throws(() => builder.Build()); Assert.True(ex.Message.Contains("ConfigureServices")); } @@ -441,27 +444,26 @@ namespace Microsoft.AspNet.Hosting public void Configure(IApplicationBuilder app) { } } - private IHostingEngine CreateHostingEngine(RequestDelegate requestDelegate) + private IWebApplication CreateApplication(RequestDelegate requestDelegate) { - var host = CreateBuilder() + var builder = CreateBuilder() .UseServer(this) - .UseStartup( + .Configure( appBuilder => { appBuilder.ApplicationServices.GetRequiredService().AddProvider(new AllMessagesAreNeeded()); appBuilder.Run(requestDelegate); - }, - configureServices => configureServices.BuildServiceProvider()); - return host.Build(); + }); + return builder.Build(); } private void RunMapPath(string virtualPath, string expectedSuffix) { - var engine = CreateBuilder().UseServer(this).Build(); + var application = CreateBuilder().UseServer(this).Build(); - using (engine.Start()) + using (application.Start()) { - var env = engine.ApplicationServices.GetRequiredService(); + var env = application.Services.GetRequiredService(); // MapPath requires webroot to be set, we don't care // about file provider so just set it here env.WebRootPath = "."; @@ -471,9 +473,9 @@ namespace Microsoft.AspNet.Hosting } } - private WebHostBuilder CreateBuilder(IConfiguration config = null) + private WebApplicationBuilder CreateBuilder(IConfiguration config = null) { - return new WebHostBuilder(config ?? new ConfigurationBuilder().Build()); + return new WebApplicationBuilder().UseConfiguration(config ?? new ConfigurationBuilder().Build()).UseStartup("Microsoft.AspNet.Hosting.Tests"); } public void Start(IHttpApplication application) diff --git a/test/Microsoft.AspNet.TestHost.Tests/RequestBuilderTests.cs b/test/Microsoft.AspNet.TestHost.Tests/RequestBuilderTests.cs index bcc4c79707..a47cf1f00c 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/RequestBuilderTests.cs +++ b/test/Microsoft.AspNet.TestHost.Tests/RequestBuilderTests.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. 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.Testing.xunit; using Xunit; @@ -13,7 +14,8 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono)] public void AddRequestHeader() { - var server = TestServer.Create(app => { }); + var builder = new WebApplicationBuilder().Configure(app => { }); + var server = new TestServer(builder); server.CreateRequest("/") .AddHeader("Host", "MyHost:90") .And(request => @@ -25,7 +27,8 @@ namespace Microsoft.AspNet.TestHost [Fact] public void AddContentHeaders() { - var server = TestServer.Create(app => { }); + var builder = new WebApplicationBuilder().Configure(app => { }); + var server = new TestServer(builder); server.CreateRequest("/") .AddHeader("Content-Type", "Test/Value") .And(request => diff --git a/test/Microsoft.AspNet.TestHost.Tests/TestClientTests.cs b/test/Microsoft.AspNet.TestHost.Tests/TestClientTests.cs index 61e0f2b9d7..a453aaa564 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/TestClientTests.cs +++ b/test/Microsoft.AspNet.TestHost.Tests/TestClientTests.cs @@ -10,6 +10,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; using Microsoft.AspNet.Testing.xunit; using Xunit; @@ -22,7 +23,7 @@ namespace Microsoft.AspNet.TestHost public TestClientTests() { - _server = TestServer.Create(app => app.Run(ctx => Task.FromResult(0))); + _server = new TestServer(new WebApplicationBuilder().Configure(app => app.Run(ctx => Task.FromResult(0)))); } [ConditionalFact] @@ -33,7 +34,8 @@ namespace Microsoft.AspNet.TestHost var expected = "GET Response"; RequestDelegate appDelegate = ctx => ctx.Response.WriteAsync(expected); - var server = TestServer.Create(app => app.Run(appDelegate)); + var builder = new WebApplicationBuilder().Configure(app => app.Run(appDelegate)); + var server = new TestServer(builder); var client = server.CreateClient(); // Act @@ -55,7 +57,8 @@ namespace Microsoft.AspNet.TestHost Assert.Equal("/", ctx.Request.Path.Value); return ctx.Response.WriteAsync(expected); }; - var server = TestServer.Create(app => app.Run(appDelegate)); + var builder = new WebApplicationBuilder().Configure(app => app.Run(appDelegate)); + var server = new TestServer(builder); var client = server.CreateClient(); // Act @@ -77,7 +80,8 @@ namespace Microsoft.AspNet.TestHost Assert.Equal("/", ctx.Request.Path.Value); return ctx.Response.WriteAsync(expected); }; - var server = TestServer.Create(app => app.Run(appDelegate)); + var builder = new WebApplicationBuilder().Configure(app => app.Run(appDelegate)); + var server = new TestServer(builder); var client = server.CreateClient(); // Act @@ -94,7 +98,8 @@ namespace Microsoft.AspNet.TestHost // Arrange RequestDelegate appDelegate = ctx => ctx.Response.WriteAsync(new StreamReader(ctx.Request.Body).ReadToEnd() + " PUT Response"); - var server = TestServer.Create(app => app.Run(appDelegate)); + var builder = new WebApplicationBuilder().Configure(app => app.Run(appDelegate)); + var server = new TestServer(builder); var client = server.CreateClient(); // Act @@ -112,7 +117,8 @@ 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(app => app.Run(appDelegate)); + var builder = new WebApplicationBuilder().Configure(app => app.Run(appDelegate)); + var server = new TestServer(builder); var client = server.CreateClient(); // Act @@ -150,10 +156,11 @@ namespace Microsoft.AspNet.TestHost } } }; - var server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(appDelegate); }); + var server = new TestServer(builder); // Act var client = server.CreateWebSocketClient(); @@ -198,10 +205,11 @@ namespace Microsoft.AspNet.TestHost websocket.Dispose(); } }; - var server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(appDelegate); }); + var server = new TestServer(builder); // Act var client = server.CreateWebSocketClient(); @@ -231,10 +239,11 @@ namespace Microsoft.AspNet.TestHost } } }; - var server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(appDelegate); }); + var server = new TestServer(builder); // Act var client = server.CreateWebSocketClient(); @@ -279,7 +288,8 @@ namespace Microsoft.AspNet.TestHost }; // Act - var server = TestServer.Create(app => app.Run(appDelegate)); + var builder = new WebApplicationBuilder().Configure(app => app.Run(appDelegate)); + var server = new TestServer(builder); var client = server.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:12345"); var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); @@ -310,7 +320,8 @@ namespace Microsoft.AspNet.TestHost }; // Act - var server = TestServer.Create(app => app.Run(appDelegate)); + var builder = new WebApplicationBuilder().Configure(app => app.Run(appDelegate)); + var server = new TestServer(builder); var client = server.CreateClient(); var cts = new CancellationTokenSource(); cts.CancelAfter(500); diff --git a/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs b/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs index b923a10826..92fdc85fb8 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs +++ b/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs @@ -28,20 +28,21 @@ namespace Microsoft.AspNet.TestHost { // Arrange // Act & Assert (Does not throw) - TestServer.Create(app => { }); + new TestServer(new WebApplicationBuilder().Configure(app => { })); } [ConditionalFact] [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task RequestServicesAutoCreated() { - var server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(context => { return context.Response.WriteAsync("RequestServices:" + (context.RequestServices != null)); }); }); + var server = new TestServer(builder); string result = await server.CreateClient().GetStringAsync("/path"); Assert.Equal("RequestServices:True", result); @@ -71,7 +72,8 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task CustomServiceProviderSetsApplicationServices() { - var server = new TestServer(TestServer.CreateBuilder().UseStartup()); + var builder = new WebApplicationBuilder().UseStartup(); + var server = new TestServer(builder); string result = await server.CreateClient().GetStringAsync("/path"); Assert.Equal("ApplicationServicesEqual:True", result); } @@ -113,15 +115,20 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task ExistingRequestServicesWillNotBeReplaced() { - var server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(context => { var service = context.RequestServices.GetService(); return context.Response.WriteAsync("Found:" + (service != null)); }); - }, - services => services.AddTransient()); + }) + .ConfigureServices(services => + { + services.AddTransient(); + }); + var server = new TestServer(builder); + string result = await server.CreateClient().GetStringAsync("/path"); Assert.Equal("Found:True", result); } @@ -130,19 +137,21 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task CanSetCustomServiceProvider() { - var server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(context => { context.RequestServices = new ServiceCollection() .AddTransient() .BuildServiceProvider(); - + var s = context.RequestServices.GetRequiredService(); return context.Response.WriteAsync("Success"); }); }); + var server = new TestServer(builder); + string result = await server.CreateClient().GetStringAsync("/path"); Assert.Equal("Success", result); } @@ -178,15 +187,20 @@ namespace Microsoft.AspNet.TestHost public async Task ExistingServiceProviderFeatureWillNotBeReplaced() { var appServices = new ServiceCollection().BuildServiceProvider(); - var server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(context => { Assert.Equal(appServices, context.RequestServices); return context.Response.WriteAsync("Success"); }); - }, - services => services.AddSingleton(new ReplaceServiceProvidersFeatureFilter(appServices, appServices))); + }) + .ConfigureServices(services => + { + services.AddSingleton(new ReplaceServiceProvidersFeatureFilter(appServices, appServices)); + }); + var server = new TestServer(builder); + var result = await server.CreateClient().GetStringAsync("/path"); Assert.Equal("Success", result); } @@ -215,15 +229,20 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task WillReplaceServiceProviderFeatureWithNullRequestServices() { - var server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(context => { Assert.NotNull(context.RequestServices); return context.Response.WriteAsync("Success"); }); - }, - services => services.AddTransient()); + }) + .ConfigureServices(services => + { + services.AddTransient(); + }); + var server = new TestServer(builder); + var result = await server.CreateClient().GetStringAsync("/path"); Assert.Equal("Success", result); } @@ -232,7 +251,7 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task CanAccessLogger() { - var server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(context => { @@ -240,6 +259,7 @@ namespace Microsoft.AspNet.TestHost return context.Response.WriteAsync("FoundLogger:" + (logger != null)); }); }); + var server = new TestServer(builder); string result = await server.CreateClient().GetStringAsync("/path"); Assert.Equal("FoundLogger:True", result); @@ -249,18 +269,19 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task CanAccessHttpContext() { - Action configureServices = services => - { - services.AddSingleton(); - }; - TestServer server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(context => { var accessor = app.ApplicationServices.GetRequiredService(); - return context.Response.WriteAsync("HasContext:"+(accessor.HttpContext != null)); + return context.Response.WriteAsync("HasContext:" + (accessor.HttpContext != null)); }); - }, configureServices); + }) + .ConfigureServices(services => + { + services.AddSingleton(); + }); + var server = new TestServer(builder); string result = await server.CreateClient().GetStringAsync("/path"); Assert.Equal("HasContext:True", result); @@ -280,19 +301,20 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task CanAddNewHostServices() { - Action configureServices = services => - { - services.AddSingleton(); - services.AddSingleton(); - }; - TestServer server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(context => { var accessor = app.ApplicationServices.GetRequiredService(); return context.Response.WriteAsync("HasContext:" + (accessor.Accessor.HttpContext != null)); }); - }, configureServices); + }) + .ConfigureServices(services => + { + services.AddSingleton(); + services.AddSingleton(); + }); + var server = new TestServer(builder); string result = await server.CreateClient().GetStringAsync("/path"); Assert.Equal("HasContext:True", result); @@ -302,13 +324,14 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task CreateInvokesApp() { - TestServer server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(context => { return context.Response.WriteAsync("CreateInvokesApp"); }); }); + var server = new TestServer(builder); string result = await server.CreateClient().GetStringAsync("/path"); Assert.Equal("CreateInvokesApp", result); @@ -318,7 +341,7 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task DisposeStreamIgnored() { - TestServer server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(async context => { @@ -326,6 +349,7 @@ namespace Microsoft.AspNet.TestHost context.Response.Body.Dispose(); }); }); + var server = new TestServer(builder); HttpResponseMessage result = await server.CreateClient().GetAsync("/"); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -336,7 +360,7 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task DisposedServerThrows() { - TestServer server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { app.Run(async context => { @@ -344,6 +368,7 @@ namespace Microsoft.AspNet.TestHost context.Response.Body.Dispose(); }); }); + var server = new TestServer(builder); HttpResponseMessage result = await server.CreateClient().GetAsync("/"); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -355,15 +380,17 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task CancelAborts() { - TestServer server = TestServer.Create(app => - { - app.Run(context => - { - TaskCompletionSource tcs = new TaskCompletionSource(); - tcs.SetCanceled(); - return tcs.Task; - }); - }); + var builder = new WebApplicationBuilder() + .Configure(app => + { + app.Run(context => + { + TaskCompletionSource tcs = new TaskCompletionSource(); + tcs.SetCanceled(); + return tcs.Task; + }); + }); + var server = new TestServer(builder); await Assert.ThrowsAsync(async () => { string result = await server.CreateClient().GetStringAsync("/path"); }); } @@ -372,7 +399,9 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task CanCreateViaStartupType() { - TestServer server = new TestServer(TestServer.CreateBuilder().UseStartup()); + var builder = new WebApplicationBuilder() + .UseStartup(); + var server = new TestServer(builder); HttpResponseMessage result = await server.CreateClient().GetAsync("/"); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal("FoundService:True", await result.Content.ReadAsStringAsync()); @@ -382,9 +411,11 @@ namespace Microsoft.AspNet.TestHost [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Hangs randomly (issue #507)")] public async Task CanCreateViaStartupTypeAndSpecifyEnv() { - TestServer server = new TestServer(TestServer.CreateBuilder() - .UseStartup() - .UseEnvironment("Foo")); + var builder = new WebApplicationBuilder() + .UseStartup() + .UseEnvironment("Foo"); + var server = new TestServer(builder); + HttpResponseMessage result = await server.CreateClient().GetAsync("/"); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal("FoundFoo:False", await result.Content.ReadAsStringAsync()); @@ -395,14 +426,18 @@ namespace Microsoft.AspNet.TestHost public async Task BeginEndDiagnosticAvailable() { DiagnosticListener diagnosticListener = null; - var server = TestServer.Create(app => - { - diagnosticListener = app.ApplicationServices.GetRequiredService(); - app.Run(context => - { - return context.Response.WriteAsync("Hello World"); - }); - }); + + var builder = new WebApplicationBuilder() + .Configure(app => + { + diagnosticListener = app.ApplicationServices.GetRequiredService(); + app.Run(context => + { + return context.Response.WriteAsync("Hello World"); + }); + }); + var server = new TestServer(builder); + var listener = new TestDiagnosticListener(); diagnosticListener.SubscribeWithAdapter(listener); var result = await server.CreateClient().GetStringAsync("/path"); @@ -421,7 +456,7 @@ namespace Microsoft.AspNet.TestHost public async Task ExceptionDiagnosticAvailable() { DiagnosticListener diagnosticListener = null; - var server = TestServer.Create(app => + var builder = new WebApplicationBuilder().Configure(app => { diagnosticListener = app.ApplicationServices.GetRequiredService(); app.Run(context => @@ -429,10 +464,12 @@ namespace Microsoft.AspNet.TestHost throw new Exception("Test exception"); }); }); + var server = new TestServer(builder); + var listener = new TestDiagnosticListener(); diagnosticListener.SubscribeWithAdapter(listener); await Assert.ThrowsAsync(() => server.CreateClient().GetAsync("/path")); - + // This ensures that all diagnostics are completely written to the diagnostic listener Thread.Sleep(1000);