1414using Microsoft . AspNet . Http . Features ;
1515using Microsoft . AspNet . Http . Features . Internal ;
1616using Microsoft . AspNet . Server . Features ;
17+ using Microsoft . Dnx . Runtime ;
1718using Microsoft . Framework . Configuration ;
1819using Microsoft . Framework . DependencyInjection ;
1920using Microsoft . Framework . Logging ;
@@ -24,11 +25,13 @@ public class HostingEngine : IHostingEngine
2425 {
2526 // This is defined by IIS's HttpPlatformHandler.
2627 private static readonly string ServerPort = "HTTP_PLATFORM_PORT" ;
28+ private static readonly string DetailedErrors = "Hosting:DetailedErrors" ;
2729
2830 private readonly IServiceCollection _applicationServiceCollection ;
2931 private readonly IStartupLoader _startupLoader ;
3032 private readonly ApplicationLifetime _applicationLifetime ;
3133 private readonly IConfiguration _config ;
34+ private readonly bool _captureStartupErrors ;
3235
3336 private IServiceProvider _applicationServices ;
3437
@@ -45,7 +48,8 @@ public class HostingEngine : IHostingEngine
4548 public HostingEngine (
4649 IServiceCollection appServices ,
4750 IStartupLoader startupLoader ,
48- IConfiguration config )
51+ IConfiguration config ,
52+ bool captureStartupErrors )
4953 {
5054 if ( appServices == null )
5155 {
@@ -65,6 +69,7 @@ public HostingEngine(
6569 _config = config ;
6670 _applicationServiceCollection = appServices ;
6771 _startupLoader = startupLoader ;
72+ _captureStartupErrors = captureStartupErrors ;
6873 _applicationLifetime = new ApplicationLifetime ( ) ;
6974 }
7075
@@ -79,8 +84,6 @@ public IServiceProvider ApplicationServices
7984
8085 public virtual IApplication Start ( )
8186 {
82- EnsureApplicationServices ( ) ;
83-
8487 var application = BuildApplication ( ) ;
8588
8689 var logger = _applicationServices . GetRequiredService < ILogger < HostingEngine > > ( ) ;
@@ -175,48 +178,97 @@ private void EnsureStartup()
175178
176179 private RequestDelegate BuildApplication ( )
177180 {
178- if ( ServerFactory == null )
181+ try
179182 {
180- // Blow up if we don't have a server set at this point
181- if ( ServerFactoryLocation == null )
183+ EnsureApplicationServices ( ) ;
184+ EnsureServer ( ) ;
185+
186+ var builderFactory = _applicationServices . GetRequiredService < IApplicationBuilderFactory > ( ) ;
187+ var builder = builderFactory . CreateBuilder ( _serverInstance ) ;
188+ builder . ApplicationServices = _applicationServices ;
189+
190+ var startupFilters = _applicationServices . GetService < IEnumerable < IStartupFilter > > ( ) ;
191+ var configure = Startup . ConfigureDelegate ;
192+ foreach ( var filter in startupFilters )
182193 {
183- throw new InvalidOperationException ( "IHostingBuilder.UseServer() is required for " + nameof ( Start ) + "()" ) ;
194+ configure = filter . Configure ( configure ) ;
184195 }
185196
186- ServerFactory = _applicationServices . GetRequiredService < IServerLoader > ( ) . LoadServerFactory ( ServerFactoryLocation ) ;
187- }
188-
189- _serverInstance = ServerFactory . Initialize ( _config ) ;
190- var builderFactory = _applicationServices . GetRequiredService < IApplicationBuilderFactory > ( ) ;
191- var builder = builderFactory . CreateBuilder ( _serverInstance ) ;
192- builder . ApplicationServices = _applicationServices ;
197+ configure ( builder ) ;
193198
194- var addresses = builder . ServerFeatures ? . Get < IServerAddressesFeature > ( ) ? . Addresses ;
195- if ( addresses != null && ! addresses . IsReadOnly )
199+ return builder . Build ( ) ;
200+ }
201+ catch ( Exception ex )
196202 {
197- var port = _config [ ServerPort ] ;
198- if ( ! string . IsNullOrEmpty ( port ) )
203+ if ( ! _captureStartupErrors )
199204 {
200- addresses . Add ( "http://localhost:" + port ) ;
205+ throw ;
201206 }
202207
203- // Provide a default address if there aren't any configured .
204- if ( addresses . Count == 0 )
208+ // EnsureApplicationServices may have failed due to a missing or throwing Startup class .
209+ if ( _applicationServices == null )
205210 {
206- addresses . Add ( "http://localhost:5000" ) ;
211+ _applicationServices = _applicationServiceCollection . BuildServiceProvider ( ) ;
207212 }
213+
214+ EnsureServer ( ) ;
215+
216+ // Write errors to standard out so they can be retrieved when not in development mode.
217+ Console . Out . WriteLine ( "Application startup exception: " + ex . ToString ( ) ) ;
218+ var logger = _applicationServices . GetRequiredService < ILogger < HostingEngine > > ( ) ;
219+ logger . LogError ( "Application startup exception" , ex ) ;
220+
221+ // Generate an HTML error page.
222+ var runtimeEnv = _applicationServices . GetRequiredService < IRuntimeEnvironment > ( ) ;
223+ var hostingEnv = _applicationServices . GetRequiredService < IHostingEnvironment > ( ) ;
224+ var showDetailedErrors = hostingEnv . IsDevelopment ( )
225+ || string . Equals ( "true" , _config [ DetailedErrors ] , StringComparison . OrdinalIgnoreCase )
226+ || string . Equals ( "1" , _config [ DetailedErrors ] , StringComparison . OrdinalIgnoreCase ) ;
227+ var errorBytes = StartupExceptionPage . GenerateErrorHtml ( showDetailedErrors , runtimeEnv , ex ) ;
228+
229+ return context =>
230+ {
231+ context . Response . StatusCode = 500 ;
232+ context . Response . Headers [ "Cache-Control" ] = "private, max-age=0" ;
233+ context . Response . ContentType = "text/html; charset=utf-8" ;
234+ context . Response . ContentLength = errorBytes . Length ;
235+ return context . Response . Body . WriteAsync ( errorBytes , 0 , errorBytes . Length ) ;
236+ } ;
208237 }
238+ }
209239
210- var startupFilters = _applicationServices . GetService < IEnumerable < IStartupFilter > > ( ) ;
211- var configure = Startup . ConfigureDelegate ;
212- foreach ( var filter in startupFilters )
240+ private void EnsureServer ( )
241+ {
242+ if ( ServerFactory == null )
213243 {
214- configure = filter . Configure ( configure ) ;
244+ // Blow up if we don't have a server set at this point
245+ if ( ServerFactoryLocation == null )
246+ {
247+ throw new InvalidOperationException ( "IHostingBuilder.UseServer() is required for " + nameof ( Start ) + "()" ) ;
248+ }
249+
250+ ServerFactory = _applicationServices . GetRequiredService < IServerLoader > ( ) . LoadServerFactory ( ServerFactoryLocation ) ;
215251 }
216252
217- configure ( builder ) ;
253+ if ( _serverInstance == null )
254+ {
255+ _serverInstance = ServerFactory . Initialize ( _config ) ;
256+ var addresses = _serverInstance ? . Get < IServerAddressesFeature > ( ) ? . Addresses ;
257+ if ( addresses != null && ! addresses . IsReadOnly )
258+ {
259+ var port = _config [ ServerPort ] ;
260+ if ( ! string . IsNullOrEmpty ( port ) )
261+ {
262+ addresses . Add ( "http://localhost:" + port ) ;
263+ }
218264
219- return builder . Build ( ) ;
265+ // Provide a default address if there aren't any configured.
266+ if ( addresses . Count == 0 )
267+ {
268+ addresses . Add ( "http://localhost:5000" ) ;
269+ }
270+ }
271+ }
220272 }
221273
222274 private string GetRequestIdentifier ( HttpContext httpContext )
0 commit comments