#1263 Delay IServer and Startup.Configure until StartAsync

This commit is contained in:
Chris Ross (ASP.NET) 2017-11-10 16:18:51 -08:00
parent adf2f37ad2
commit cd3f58bed7
3 changed files with 32 additions and 17 deletions

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -38,7 +39,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal
private readonly AggregateException _hostingStartupErrors; private readonly AggregateException _hostingStartupErrors;
private IServiceProvider _applicationServices; private IServiceProvider _applicationServices;
private RequestDelegate _application; private ExceptionDispatchInfo _applicationServicesException;
private ILogger<WebHost> _logger; private ILogger<WebHost> _logger;
private bool _stopped; private bool _stopped;
@ -88,7 +89,6 @@ namespace Microsoft.AspNetCore.Hosting.Internal
{ {
get get
{ {
EnsureApplicationServices();
return _applicationServices; return _applicationServices;
} }
} }
@ -97,15 +97,32 @@ namespace Microsoft.AspNetCore.Hosting.Internal
{ {
get get
{ {
EnsureServer();
return Server?.Features; return Server?.Features;
} }
} }
// Called immediately after the constructor so the properties can rely on it.
public void Initialize() public void Initialize()
{ {
if (_application == null) try
{ {
_application = BuildApplication(); EnsureApplicationServices();
}
catch (Exception ex)
{
// EnsureApplicationServices may have failed due to a missing or throwing Startup class.
if (_applicationServices == null)
{
_applicationServices = _applicationServiceCollection.BuildServiceProvider();
}
if (!_options.CaptureStartupErrors)
{
throw;
}
_applicationServicesException = ExceptionDispatchInfo.Capture(ex);
} }
} }
@ -120,13 +137,13 @@ namespace Microsoft.AspNetCore.Hosting.Internal
_logger = _applicationServices.GetRequiredService<ILogger<WebHost>>(); _logger = _applicationServices.GetRequiredService<ILogger<WebHost>>();
_logger.Starting(); _logger.Starting();
Initialize(); var application = BuildApplication();
_applicationLifetime = _applicationServices.GetRequiredService<IApplicationLifetime>() as ApplicationLifetime; _applicationLifetime = _applicationServices.GetRequiredService<IApplicationLifetime>() as ApplicationLifetime;
_hostedServiceExecutor = _applicationServices.GetRequiredService<HostedServiceExecutor>(); _hostedServiceExecutor = _applicationServices.GetRequiredService<HostedServiceExecutor>();
var diagnosticSource = _applicationServices.GetRequiredService<DiagnosticListener>(); var diagnosticSource = _applicationServices.GetRequiredService<DiagnosticListener>();
var httpContextFactory = _applicationServices.GetRequiredService<IHttpContextFactory>(); var httpContextFactory = _applicationServices.GetRequiredService<IHttpContextFactory>();
var hostingApp = new HostingApplication(_application, _logger, diagnosticSource, httpContextFactory); var hostingApp = new HostingApplication(application, _logger, diagnosticSource, httpContextFactory);
await Server.StartAsync(hostingApp, cancellationToken).ConfigureAwait(false); await Server.StartAsync(hostingApp, cancellationToken).ConfigureAwait(false);
// Fire IApplicationLifetime.Started // Fire IApplicationLifetime.Started
@ -183,7 +200,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal
{ {
try try
{ {
EnsureApplicationServices(); _applicationServicesException?.Throw();
EnsureServer(); EnsureServer();
var builderFactory = _applicationServices.GetRequiredService<IApplicationBuilderFactory>(); var builderFactory = _applicationServices.GetRequiredService<IApplicationBuilderFactory>();
@ -203,12 +220,6 @@ namespace Microsoft.AspNetCore.Hosting.Internal
} }
catch (Exception ex) catch (Exception ex)
{ {
// EnsureApplicationServices may have failed due to a missing or throwing Startup class.
if (_applicationServices == null)
{
_applicationServices = _applicationServiceCollection.BuildServiceProvider();
}
if (!_options.SuppressStatusMessages) if (!_options.SuppressStatusMessages)
{ {
// Write errors to standard out so they can be retrieved when not in development mode. // Write errors to standard out so they can be retrieved when not in development mode.

View File

@ -182,7 +182,7 @@ namespace Microsoft.AspNetCore.Hosting
options.ValidateScopes = true; options.ValidateScopes = true;
}); });
Assert.Throws<InvalidOperationException>(() => hostBuilder.Build()); Assert.Throws<InvalidOperationException>(() => hostBuilder.Build().Start());
} }
[Fact] [Fact]
@ -208,7 +208,7 @@ namespace Microsoft.AspNetCore.Hosting
options.ValidateScopes = true; options.ValidateScopes = true;
}); });
Assert.Throws<InvalidOperationException>(() => hostBuilder.Build()); Assert.Throws<InvalidOperationException>(() => hostBuilder.Build().Start());
Assert.True(configurationCallbackCalled); Assert.True(configurationCallbackCalled);
} }
@ -784,8 +784,9 @@ namespace Microsoft.AspNetCore.Hosting
}) })
.UseServer(new TestServer()); .UseServer(new TestServer());
using (builder.Build()) using (var host = builder.Build())
{ {
host.Start();
Assert.NotNull(startup.ServiceADescriptor); Assert.NotNull(startup.ServiceADescriptor);
Assert.NotNull(startup.ServiceA); Assert.NotNull(startup.ServiceA);
} }
@ -823,6 +824,7 @@ namespace Microsoft.AspNetCore.Hosting
using (var host = (WebHost)builder.Build()) using (var host = (WebHost)builder.Build())
{ {
host.Start();
var sink = host.Services.GetRequiredService<ITestSink>(); var sink = host.Services.GetRequiredService<ITestSink>();
Assert.Contains(sink.Writes, w => w.State.ToString() == "From startup"); Assert.Contains(sink.Writes, w => w.State.ToString() == "From startup");
} }
@ -920,6 +922,7 @@ namespace Microsoft.AspNetCore.Hosting
using (var host = (WebHost)builder.Build()) using (var host = (WebHost)builder.Build())
{ {
host.Start();
var sink = host.Services.GetRequiredService<ITestSink>(); var sink = host.Services.GetRequiredService<ITestSink>();
Assert.Contains(sink.Writes, w => w.Exception?.Message == "Startup exception"); Assert.Contains(sink.Writes, w => w.Exception?.Message == "Startup exception");
} }
@ -940,7 +943,7 @@ namespace Microsoft.AspNetCore.Hosting
}) })
.UseServer(new TestServer()); .UseServer(new TestServer());
Assert.Throws<InvalidOperationException>(() => builder.Build()); Assert.Throws<InvalidOperationException>(() => builder.Build().Start());
Assert.NotNull(testSink); Assert.NotNull(testSink);
Assert.Contains(testSink.Writes, w => w.Exception?.Message == "Startup exception"); Assert.Contains(testSink.Writes, w => w.Exception?.Message == "Startup exception");

View File

@ -759,6 +759,7 @@ namespace Microsoft.AspNetCore.Hosting
}) })
.Build()) .Build())
{ {
host.Start();
Assert.Equal(6, configureOrder); Assert.Equal(6, configureOrder);
} }
} }