API changes to Hosting and TestServer #525

This commit is contained in:
David Fowler 2015-12-11 13:03:43 -08:00 committed by John Luo
parent 35f9de5ae1
commit 1c70ff4d13
32 changed files with 948 additions and 709 deletions

View File

@ -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

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>485b6745-7648-400a-a969-f68fcf194e46</ProjectGuid>
<RootNamespace>SampleStartups</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<ItemGroup>
<DnxInvisibleContent Include="bower.json" />
<DnxInvisibleContent Include=".bowerrc" />
<DnxInvisibleContent Include="package.json" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -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<StartupBlockingOnStart>()
.Build();
using (application.Start())
{
Console.ReadLine();
}
}
}
}

View File

@ -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<StartupConfigureAddresses>()
.Build();
var addresses = application.GetAddresses();
addresses.Add("http://localhost:5000");
addresses.Add("http://localhost:5001");
application.Run();
}
}
}

View File

@ -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<StartupExternallyControlled>().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);
}
}
}

View File

@ -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<IMyCustomService, MyCustomService>();
})
.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();
}
}
}

View File

@ -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<StartupHelloWorld>()
.Build();
application.Run();
}
}
}

View File

@ -0,0 +1,10 @@
{
"version": "1.0.0-*",
"dependencies": {
"Microsoft.AspNet.Hosting": "1.0.0-*"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
}
}

View File

@ -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
{
/// <summary>
/// Represents a configured web application
/// </summary>
public interface IWebApplication
{
/// <summary>
/// The <see cref="IFeatureCollection"/> exposed by the configured server.
/// </summary>
IFeatureCollection ServerFeatures { get; }
/// <summary>
/// The <see cref="IServiceProvider"/> for the application.
/// </summary>
IServiceProvider Services { get; }
/// <summary>
/// Starts listening on the configured addresses.
/// </summary>
/// <returns></returns>
IDisposable Start();
}
}

View File

@ -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();
}
}
}

View File

@ -4,7 +4,7 @@
using System;
using System.Threading;
namespace Microsoft.AspNet.Hosting
namespace Microsoft.AspNet.Hosting.Internal
{
/// <summary>
/// Allows consumers to perform cleanup during a graceful shutdown.

View File

@ -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
{

View File

@ -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)
{

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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<IApplicationLifetime>(_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<ILogger<HostingEngine>>();
public void Initialize()
{
if (_application == null)
{
_application = BuildApplication();
}
}
public virtual IDisposable Start()
{
Initialize();
var logger = _applicationServices.GetRequiredService<ILogger<WebApplication>>();
var diagnosticSource = _applicationServices.GetRequiredService<DiagnosticSource>();
var httpContextFactory = _applicationServices.GetRequiredService<IHttpContextFactory>();
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<ILogger<HostingEngine>>();
var logger = _applicationServices.GetRequiredService<ILogger<WebApplication>>();
logger.ApplicationError(ex);
// Generate an HTML error page.

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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<TStartup>()
{
Run(typeof(TStartup), null);
}
public static void Run<TStartup>(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<IHostingEnvironment>();
Console.WriteLine("Hosting environment: " + hostingEnv.EnvironmentName);
var serverAddresses = app.ServerFeatures.Get<IServerAddressesFeature>();
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<IApplicationLifetime>();
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();
}
}
}

View File

@ -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<IServiceCollection> _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<TStartup>() where TStartup : class
{
return UseStartup(typeof(TStartup));
}
public WebApplicationBuilder ConfigureServices(Action<IServiceCollection> configureServices)
{
_configureServices = configureServices;
return this;
}
public WebApplicationBuilder Configure(Action<IApplicationBuilder> configureApp)
{
if (configureApp == null)
{
throw new ArgumentNullException(nameof(configureApp));
}
_startup = new StartupMethods(configureApp);
return this;
}
public WebApplicationBuilder ConfigureLogging(Action<ILoggerFactory> configureLogging)
{
configureLogging(_loggerFactory);
return this;
}
public IWebApplication Build()
{
var hostingServices = BuildHostingServices();
var hostingContainer = hostingServices.BuildServiceProvider();
var appEnvironment = hostingContainer.GetRequiredService<IApplicationEnvironment>();
var startupLoader = hostingContainer.GetRequiredService<IStartupLoader>();
_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<IStartupFilter, AutoRequestServicesStartupFilter>();
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<IApplicationEnvironment>();
var startupLoader = hostingContainer.GetRequiredService<IStartupLoader>();
_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<IServiceCollection> 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<TStartup>() where TStartup : class
{
return UseStartup(typeof(TStartup));
}
public WebHostBuilder UseStartup(Action<IApplicationBuilder> configureApp)
{
if (configureApp == null)
{
throw new ArgumentNullException(nameof(configureApp));
}
return UseStartup(configureApp, configureServices: null);
}
public WebHostBuilder UseStartup(Action<IApplicationBuilder> configureApp, Func<IServiceCollection, IServiceProvider> configureServices)
{
if (configureApp == null)
{
throw new ArgumentNullException(nameof(configureApp));
}
_startup = new StartupMethods(configureApp, configureServices);
return this;
}
public WebHostBuilder UseStartup(Action<IApplicationBuilder> configureApp, Action<IServiceCollection> configureServices)
{
if (configureApp == null)
{
throw new ArgumentNullException(nameof(configureApp));
}
_startup = new StartupMethods(configureApp,
services =>
{
if (configureServices != null)
{
configureServices(services);
}
return services.BuildServiceProvider();
});
return this;
}
}
}

View File

@ -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();
}
}
}

