Map ListenOptions.Protocols from IConfiguration #2903
This commit is contained in:
parent
de5ccb5c78
commit
f38f60f8ce
|
|
@ -9,9 +9,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
{
|
{
|
||||||
internal class ConfigurationReader
|
internal class ConfigurationReader
|
||||||
{
|
{
|
||||||
|
private const string ProtocolsKey = "Protocols";
|
||||||
|
private const string CertificatesKey = "Certificates";
|
||||||
|
private const string CertificateKey = "Certificate";
|
||||||
|
private const string EndpointDefaultsKey = "EndpointDefaults";
|
||||||
|
private const string EndpointsKey = "Endpoints";
|
||||||
|
private const string UrlKey = "Url";
|
||||||
|
|
||||||
private IConfiguration _configuration;
|
private IConfiguration _configuration;
|
||||||
private IDictionary<string, CertificateConfig> _certificates;
|
private IDictionary<string, CertificateConfig> _certificates;
|
||||||
private IList<EndpointConfig> _endpoints;
|
private IList<EndpointConfig> _endpoints;
|
||||||
|
private EndpointDefaults _endpointDefaults;
|
||||||
|
|
||||||
public ConfigurationReader(IConfiguration configuration)
|
public ConfigurationReader(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
|
|
@ -31,6 +39,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EndpointDefaults EndpointDefaults
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_endpointDefaults == null)
|
||||||
|
{
|
||||||
|
ReadEndpointDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _endpointDefaults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<EndpointConfig> Endpoints
|
public IEnumerable<EndpointConfig> Endpoints
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -48,29 +69,42 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
{
|
{
|
||||||
_certificates = new Dictionary<string, CertificateConfig>(0);
|
_certificates = new Dictionary<string, CertificateConfig>(0);
|
||||||
|
|
||||||
var certificatesConfig = _configuration.GetSection("Certificates").GetChildren();
|
var certificatesConfig = _configuration.GetSection(CertificatesKey).GetChildren();
|
||||||
foreach (var certificateConfig in certificatesConfig)
|
foreach (var certificateConfig in certificatesConfig)
|
||||||
{
|
{
|
||||||
_certificates.Add(certificateConfig.Key, new CertificateConfig(certificateConfig));
|
_certificates.Add(certificateConfig.Key, new CertificateConfig(certificateConfig));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "EndpointDefaults": {
|
||||||
|
// "Protocols": "Http1AndHttp2",
|
||||||
|
// }
|
||||||
|
private void ReadEndpointDefaults()
|
||||||
|
{
|
||||||
|
var configSection = _configuration.GetSection(EndpointDefaultsKey);
|
||||||
|
_endpointDefaults = new EndpointDefaults()
|
||||||
|
{
|
||||||
|
Protocols = ParseProtocols(configSection[ProtocolsKey])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void ReadEndpoints()
|
private void ReadEndpoints()
|
||||||
{
|
{
|
||||||
_endpoints = new List<EndpointConfig>();
|
_endpoints = new List<EndpointConfig>();
|
||||||
|
|
||||||
var endpointsConfig = _configuration.GetSection("Endpoints").GetChildren();
|
var endpointsConfig = _configuration.GetSection(EndpointsKey).GetChildren();
|
||||||
foreach (var endpointConfig in endpointsConfig)
|
foreach (var endpointConfig in endpointsConfig)
|
||||||
{
|
{
|
||||||
// "EndpointName": {
|
// "EndpointName": {
|
||||||
// "Url": "https://*:5463",
|
// "Url": "https://*:5463",
|
||||||
// "Certificate": {
|
// "Protocols": "Http1AndHttp2",
|
||||||
// "Path": "testCert.pfx",
|
// "Certificate": {
|
||||||
// "Password": "testPassword"
|
// "Path": "testCert.pfx",
|
||||||
// }
|
// "Password": "testPassword"
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
var url = endpointConfig["Url"];
|
var url = endpointConfig[UrlKey];
|
||||||
if (string.IsNullOrEmpty(url))
|
if (string.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(CoreStrings.FormatEndpointMissingUrl(endpointConfig.Key));
|
throw new InvalidOperationException(CoreStrings.FormatEndpointMissingUrl(endpointConfig.Key));
|
||||||
|
|
@ -80,16 +114,37 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
{
|
{
|
||||||
Name = endpointConfig.Key,
|
Name = endpointConfig.Key,
|
||||||
Url = url,
|
Url = url,
|
||||||
|
Protocols = ParseProtocols(endpointConfig[ProtocolsKey]),
|
||||||
ConfigSection = endpointConfig,
|
ConfigSection = endpointConfig,
|
||||||
Certificate = new CertificateConfig(endpointConfig.GetSection("Certificate")),
|
Certificate = new CertificateConfig(endpointConfig.GetSection(CertificateKey)),
|
||||||
};
|
};
|
||||||
_endpoints.Add(endpoint);
|
_endpoints.Add(endpoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static HttpProtocols? ParseProtocols(string protocols)
|
||||||
|
{
|
||||||
|
if (Enum.TryParse<HttpProtocols>(protocols, ignoreCase: true, out var result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// "EndpointDefaults": {
|
||||||
|
// "Protocols": "Http1AndHttp2",
|
||||||
|
// }
|
||||||
|
internal class EndpointDefaults
|
||||||
|
{
|
||||||
|
public HttpProtocols? Protocols { get; set; }
|
||||||
|
public IConfigurationSection ConfigSection { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// "EndpointName": {
|
// "EndpointName": {
|
||||||
// "Url": "https://*:5463",
|
// "Url": "https://*:5463",
|
||||||
|
// "Protocols": "Http1AndHttp2",
|
||||||
// "Certificate": {
|
// "Certificate": {
|
||||||
// "Path": "testCert.pfx",
|
// "Path": "testCert.pfx",
|
||||||
// "Password": "testPassword"
|
// "Password": "testPassword"
|
||||||
|
|
@ -99,6 +154,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Url { get; set; }
|
public string Url { get; set; }
|
||||||
|
public HttpProtocols? Protocols { get; set; }
|
||||||
public IConfigurationSection ConfigSection { get; set; }
|
public IConfigurationSection ConfigSection { get; set; }
|
||||||
public CertificateConfig Certificate { get; set; }
|
public CertificateConfig Certificate { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
||||||
{
|
{
|
||||||
public class KestrelConfigurationLoader
|
public class KestrelConfigurationLoader
|
||||||
{
|
{
|
||||||
|
private bool _loaded = false;
|
||||||
|
|
||||||
internal KestrelConfigurationLoader(KestrelServerOptions options, IConfiguration configuration)
|
internal KestrelConfigurationLoader(KestrelServerOptions options, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
Options = options ?? throw new ArgumentNullException(nameof(options));
|
Options = options ?? throw new ArgumentNullException(nameof(options));
|
||||||
Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
||||||
|
ConfigurationReader = new ConfigurationReader(Configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KestrelServerOptions Options { get; }
|
public KestrelServerOptions Options { get; }
|
||||||
public IConfiguration Configuration { get; }
|
public IConfiguration Configuration { get; }
|
||||||
|
internal ConfigurationReader ConfigurationReader { get; }
|
||||||
private IDictionary<string, Action<EndpointConfiguration>> EndpointConfigurations { get; }
|
private IDictionary<string, Action<EndpointConfiguration>> EndpointConfigurations { get; }
|
||||||
= new Dictionary<string, Action<EndpointConfiguration>>(0, StringComparer.OrdinalIgnoreCase);
|
= new Dictionary<string, Action<EndpointConfiguration>>(0, StringComparer.OrdinalIgnoreCase);
|
||||||
// Actions that will be delayed until Load so that they aren't applied if the configuration loader is replaced.
|
// Actions that will be delayed until Load so that they aren't applied if the configuration loader is replaced.
|
||||||
|
|
@ -197,24 +201,39 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called from ApplyEndpointDefaults so it applies to even explicit Listen endpoints.
|
||||||
|
// Does not require a call to Load.
|
||||||
|
internal void ApplyConfigurationDefaults(ListenOptions listenOptions)
|
||||||
|
{
|
||||||
|
var defaults = ConfigurationReader.EndpointDefaults;
|
||||||
|
|
||||||
|
if (defaults.Protocols.HasValue)
|
||||||
|
{
|
||||||
|
listenOptions.Protocols = defaults.Protocols.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Load()
|
public void Load()
|
||||||
{
|
{
|
||||||
if (Options.ConfigurationLoader == null)
|
if (_loaded)
|
||||||
{
|
{
|
||||||
// The loader has already been run.
|
// The loader has already been run.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Options.ConfigurationLoader = null;
|
_loaded = true;
|
||||||
|
|
||||||
var configReader = new ConfigurationReader(Configuration);
|
LoadDefaultCert(ConfigurationReader);
|
||||||
|
|
||||||
LoadDefaultCert(configReader);
|
foreach (var endpoint in ConfigurationReader.Endpoints)
|
||||||
|
|
||||||
foreach (var endpoint in configReader.Endpoints)
|
|
||||||
{
|
{
|
||||||
var listenOptions = AddressBinder.ParseAddress(endpoint.Url, out var https);
|
var listenOptions = AddressBinder.ParseAddress(endpoint.Url, out var https);
|
||||||
Options.ApplyEndpointDefaults(listenOptions);
|
Options.ApplyEndpointDefaults(listenOptions);
|
||||||
|
|
||||||
|
if (endpoint.Protocols.HasValue)
|
||||||
|
{
|
||||||
|
listenOptions.Protocols = endpoint.Protocols.Value;
|
||||||
|
}
|
||||||
|
|
||||||
// Compare to UseHttps(httpsOptions => { })
|
// Compare to UseHttps(httpsOptions => { })
|
||||||
var httpsOptions = new HttpsConnectionAdapterOptions();
|
var httpsOptions = new HttpsConnectionAdapterOptions();
|
||||||
if (https)
|
if (https)
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
||||||
internal void ApplyEndpointDefaults(ListenOptions listenOptions)
|
internal void ApplyEndpointDefaults(ListenOptions listenOptions)
|
||||||
{
|
{
|
||||||
listenOptions.KestrelServerOptions = this;
|
listenOptions.KestrelServerOptions = this;
|
||||||
|
ConfigurationLoader?.ApplyConfigurationDefaults(listenOptions);
|
||||||
EndpointDefaults(listenOptions);
|
EndpointDefaults(listenOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,13 +81,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests
|
||||||
|
|
||||||
Assert.Single(serverOptions.ListenOptions);
|
Assert.Single(serverOptions.ListenOptions);
|
||||||
Assert.Equal(5001, serverOptions.ListenOptions[0].IPEndPoint.Port);
|
Assert.Equal(5001, serverOptions.ListenOptions[0].IPEndPoint.Port);
|
||||||
Assert.Null(serverOptions.ConfigurationLoader);
|
Assert.NotNull(serverOptions.ConfigurationLoader);
|
||||||
|
|
||||||
builder.Load();
|
builder.Load();
|
||||||
|
|
||||||
Assert.Single(serverOptions.ListenOptions);
|
Assert.Single(serverOptions.ListenOptions);
|
||||||
Assert.Equal(5001, serverOptions.ListenOptions[0].IPEndPoint.Port);
|
Assert.Equal(5001, serverOptions.ListenOptions[0].IPEndPoint.Port);
|
||||||
Assert.Null(serverOptions.ConfigurationLoader);
|
Assert.NotNull(serverOptions.ConfigurationLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -131,6 +131,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests
|
||||||
serverOptions.ConfigureEndpointDefaults(opt =>
|
serverOptions.ConfigureEndpointDefaults(opt =>
|
||||||
{
|
{
|
||||||
opt.NoDelay = false;
|
opt.NoDelay = false;
|
||||||
|
opt.Protocols = HttpProtocols.Http2;
|
||||||
});
|
});
|
||||||
|
|
||||||
serverOptions.ConfigureHttpsDefaults(opt =>
|
serverOptions.ConfigureHttpsDefaults(opt =>
|
||||||
|
|
@ -153,11 +154,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests
|
||||||
Assert.NotNull(opt.HttpsOptions.ServerCertificate);
|
Assert.NotNull(opt.HttpsOptions.ServerCertificate);
|
||||||
Assert.Equal(ClientCertificateMode.RequireCertificate, opt.HttpsOptions.ClientCertificateMode);
|
Assert.Equal(ClientCertificateMode.RequireCertificate, opt.HttpsOptions.ClientCertificateMode);
|
||||||
Assert.False(opt.ListenOptions.NoDelay);
|
Assert.False(opt.ListenOptions.NoDelay);
|
||||||
|
Assert.Equal(HttpProtocols.Http2, opt.ListenOptions.Protocols);
|
||||||
})
|
})
|
||||||
.LocalhostEndpoint(5002, opt =>
|
.LocalhostEndpoint(5002, opt =>
|
||||||
{
|
{
|
||||||
ran2 = true;
|
ran2 = true;
|
||||||
Assert.False(opt.NoDelay);
|
Assert.False(opt.NoDelay);
|
||||||
|
Assert.Equal(HttpProtocols.Http2, opt.Protocols);
|
||||||
})
|
})
|
||||||
.Load();
|
.Load();
|
||||||
|
|
||||||
|
|
@ -316,6 +319,119 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("http1", HttpProtocols.Http1)]
|
||||||
|
[InlineData("http2", HttpProtocols.Http2)]
|
||||||
|
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)]
|
||||||
|
public void DefaultConfigSectionCanSetProtocols(string input, HttpProtocols expected)
|
||||||
|
{
|
||||||
|
var serverOptions = CreateServerOptions();
|
||||||
|
var ranDefault = false;
|
||||||
|
serverOptions.ConfigureEndpointDefaults(opt =>
|
||||||
|
{
|
||||||
|
Assert.Equal(expected, opt.Protocols);
|
||||||
|
ranDefault = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
serverOptions.ConfigureHttpsDefaults(opt =>
|
||||||
|
{
|
||||||
|
opt.ServerCertificate = new X509Certificate2(TestResources.TestCertificatePath, "testPassword");
|
||||||
|
opt.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
|
||||||
|
});
|
||||||
|
|
||||||
|
var ran1 = false;
|
||||||
|
var ran2 = false;
|
||||||
|
var ran3 = false;
|
||||||
|
var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, string>("EndpointDefaults:Protocols", input),
|
||||||
|
new KeyValuePair<string, string>("Endpoints:End1:Url", "https://*:5001"),
|
||||||
|
}).Build();
|
||||||
|
serverOptions.Configure(config)
|
||||||
|
.Endpoint("End1", opt =>
|
||||||
|
{
|
||||||
|
Assert.True(opt.IsHttps);
|
||||||
|
Assert.NotNull(opt.HttpsOptions.ServerCertificate);
|
||||||
|
Assert.Equal(ClientCertificateMode.RequireCertificate, opt.HttpsOptions.ClientCertificateMode);
|
||||||
|
Assert.Equal(expected, opt.ListenOptions.Protocols);
|
||||||
|
ran1 = true;
|
||||||
|
})
|
||||||
|
.LocalhostEndpoint(5002, opt =>
|
||||||
|
{
|
||||||
|
Assert.Equal(expected, opt.Protocols);
|
||||||
|
ran2 = true;
|
||||||
|
})
|
||||||
|
.Load();
|
||||||
|
serverOptions.ListenAnyIP(0, opt =>
|
||||||
|
{
|
||||||
|
Assert.Equal(expected, opt.Protocols);
|
||||||
|
ran3 = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.True(ranDefault);
|
||||||
|
Assert.True(ran1);
|
||||||
|
Assert.True(ran2);
|
||||||
|
Assert.True(ran3);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("http1", HttpProtocols.Http1)]
|
||||||
|
[InlineData("http2", HttpProtocols.Http2)]
|
||||||
|
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)]
|
||||||
|
public void EndpointConfigSectionCanSetProtocols(string input, HttpProtocols expected)
|
||||||
|
{
|
||||||
|
var serverOptions = CreateServerOptions();
|
||||||
|
var ranDefault = false;
|
||||||
|
serverOptions.ConfigureEndpointDefaults(opt =>
|
||||||
|
{
|
||||||
|
// Kestrel default.
|
||||||
|
Assert.Equal(HttpProtocols.Http1AndHttp2, opt.Protocols);
|
||||||
|
ranDefault = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
serverOptions.ConfigureHttpsDefaults(opt =>
|
||||||
|
{
|
||||||
|
opt.ServerCertificate = new X509Certificate2(TestResources.TestCertificatePath, "testPassword");
|
||||||
|
opt.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
|
||||||
|
});
|
||||||
|
|
||||||
|
var ran1 = false;
|
||||||
|
var ran2 = false;
|
||||||
|
var ran3 = false;
|
||||||
|
var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, string>("Endpoints:End1:Protocols", input),
|
||||||
|
new KeyValuePair<string, string>("Endpoints:End1:Url", "https://*:5001"),
|
||||||
|
}).Build();
|
||||||
|
serverOptions.Configure(config)
|
||||||
|
.Endpoint("End1", opt =>
|
||||||
|
{
|
||||||
|
Assert.True(opt.IsHttps);
|
||||||
|
Assert.NotNull(opt.HttpsOptions.ServerCertificate);
|
||||||
|
Assert.Equal(ClientCertificateMode.RequireCertificate, opt.HttpsOptions.ClientCertificateMode);
|
||||||
|
Assert.Equal(expected, opt.ListenOptions.Protocols);
|
||||||
|
ran1 = true;
|
||||||
|
})
|
||||||
|
.LocalhostEndpoint(5002, opt =>
|
||||||
|
{
|
||||||
|
// Kestrel default.
|
||||||
|
Assert.Equal(HttpProtocols.Http1AndHttp2, opt.Protocols);
|
||||||
|
ran2 = true;
|
||||||
|
})
|
||||||
|
.Load();
|
||||||
|
serverOptions.ListenAnyIP(0, opt =>
|
||||||
|
{
|
||||||
|
// Kestrel default.
|
||||||
|
Assert.Equal(HttpProtocols.Http1AndHttp2, opt.Protocols);
|
||||||
|
ran3 = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.True(ranDefault);
|
||||||
|
Assert.True(ran1);
|
||||||
|
Assert.True(ran2);
|
||||||
|
Assert.True(ran3);
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetCertificatePath()
|
private static string GetCertificatePath()
|
||||||
{
|
{
|
||||||
var appData = Environment.GetEnvironmentVariable("APPDATA");
|
var appData = Environment.GetEnvironmentVariable("APPDATA");
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -770,6 +771,36 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("http1", HttpProtocols.Http1)]
|
||||||
|
[InlineData("http2", HttpProtocols.Http2)]
|
||||||
|
[InlineData("http1AndHttp2", HttpProtocols.Http1AndHttp2)]
|
||||||
|
public void EndpointDefaultsConfig_CanSetProtocolForUrlsConfig(string input, HttpProtocols expected)
|
||||||
|
{
|
||||||
|
KestrelServerOptions capturedOptions = null;
|
||||||
|
var hostBuilder = TransportSelector.GetWebHostBuilder()
|
||||||
|
.UseKestrel(options =>
|
||||||
|
{
|
||||||
|
var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, string>("EndpointDefaults:Protocols", input),
|
||||||
|
}).Build();
|
||||||
|
options.Configure(config);
|
||||||
|
|
||||||
|
capturedOptions = options;
|
||||||
|
})
|
||||||
|
.ConfigureServices(AddTestLogging)
|
||||||
|
.UseUrls("http://127.0.0.1:0")
|
||||||
|
.Configure(ConfigureEchoAddress);
|
||||||
|
|
||||||
|
using (var host = hostBuilder.Build())
|
||||||
|
{
|
||||||
|
host.Start();
|
||||||
|
Assert.Single(capturedOptions.ListenOptions);
|
||||||
|
Assert.Equal(expected, capturedOptions.ListenOptions[0].Protocols);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ThrowsWhenBindingLocalhostToAddressInUse(AddressFamily addressFamily)
|
private void ThrowsWhenBindingLocalhostToAddressInUse(AddressFamily addressFamily)
|
||||||
{
|
{
|
||||||
TestApplicationErrorLogger.IgnoredExceptions.Add(typeof(IOException));
|
TestApplicationErrorLogger.IgnoredExceptions.Add(typeof(IOException));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue