diff --git a/KestrelHttpServer.sln b/KestrelHttpServer.sln
index 2fba69b809..3c10b81d05 100644
--- a/KestrelHttpServer.sln
+++ b/KestrelHttpServer.sln
@@ -25,6 +25,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{0EF2AC
test\shared\KestrelTestLoggerFactory.cs = test\shared\KestrelTestLoggerFactory.cs
test\shared\LifetimeNotImplemented.cs = test\shared\LifetimeNotImplemented.cs
test\shared\MockFrameControl.cs = test\shared\MockFrameControl.cs
+ test\shared\MockLogger.cs = test\shared\MockLogger.cs
test\shared\MockSocketOutput.cs = test\shared\MockSocketOutput.cs
test\shared\MockSystemClock.cs = test\shared\MockSystemClock.cs
test\shared\StringExtensions.cs = test\shared\StringExtensions.cs
diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Core/CoreStrings.resx b/src/Microsoft.AspNetCore.Server.Kestrel.Core/CoreStrings.resx
index f1605f6630..03a86be5db 100644
--- a/src/Microsoft.AspNetCore.Server.Kestrel.Core/CoreStrings.resx
+++ b/src/Microsoft.AspNetCore.Server.Kestrel.Core/CoreStrings.resx
@@ -117,6 +117,9 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ Failed to bind to http://[::]:{port} (IPv6Any). Attempting to bind to http://0.0.0.0:{port} instead.
+
Cannot write to response body after connection has been upgraded.
diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Core/Internal/AddressBinder.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Core/Internal/AddressBinder.cs
index e30418727b..d041c3bec0 100644
--- a/src/Microsoft.AspNetCore.Server.Kestrel.Core/Internal/AddressBinder.cs
+++ b/src/Microsoft.AspNetCore.Server.Kestrel.Core/Internal/AddressBinder.cs
@@ -206,6 +206,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
}
catch (Exception ex) when (!(ex is IOException))
{
+ context.Logger.LogDebug(CoreStrings.FormatFallbackToIPv4Any(parsedAddress.Port));
+
// for machines that do not support IPv6
options = new ListenOptions(new IPEndPoint(IPAddress.Any, parsedAddress.Port));
await BindEndpointAsync(options, context).ConfigureAwait(false);
diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Core/Properties/CoreStrings.Designer.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Core/Properties/CoreStrings.Designer.cs
index 0deecaa6d1..c97aefeac9 100644
--- a/src/Microsoft.AspNetCore.Server.Kestrel.Core/Properties/CoreStrings.Designer.cs
+++ b/src/Microsoft.AspNetCore.Server.Kestrel.Core/Properties/CoreStrings.Designer.cs
@@ -10,6 +10,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNetCore.Server.Kestrel.Core.CoreStrings", typeof(CoreStrings).GetTypeInfo().Assembly);
+ ///
+ /// Failed to bind to http://[::]:{port} (IPv6Any). Attempting to bind to http://0.0.0.0:{port} instead.
+ ///
+ internal static string FallbackToIPv4Any
+ {
+ get => GetString("FallbackToIPv4Any");
+ }
+
+ ///
+ /// Failed to bind to http://[::]:{port} (IPv6Any). Attempting to bind to http://0.0.0.0:{port} instead.
+ ///
+ internal static string FormatFallbackToIPv4Any(object port)
+ => string.Format(CultureInfo.CurrentCulture, GetString("FallbackToIPv4Any", "port"), port);
+
///
/// Cannot write to response body after connection has been upgraded.
///
diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests/AddressBinderTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests/AddressBinderTests.cs
index 762e3191f1..655bbaea25 100644
--- a/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests/AddressBinderTests.cs
+++ b/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests/AddressBinderTests.cs
@@ -8,6 +8,7 @@ using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
+using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
@@ -88,6 +89,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
[InlineData("http://contoso.com:80")]
public async Task FallbackToIPv4WhenIPv6AnyBindFails(string address)
{
+ var logger = new MockLogger();
var addresses = new ServerAddressesFeature();
addresses.Addresses.Add(address);
var options = new List();
@@ -97,7 +99,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
await AddressBinder.BindAsync(addresses,
options,
- NullLogger.Instance,
+ logger,
endpoint =>
{
if (endpoint.IPEndPoint.Address == IPAddress.IPv6Any)
@@ -116,6 +118,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Assert.True(ipV4Attempt, "Should have attempted to bind to IPAddress.Any");
Assert.True(ipV6Attempt, "Should have attempted to bind to IPAddress.IPv6Any");
+ Assert.Contains(logger.Messages, f => f.Equals(CoreStrings.FormatFallbackToIPv4Any(80)));
}
}
}
diff --git a/test/shared/MockLogger.cs b/test/shared/MockLogger.cs
new file mode 100644
index 0000000000..677d0687de
--- /dev/null
+++ b/test/shared/MockLogger.cs
@@ -0,0 +1,28 @@
+// 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.Collections.Generic;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions.Internal;
+
+namespace Microsoft.AspNetCore.Testing
+{
+ public class MockLogger : ILogger
+ {
+ private List _messages = new List();
+
+ public IDisposable BeginScope(TState state)
+ => NullScope.Instance;
+
+ public bool IsEnabled(LogLevel logLevel)
+ => true;
+
+ public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
+ {
+ _messages.Add(formatter(state, exception));
+ }
+
+ public IReadOnlyList Messages => _messages;
+ }
+}