View File

@ -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
{
/// <summary>
/// Retruns the server addresses the web application is going to listen on.
/// </summary>
/// <param name="application"></param>
/// <returns>An <see cref="ICollection{string}"> which the addresses the server will listen to</returns>
public static ICollection<string> GetAddresses(this IWebApplication application)
{
return application.ServerFeatures.Get<IServerAddressesFeature>()?.Addresses;
}
/// <summary>
/// Runs a web application and block the calling thread until host shutdown.
/// </summary>
/// <param name="application"></param>
public static void Run(this IWebApplication application)
{
using (application.Start())
{
var hostingEnvironment = application.Services.GetService<IHostingEnvironment>();
var applicationLifetime = application.Services.GetService<IApplicationLifetime>();
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();
}
}
}
}

View File

@ -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; }
}
}

View File

@ -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<Context> _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<IApplicationBuilder> configureApp)
{
return Create(config: null, configureApp: configureApp, configureServices: null);
}
public static TestServer Create(Action<IApplicationBuilder> configureApp, Action<IServiceCollection> configureServices)
{
return Create(config: null, configureApp: configureApp, configureServices: configureServices);
}
public static TestServer Create(Action<IApplicationBuilder> configureApp, Func<IServiceCollection, IServiceProvider> configureServices)
{
return new TestServer(CreateBuilder(config: null, configureApp: configureApp, configureServices: configureServices, configureHostServices: null));
}
public static TestServer Create(Action<IApplicationBuilder> configureApp, Func<IServiceCollection, IServiceProvider> configureServices, Action<IServiceCollection> configureHostServices)
{
return new TestServer(CreateBuilder(config: null, configureApp: configureApp, configureServices: configureServices, configureHostServices: configureHostServices));
}
public static TestServer Create(IConfiguration config, Action<IApplicationBuilder> configureApp, Action<IServiceCollection> configureServices)
{
return new TestServer(CreateBuilder(config, configureApp, configureServices));
}
public static WebHostBuilder CreateBuilder(IConfiguration config, Action<IApplicationBuilder> configureApp, Action<IServiceCollection> configureServices)
{
return CreateBuilder(config, configureApp,
s =>
{
if (configureServices != null)
{
configureServices(s);
}
return s.BuildServiceProvider();
}, null);
}
public static WebHostBuilder CreateBuilder(IConfiguration config, Action<IApplicationBuilder> configureApp, Func<IServiceCollection, IServiceProvider> configureServices)
{
return CreateBuilder(config, configureApp, configureServices, null);
}
public static WebHostBuilder CreateBuilder(IConfiguration config, Action<IApplicationBuilder> configureApp, Func<IServiceCollection, IServiceProvider> configureServices, Action<IServiceCollection> 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<TContext> : IHttpApplication<TContext>
{
IHttpApplication<TContext> _application;
Action _preProcessRequestAsync;
private readonly IHttpApplication<TContext> _application;
private readonly Action _preProcessRequestAsync;
public ApplicationWrapper(IHttpApplication<TContext> application, Action preProcessRequestAsync)
{

View File

@ -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<PhysicalFileProvider>(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<PhysicalFileProvider>(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<NullFileProvider>(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<InvalidOperationException>(() => env.MapPath("file.txt"));
}

View File

@ -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;

View File

@ -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<StartupStaticCtorThrows>().Build();
using (engine.Start())
var application = builder.UseServer(server).UseStartup<StartupStaticCtorThrows>().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<StartupCtorThrows>().Build();
using (engine.Start())
var application = builder.UseServer(server).UseStartup<StartupCtorThrows>().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<StartupThrowTypeLoadException>().Build();
using (engine.Start())
var application = builder.UseServer(server).UseStartup<StartupThrowTypeLoadException>().Build();
using (application.Start())
{
await AssertResponseContains(server.RequestDelegate, "Message from the LoaderException</span>");
}
@ -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<StartupCtorThrows>().Build();
using (engine.Start())
var application = builder.UseServer(server).UseStartup<StartupCtorThrows>().Build();
using (application.Start())
{
var service = engine.ApplicationServices.GetServices<IApplicationLifetime>();
var service = application.Services.GetServices<IApplicationLifetime>();
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<StartupConfigureServicesThrows>().Build();
using (engine.Start())
var application = builder.UseServer(server).UseStartup<StartupConfigureServicesThrows>().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<StartupConfigureServicesThrows>().Build();
using (engine.Start())
var application = builder.UseServer(server).UseStartup<StartupConfigureServicesThrows>().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<IHostingEnvironment>().EnvironmentName);
Assert.Equal(expected, application.Services.GetService<IHostingEnvironment>().EnvironmentName);
}
private WebHostBuilder CreateWebHostBuilder()
private WebApplicationBuilder CreateWebApplicationBuilder()
{
var vals = new Dictionary<string, string>
{
{ "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)

View File

@ -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<string, string>() { { "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<string, string>() { { "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);
}

View File

@ -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<StartInstance> _startInstances = new List<StartInstance>();
private IFeatureCollection _featuresSupportedByThisHost = NewFeatureCollection();
@ -63,7 +62,7 @@ namespace Microsoft.AspNet.Hosting
}
[Fact]
public void HostingEngineThrowsWithNoServer()
public void WebApplicationThrowsWithNoServer()
{
var ex = Assert.Throws<InvalidOperationException>(() => 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<IHostingEnvironment>());
var application = CreateBuilder(config).Build();
application.Start();
Assert.NotNull(application.Services.GetService<IHostingEnvironment>());
}
[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<IHostingEnvironment>());
var application = CreateBuilder(config).Build();
application.Start();
Assert.NotNull(application.Services.GetService<IHostingEnvironment>());
}
[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<IHostingEnvironment>());
Assert.Equal("http://localhost:abc123", app.ServerFeatures.Get<IServerAddressesFeature>().Addresses.First());
var application = CreateBuilder(config).Build();
var app = application.Start();
Assert.NotNull(application.Services.GetService<IHostingEnvironment>());
Assert.Equal("http://localhost:abc123", application.ServerFeatures.Get<IServerAddressesFeature>().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<IHostingEnvironment>());
Assert.Equal("http://localhost:5000", app.ServerFeatures.Get<IServerAddressesFeature>().Addresses.First());
var application = CreateBuilder(config).Build();
var app = application.Start();
Assert.NotNull(application.Services.GetService<IHostingEnvironment>());
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<IHostingEnvironment>();
var application = CreateBuilder(config).Build();
var app = application.Start();
var hostingEnvironment = application.Services.GetService<IHostingEnvironment>();
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<IFakeService, FakeService>();
s.AddSingleton<IFakeSingletonService, FakeService>();
})
.UseStartup("Microsoft.AspNet.Hosting.Tests")
.Build()
.Start();
.Build();
var singleton = (FakeService)engine.Services.GetService<IFakeSingletonService>();
var transient = (FakeService)engine.Services.GetService<IFakeService>();
var app = application.Start();
var singleton = (FakeService)application.Services.GetService<IFakeSingletonService>();
var transient = (FakeService)application.Services.GetService<IFakeService>();
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<IApplicationLifetime>();
var applicationLifetime = application.Services.GetService<IApplicationLifetime>();
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<IHostingEnvironment>();
var env = application.Services.GetService<IHostingEnvironment>();
Assert.Equal("Changed", env.EnvironmentName);
}
}
@ -238,26 +238,29 @@ namespace Microsoft.AspNet.Hosting
[Fact]
public void CanReplaceStartupLoader()
{
var engine = CreateBuilder().UseServices(services => services.AddTransient<IStartupLoader, TestLoader>())
var builder = CreateBuilder()
.ConfigureServices(services =>
{
services.AddTransient<IStartupLoader, TestLoader>();
})
.UseServer(this)
.UseStartup("Microsoft.AspNet.Hosting.Tests")
.Build();
.UseStartup("Microsoft.AspNet.Hosting.Tests");
Assert.Throws<NotImplementedException>(() => engine.Start());
Assert.Throws<NotImplementedException>(() => builder.Build());
}
[Fact]
public void CanCreateApplicationServicesWithAddedServices()
{
var host = CreateBuilder().UseServices(services => services.AddOptions()).Build();
Assert.NotNull(host.ApplicationServices.GetRequiredService<IOptions<object>>());
var application = CreateBuilder().UseServer(this).ConfigureServices(services => services.AddOptions()).Build();
Assert.NotNull(application.Services.GetRequiredService<IOptions<object>>());
}
[Fact]
public void EnvDefaultsToProductionIfNoConfig()
{
var engine = CreateBuilder().Build();
var env = engine.ApplicationServices.GetRequiredService<IHostingEnvironment>();
var application = CreateBuilder().UseServer(this).Build();
var env = application.Services.GetService<IHostingEnvironment>();
Assert.Equal(EnvironmentName.Production, env.EnvironmentName);
}
@ -266,7 +269,7 @@ namespace Microsoft.AspNet.Hosting
{
var vals = new Dictionary<string, string>
{
// 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<IHostingEnvironment>();
var application = CreateBuilder(config).UseServer(this).Build();
var env = application.Services.GetService<IHostingEnvironment>();
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<IHostingEnvironment>();
var application = CreateBuilder(config).UseServer(this).Build();
var env = application.Services.GetService<IHostingEnvironment>();
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<IHostingEnvironment>();
var application = CreateBuilder(config).UseServer(this).Build();
var env = application.Services.GetService<IHostingEnvironment>();
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<IHostingEnvironment>();
var env = application.Services.GetRequiredService<IHostingEnvironment>();
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<CountStartup>()
.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<BadConfigureServicesStartup>()
.Build();
var ex = Assert.Throws<InvalidOperationException>(() => engine.Start());
.UseStartup<BadConfigureServicesStartup>();
var ex = Assert.Throws<InvalidOperationException>(() => 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<ILoggerFactory>().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<IHostingEnvironment>();
var env = application.Services.GetRequiredService<IHostingEnvironment>();
// 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<TContext>(IHttpApplication<TContext> application)

View File

@ -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 =>

View File

@ -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);

View File

@ -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<CustomContainerStartup>());
var builder = new WebApplicationBuilder().UseStartup<CustomContainerStartup>();
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<TestService>();
return context.Response.WriteAsync("Found:" + (service != null));
});
},
services => services.AddTransient<IStartupFilter, RequestServicesFilter>());
})
.ConfigureServices(services =>
{
services.AddTransient<IStartupFilter, RequestServicesFilter>();
});
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<TestService>()
.BuildServiceProvider();
var s = context.RequestServices.GetRequiredService<TestService>();
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<IStartupFilter>(new ReplaceServiceProvidersFeatureFilter(appServices, appServices)));
})
.ConfigureServices(services =>
{
services.AddSingleton<IStartupFilter>(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<IStartupFilter, NullServiceProvidersFeatureFilter>());
})
.ConfigureServices(services =>
{
services.AddTransient<IStartupFilter, NullServiceProvidersFeatureFilter>();
});
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<IServiceCollection> configureServices = services =>
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
};
TestServer server = TestServer.Create(app =>
var builder = new WebApplicationBuilder().Configure(app =>
{
app.Run(context =>
{
var accessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
return context.Response.WriteAsync("HasContext:"+(accessor.HttpContext != null));
return context.Response.WriteAsync("HasContext:" + (accessor.HttpContext != null));
});
}, configureServices);
})
.ConfigureServices(services =>
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
});
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<IServiceCollection> configureServices = services =>
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<ContextHolder>();
};
TestServer server = TestServer.Create(app =>
var builder = new WebApplicationBuilder().Configure(app =>
{
app.Run(context =>
{
var accessor = app.ApplicationServices.GetRequiredService<ContextHolder>();
return context.Response.WriteAsync("HasContext:" + (accessor.Accessor.HttpContext != null));
});
}, configureServices);
})
.ConfigureServices(services =>
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<ContextHolder>();
});
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<int> tcs = new TaskCompletionSource<int>();
tcs.SetCanceled();
return tcs.Task;
});
});
var builder = new WebApplicationBuilder()
.Configure(app =>
{
app.Run(context =>
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
tcs.SetCanceled();
return tcs.Task;
});
});
var server = new TestServer(builder);
await Assert.ThrowsAsync<TaskCanceledException>(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<TestStartup>());
var builder = new WebApplicationBuilder()
.UseStartup<TestStartup>();
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<TestStartup>()
.UseEnvironment("Foo"));
var builder = new WebApplicationBuilder()
.UseStartup<TestStartup>()
.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<DiagnosticListener>();
app.Run(context =>
{
return context.Response.WriteAsync("Hello World");
});
});
var builder = new WebApplicationBuilder()
.Configure(app =>
{
diagnosticListener = app.ApplicationServices.GetRequiredService<DiagnosticListener>();
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<DiagnosticListener>();
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<Exception>(() => server.CreateClient().GetAsync("/path"));
// This ensures that all diagnostics are completely written to the diagnostic listener
Thread.Sleep(1000);