#698 Remove IServerFactory

This commit is contained in:
Chris R 2016-04-14 14:08:36 -07:00
parent 622d6b006f
commit 26e6036187
11 changed files with 55 additions and 122 deletions

View File

@ -3,7 +3,7 @@
using System.Collections.Generic;
namespace Microsoft.AspNetCore.Server.Features
namespace Microsoft.AspNetCore.Hosting.Server.Features
{
public interface IServerAddressesFeature
{

View File

@ -1,20 +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 Microsoft.Extensions.Configuration;
namespace Microsoft.AspNetCore.Hosting.Server
{
/// <summary>
/// Represents a factory for creating servers.
/// </summary>
public interface IServerFactory
{
/// <summary>
/// Creates <see cref="IServer"/> based on the given configuration.
/// </summary>
/// <param name="configuration">An instance of <see cref="IConfiguration"/>.</param>
/// <returns>The created server.</returns>
IServer CreateServer(IConfiguration configuration);
}
}

View File

@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal
{
internal static class ServerLoader
{
internal static Type ResolveServerFactoryType(string assemblyName)
internal static Type ResolveServerType(string assemblyName)
{
var assembly = Assembly.Load(new AssemblyName(assemblyName));
if (assembly == null)
@ -16,12 +16,12 @@ namespace Microsoft.AspNetCore.Hosting.Internal
}
var serverTypeInfo = assembly.DefinedTypes.Where(
t => t.ImplementedInterfaces.FirstOrDefault(interf => interf.Equals(typeof(IServerFactory))) != null)
t => t.ImplementedInterfaces.FirstOrDefault(interf => interf.Equals(typeof(IServer))) != null)
.FirstOrDefault();
if (serverTypeInfo == null)
{
throw new InvalidOperationException($"No server type found that implements IServerFactory in assembly: {assemblyName}.");
throw new InvalidOperationException($"No server type found that implements IServer in assembly: {assemblyName}.");
}
return serverTypeInfo.AsType();

View File

@ -8,10 +8,10 @@ using System.Linq;
using System.Threading;
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.AspNetCore.Server.Features;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@ -39,8 +39,6 @@ namespace Microsoft.AspNetCore.Hosting.Internal
internal StartupMethods Startup { get; set; }
internal Type StartupType { get; set; }
private IServerFactory ServerFactory { get; set; }
private IServer Server { get; set; }
public WebHost(
@ -209,14 +207,25 @@ namespace Microsoft.AspNetCore.Hosting.Internal
{
if (Server == null)
{
ServerFactory = _applicationServices.GetRequiredService<IServerFactory>();
Server = ServerFactory.CreateServer(_config);
Server = _applicationServices.GetRequiredService<IServer>();
var addresses = Server.Features?.Get<IServerAddressesFeature>()?.Addresses;
if (addresses != null && !addresses.IsReadOnly && addresses.Count == 0)
{
// Provide a default address if there aren't any configured.
addresses.Add("http://localhost:5000");
var urls = _config[WebHostDefaults.ServerUrlsKey];
if (!string.IsNullOrEmpty(urls))
{
foreach (var value in urls.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
addresses.Add(value);
}
}
if (addresses.Count == 0)
{
// Provide a default address if there aren't any configured.
addresses.Add("http://localhost:5000");
}
}
}
}

View File

@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal
DetailedErrors = ParseBool(configuration, WebHostDefaults.DetailedErrorsKey);
CaptureStartupErrors = ParseBool(configuration, WebHostDefaults.CaptureStartupErrorsKey);
Environment = configuration[WebHostDefaults.EnvironmentKey];
ServerFactoryAssembly = configuration[WebHostDefaults.ServerKey];
ServerAssembly = configuration[WebHostDefaults.ServerKey];
WebRoot = configuration[WebHostDefaults.WebRootKey];
ContentRootPath = configuration[WebHostDefaults.ContentRootKey];
}
@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal
public string Environment { get; set; }
public string ServerFactoryAssembly { get; set; }
public string ServerAssembly { get; set; }
public string WebRoot { get; set; }

View File

@ -0,0 +1,12 @@
// 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.Collections.Generic;
namespace Microsoft.AspNetCore.Hosting.Server.Features
{
public class ServerAddressesFeature : IServerAddressesFeature
{
public ICollection<string> Addresses { get; } = new List<string>();
}
}

View File

@ -222,11 +222,11 @@ namespace Microsoft.AspNetCore.Hosting
services.AddSingleton(defaultPlatformServices.Application);
services.AddSingleton(defaultPlatformServices.Runtime);
if (!string.IsNullOrEmpty(_options.ServerFactoryAssembly))
if (!string.IsNullOrEmpty(_options.ServerAssembly))
{
// Add the server factory
var serverFactoryType = ServerLoader.ResolveServerFactoryType(_options.ServerFactoryAssembly);
services.AddSingleton(typeof(IServerFactory), serverFactoryType);
// Add the server
var serverType = ServerLoader.ResolveServerType(_options.ServerAssembly);
services.AddSingleton(typeof(IServer), serverType);
}
foreach (var configureServices in _configureServicesDelegates)

View File

@ -107,27 +107,6 @@ namespace Microsoft.AspNetCore.Hosting
return hostBuilder.UseSetting(WebHostDefaults.ServerKey, assemblyName);
}
/// <summary>
/// Specify the <see cref="IServerFactory"/> to be used by the web host.
/// </summary>
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param>
/// <param name="factory">The <see cref="IServerFactory"/> to be used.</param>
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
public static IWebHostBuilder UseServer(this IWebHostBuilder hostBuilder, IServerFactory factory)
{
if (factory == null)
{
throw new ArgumentNullException(nameof(factory));
}
return hostBuilder.ConfigureServices(services =>
{
// It would be nicer if this was transient but we need to pass in the
// factory instance directly
services.AddSingleton(factory);
});
}
/// <summary>
/// Specify the server to be used by the web host.
/// </summary>
@ -141,9 +120,12 @@ namespace Microsoft.AspNetCore.Hosting
throw new ArgumentNullException(nameof(server));
}
// It would be nicer if this was transient but we need to pass in the
// server instance directly
return hostBuilder.UseServer(new ServerFactory(server));
return hostBuilder.ConfigureServices(services =>
{
// It would be nicer if this was transient but we need to pass in the
// factory instance directly
services.AddSingleton(server);
});
}
/// <summary>
@ -222,17 +204,5 @@ namespace Microsoft.AspNetCore.Hosting
host.Start();
return host;
}
private class ServerFactory : IServerFactory
{
private readonly IServer _server;
public ServerFactory(IServer server)
{
_server = server;
}
public IServer CreateServer(IConfiguration configuration) => _server;
}
}
}

