Skip to content
This repository has been archived by the owner on Dec 19, 2018. It is now read-only.

Commit

Permalink
This change introduces a new service IStartup that can be registere…
Browse files Browse the repository at this point in the history
…d in the hosting container to override any startup logic. `UseStartup` overloads have been changed to detect `IStartup` and directly put it in the container, or to wrapping it with a `ConventionBasedStartup` implementation to preserve the existing behavior.

- Remove IStartupLoader and add `IStartup` instead that matches the signature hosting cares about
- Moved `UseStartup` to extension methods
- Move existing logic into `ConventionBasedStartup` class
  • Loading branch information
davidfowl committed Apr 19, 2016
1 parent dd6bf6a commit 8f5f8d2
Show file tree
Hide file tree
Showing 30 changed files with 280 additions and 265 deletions.
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"projects": ["src"]
}
}
11 changes: 6 additions & 5 deletions samples/SampleStartups/StartupBlockingOnStart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@

namespace SampleStartups
{
public class StartupBlockingOnStart
public class StartupBlockingOnStart : StartupBase
{
// 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)
public override IServiceProvider ConfigureServices(IServiceCollection services)
{
// 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
return base.ConfigureServices(services);
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
public override void Configure(IApplicationBuilder app)
{
app.Run(async (context) =>
{
Expand Down
11 changes: 2 additions & 9 deletions samples/SampleStartups/StartupConfigureAddresses.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.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
public class StartupConfigureAddresses : StartupBase
{
// 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)
public override void Configure(IApplicationBuilder app)
{
app.Run(async (context) =>
{
Expand Down
13 changes: 3 additions & 10 deletions samples/SampleStartups/StartupExternallyControlled.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,18 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.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
public class StartupExternallyControlled : StartupBase
{
private IWebHost _host;
private readonly List<string> _urls = new List<string>();

// 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)
public override void Configure(IApplicationBuilder app)
{
app.Run(async (context) =>
{
Expand Down
11 changes: 2 additions & 9 deletions samples/SampleStartups/StartupHelloWorld.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.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
public class StartupHelloWorld : StartupBase
{
// 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)
public override void Configure(IApplicationBuilder app)
{
app.Run(async (context) =>
{
Expand Down
16 changes: 16 additions & 0 deletions src/Microsoft.AspNetCore.Hosting.Abstractions/IStartup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Hosting
{
public interface IStartup
{
IServiceProvider ConfigureServices(IServiceCollection services);

void Configure(IApplicationBuilder app);
}
}
16 changes: 0 additions & 16 deletions src/Microsoft.AspNetCore.Hosting.Abstractions/IWebHostBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

Expand All @@ -26,27 +24,13 @@ public interface IWebHostBuilder
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
IWebHostBuilder UseLoggerFactory(ILoggerFactory loggerFactory);

/// <summary>
/// Specify the startup type to be used by the web host.
/// </summary>
/// <param name="startupType">The <see cref="Type"/> to be used.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
IWebHostBuilder UseStartup(Type startupType);

/// <summary>
/// Specify the delegate that is used to configure the services of the web application.
/// </summary>
/// <param name="configureServices">The delegate that configures the <see cref="IServiceCollection"/>.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
IWebHostBuilder ConfigureServices(Action<IServiceCollection> configureServices);

/// <summary>
/// Specify the startup method to be used to configure the web application.
/// </summary>
/// <param name="configureApplication">The delegate that configures the <see cref="IApplicationBuilder"/>.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
IWebHostBuilder Configure(Action<IApplicationBuilder> configureApplication);

/// <summary>
/// Adds a delegate for configuring the provided <see cref="ILoggerFactory"/>. This may be called multiple times.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ namespace Microsoft.AspNetCore.Hosting
{
public static class WebHostDefaults
{
public static readonly string ApplicationKey = "application";
public static readonly string ApplicationKey = "applicationName";
public static readonly string StartupAssemblyKey = "startupAssembly";

public static readonly string DetailedErrorsKey = "detailedErrors";
public static readonly string EnvironmentKey = "environment";
public static readonly string ServerKey = "server";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Startup;

namespace Microsoft.AspNetCore.Hosting.Internal
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Hosting.Startup
namespace Microsoft.AspNetCore.Hosting.Internal
{
public class ConfigureBuilder
{
Expand Down Expand Up @@ -51,4 +51,4 @@ private void Invoke(object instance, IApplicationBuilder builder)
MethodInfo.Invoke(instance, parameters);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Hosting.Startup
namespace Microsoft.AspNetCore.Hosting.Internal
{
public class ConfigureServicesBuilder
{
Expand Down
5 changes: 4 additions & 1 deletion src/Microsoft.AspNetCore.Hosting/Internal/ServerLoader.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
// 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.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Hosting.Server;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,31 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Hosting.Startup
namespace Microsoft.AspNetCore.Hosting.Internal
{
public class StartupLoader : IStartupLoader
public class StartupLoader
{
private readonly IServiceProvider _services;
private readonly IHostingEnvironment _hostingEnv;

public StartupLoader(IServiceProvider services, IHostingEnvironment hostingEnv)
{
_services = services;
_hostingEnv = hostingEnv;
}

public StartupMethods LoadMethods(
Type startupType,
IList<string> diagnosticMessages)
public static StartupMethods LoadMethods(IServiceProvider services, Type startupType, string environmentName)
{
var environmentName = _hostingEnv.EnvironmentName;
var configureMethod = FindConfigureDelegate(startupType, environmentName);
var servicesMethod = FindConfigureServicesDelegate(startupType, environmentName);

object instance = null;
if (!configureMethod.MethodInfo.IsStatic || (servicesMethod != null && !servicesMethod.MethodInfo.IsStatic))
{
instance = ActivatorUtilities.GetServiceOrCreateInstance(_services, startupType);
instance = ActivatorUtilities.GetServiceOrCreateInstance(services, startupType);
}

return new StartupMethods(configureMethod.Build(instance), servicesMethod?.Build(instance));
}

public Type FindStartupType(string startupAssemblyName, IList<string> diagnosticMessages)
public static Type FindStartupType(string startupAssemblyName, string environmentName)
{
var environmentName = _hostingEnv.EnvironmentName;
if (string.IsNullOrEmpty(startupAssemblyName))
{
throw new ArgumentException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Hosting.Startup
namespace Microsoft.AspNetCore.Hosting.Internal
{
public class StartupMethods
{
Expand Down
46 changes: 12 additions & 34 deletions src/Microsoft.AspNetCore.Hosting/Internal/WebHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Hosting.Startup;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Configuration;
Expand All @@ -22,7 +22,9 @@ namespace Microsoft.AspNetCore.Hosting.Internal
public class WebHost : IWebHost
{
private readonly IServiceCollection _applicationServiceCollection;
private readonly IStartupLoader _startupLoader;
private IStartup _startup;

private readonly IServiceProvider _hostingServiceProvider;
private readonly ApplicationLifetime _applicationLifetime;
private readonly WebHostOptions _options;
private readonly IConfiguration _config;
Expand All @@ -34,16 +36,11 @@ public class WebHost : IWebHost
// Used for testing only
internal WebHostOptions Options => _options;

// Only one of these should be set
internal string StartupAssemblyName { get; set; }
internal StartupMethods Startup { get; set; }
internal Type StartupType { get; set; }

private IServer Server { get; set; }

public WebHost(
IServiceCollection appServices,
IStartupLoader startupLoader,
IServiceProvider hostingServiceProvider,
WebHostOptions options,
IConfiguration config)
{
Expand All @@ -52,9 +49,9 @@ public WebHost(
throw new ArgumentNullException(nameof(appServices));
}

if (startupLoader == null)
if (hostingServiceProvider == null)
{
throw new ArgumentNullException(nameof(startupLoader));
throw new ArgumentNullException(nameof(hostingServiceProvider));
}

if (config == null)
Expand All @@ -65,7 +62,7 @@ public WebHost(
_config = config;
_options = options;
_applicationServiceCollection = appServices;
_startupLoader = startupLoader;
_hostingServiceProvider = hostingServiceProvider;
_applicationLifetime = new ApplicationLifetime();
_applicationServiceCollection.AddSingleton<IApplicationLifetime>(_applicationLifetime);
}
Expand Down Expand Up @@ -116,37 +113,18 @@ private void EnsureApplicationServices()
if (_applicationServices == null)
{
EnsureStartup();
_applicationServices = Startup.ConfigureServicesDelegate(_applicationServiceCollection);
_applicationServices = _startup.ConfigureServices(_applicationServiceCollection);
}
}

private void EnsureStartup()
{
if (Startup != null)
if (_startup != null)
{
return;
}

if (StartupType == null)
{
var diagnosticTypeMessages = new List<string>();
StartupType = _startupLoader.FindStartupType(StartupAssemblyName, diagnosticTypeMessages);
if (StartupType == null)
{
throw new ArgumentException(
diagnosticTypeMessages.Aggregate("Failed to find a startup type for the web application.", (a, b) => a + "\r\n" + b),
StartupAssemblyName);
}
}

var diagnosticMessages = new List<string>();
Startup = _startupLoader.LoadMethods(StartupType, diagnosticMessages);
if (Startup == null)
{
throw new ArgumentException(
diagnosticMessages.Aggregate("Failed to find a startup entry point for the web application.", (a, b) => a + "\r\n" + b),
StartupAssemblyName);
}
_startup = _hostingServiceProvider.GetRequiredService<IStartup>();
}

private RequestDelegate BuildApplication()
Expand All @@ -161,7 +139,7 @@ private RequestDelegate BuildApplication()
builder.ApplicationServices = _applicationServices;

var startupFilters = _applicationServices.GetService<IEnumerable<IStartupFilter>>();
var configure = Startup.ConfigureDelegate;
Action<IApplicationBuilder> configure = _startup.Configure;
foreach (var filter in startupFilters.Reverse())
{
configure = filter.Configure(configure);
Expand Down
Loading

0 comments on commit 8f5f8d2

Please sign in to comment.