View File

@ -3,7 +3,7 @@
using System;
using System.Threading;
using Microsoft.AspNetCore.Server.Features;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Hosting

View File

@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Hosting.Tests
var config = new WebHostOptions(new ConfigurationBuilder().AddInMemoryCollection(parameters).Build());
Assert.Equal("wwwroot", config.WebRoot);
Assert.Equal("Microsoft.AspNetCore.Server.Kestrel", config.ServerFactoryAssembly);
Assert.Equal("Microsoft.AspNetCore.Server.Kestrel", config.ServerAssembly);
Assert.Equal("MyProjectReference", config.Application);
Assert.Equal("Development", config.Environment);
Assert.True(config.CaptureStartupErrors);

View File

@ -10,11 +10,12 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Fakes;
using Microsoft.AspNetCore.Hosting.Internal;
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.AspNetCore.Server.Features;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@ -24,11 +25,10 @@ using Xunit;
namespace Microsoft.AspNetCore.Hosting
{
public class WebHostTests : IServerFactory
public class WebHostTests : IServer
{
private readonly IList<StartInstance> _startInstances = new List<StartInstance>();
private IFeatureCollection _featuresSupportedByThisHost = NewFeatureCollection();
private IFeatureCollection _instanceFeaturesSupportedByThisHost;
public IFeatureCollection Features
{
@ -41,14 +41,6 @@ namespace Microsoft.AspNetCore.Hosting
features[feature.Key] = feature.Value;
}
if (_instanceFeaturesSupportedByThisHost != null)
{
foreach (var feature in _instanceFeaturesSupportedByThisHost)
{
features[feature.Key] = feature.Value;
}
}
return features;
}
}
@ -57,8 +49,9 @@ namespace Microsoft.AspNetCore.Hosting
{
var stub = new StubFeatures();
var features = new FeatureCollection();
features[typeof(IHttpRequestFeature)] = stub;
features[typeof(IHttpResponseFeature)] = stub;
features.Set<IHttpRequestFeature>(stub);
features.Set<IHttpResponseFeature>(stub);
features.Set<IServerAddressesFeature>(new ServerAddressesFeature());
return features;
}
@ -66,7 +59,7 @@ namespace Microsoft.AspNetCore.Hosting
public void WebHostThrowsWithNoServer()
{
var ex = Assert.Throws<InvalidOperationException>(() => CreateBuilder().Build().Start());
Assert.Equal("No service for type 'Microsoft.AspNetCore.Hosting.Server.IServerFactory' has been registered.", ex.Message);
Assert.Equal("No service for type 'Microsoft.AspNetCore.Hosting.Server.IServer' has been registered.", ex.Message);
}
[Fact]
@ -138,7 +131,7 @@ namespace Microsoft.AspNetCore.Hosting
host.Dispose();
Assert.Equal(1, _startInstances[0].DisposeCalls);
Assert.Equal(2, _startInstances[0].DisposeCalls); // Once as the server, once from the DI Container
}
[Fact]
@ -166,7 +159,7 @@ namespace Microsoft.AspNetCore.Hosting
// Wait on the host to shutdown
lifetime.ApplicationStopped.WaitHandle.WaitOne();
Assert.Equal(1, _startInstances[0].DisposeCalls);
Assert.Equal(2, _startInstances[0].DisposeCalls); // Once as the server, once from the DI Container
}
[Fact]
@ -493,13 +486,6 @@ namespace Microsoft.AspNetCore.Hosting
}
}
public IServer CreateServer(IConfiguration configuration)
{
_instanceFeaturesSupportedByThisHost = new FeatureCollection();
_instanceFeaturesSupportedByThisHost.Set<IServerAddressesFeature>(new ServerAddressesFeature());
return new FakeServer(this);
}
private class StartInstance : IDisposable
{
public int DisposeCalls { get; set; }
@ -566,11 +552,6 @@ namespace Microsoft.AspNetCore.Hosting
}
}
private class ServerAddressesFeature : IServerAddressesFeature
{
public ICollection<string> Addresses { get; } = new List<string>();
}
private class AllMessagesAreNeeded : ILoggerProvider, ILogger
{
public bool IsEnabled(LogLevel logLevel) => true;
@ -671,24 +652,5 @@ namespace Microsoft.AspNetCore.Hosting
{
public string TraceIdentifier { get; set; }
}
private class FakeServer : IServer
{
private readonly WebHostTests _webHostTests;
public FakeServer(WebHostTests webHostTests)
{
_webHostTests = webHostTests;
}
public IFeatureCollection Features => _webHostTests.Features;
public void Dispose() => _webHostTests.Dispose();
public void Start<TContext>(IHttpApplication<TContext> application)
{
_webHostTests.Start<TContext>(application);
}
}
}
}