简体   繁体   English

如何配置 Kestrel 以使用随机动态端口并在运行时使用 ASP.NET Core 3.1 确定端口?

[英]How do you configure Kestrel to use a random dynamic port and determine the port at run-time with ASP.NET Core 3.1?

With ASP.NET Core 3.0 I have been able to use this IHostedService method ...使用 ASP.NET Core 3.0 我已经能够使用这个IHostedService方法......

Determine port Kestrel binded to 确定绑定到的端口 Kestrel

... to determine Kestrel's dynamic port at run-time. ... 在运行时确定 Kestrel 的动态端口。

IServerAddressesFeature is documented for ASP.NET 3.0 here:此处为 ASP.NET 3.0 记录了IServerAddressesFeature

https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.hosting.server.features.iserveraddressesfeature?view=aspnetcore-3.0 https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.hosting.server.features.iserveraddressesfeature?view=aspnetcore-3.0

But when changing the version to ASP.NET Core 3.1 then the page redirects back to ASP.NET 3.0 with the hint that the document is not available for ASP.NET Core 3.1.但是当将版本更改为 ASP.NET Core 3.1 时,页面会重定向回 ASP.NET 3.0,并提示该文档不可用于 ASP.NET Core 3.1。 Is IServerAddressesFeature no longer working? IServerAddressesFeature不再工作了吗? Using IServerAddressesFeature with ASP.NET Core 3.1 still compiles, but the port in the returned ServerAddresses is always zero.在 ASP.NET Core 3.1 中使用IServerAddressesFeature仍然可以编译,但返回的ServerAddresses的端口始终为零。

Program:程序:

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost().Run();
    }

    public static IWebHost BuildWebHost() =>

        WebHost.CreateDefaultBuilder()
            .UseKestrel()
            .UseUrls("http://127.0.0.1:0") // port zero to use random dynamic port
            .UseStartup<Startup>()
            .Build();
}

Later, when Configure is called ...后来,当Configure被调用时......

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        HostedService.ServerAddresses = app.ServerFeatures.Get<Microsoft.AspNetCore.Hosting.Server.Features.IServerAddressesFeature>();

... the server addresses are assigned to the HostedService.ServerAddresses static variable as in the linked example. ...服务器地址分配给HostedService.ServerAddresses静态变量,如链接示例中所示。 However, ServerAddresses contain only the loopback address with port zero: "http://127.0.0.1:0" .但是, ServerAddresses仅包含端口为零的环回地址: "http://127.0.0.1:0"

Am I overlooking something?我是否忽略了什么? Is there a different, proper way to resolve the problem in v3.1?在 v3.1 中是否有不同的、正确的方法来解决这个问题? How do I configure Kestrel to use a random dynamic port and determine which port it is at run-time (before any controller action takes place) with ASP.NET Core 3.1?在 ASP.NET Core 3.1 中,如何配置 Kestrel 以使用随机动态端口并确定它在运行时(在任何控制器操作发生之前)是哪个端口?

Update更新

Here is an ugly workaround that helps determine the port.这是一个丑陋的解决方法,可帮助确定端口。 It appears that the timing or sequence of dynamic port allocation has changed.动态端口分配的时间或顺序似乎发生了变化。 Returning from the HostedService.StartAsync method and reading the server address a bit later seems to be enough.HostedService.StartAsync方法返回并稍后读取服务器地址似乎就足够了。 Surely there must be a better way?当然一定有更好的方法吗?

        public Task StartAsync(CancellationToken cancellationToken)
        {
            System.Threading.Tasks.Task.Run(async () =>
            {
                int port = 0;
                while (port == 0)
                {
                    await System.Threading.Tasks.Task.Delay(250);
                    var address = ServerAddresses.Addresses.FirstOrDefault();
                    if (string.IsNullOrEmpty(address))
                        continue;
                    // address is always in form http://127.0.0.1:port
                    var pos = address.LastIndexOf(':');
                    if (pos > 0)
                    {
                        var portString = address.Substring(pos + 1);
                        port = int.Parse(portString);
                    }
                }
                // have determined the dynamic port now
            });
            return System.Threading.Tasks.Task.CompletedTask;
        }

The reason the IHostedService method does not work is because .Net Core 3 changed when IHostedServices are executed. IHostedService 方法不起作用的原因是因为在执行 IHostedServices 时 .Net Core 3 发生了变化。 In .Net Core 2, IHostedService was executed after the host starts so the server address information was readily available.在 .Net Core 2 中,IHostedService 在主机启动后执行,因此服务器地址信息很容易获得。 In .Net Core 3, IHostedService runs after the host is built, but before the host starts up and the address is not yet available.在 .Net Core 3 中,IHostedService 在主机构建之后运行,但在主机启动之前且地址尚不可用时运行。 This blog has a nice explanation of what changed. 这个博客很好地解释了发生了什么变化。

The following method of getting the bound address, copied from here , works in both .Net Core 2 & 3.以下获取绑定地址的方法(从此处复制)适用于 .Net Core 2 和 3。

You can call IWebHost.Start() instead of IWebHost.Run() as suggested here .您可以按照此处的建议调用IWebHost.Start()而不是IWebHost.Run() This will allow execution of your Main method to continue so you can get the desired information from IWebHost.ServerFeatures .这将允许您继续执行Main方法,以便您可以从IWebHost.ServerFeatures获取所需的信息。 Just remember, your application will shutdown immediately unless you explicitly tell it not to using IWebHost.WaitForShutdown() .请记住,您的应用程序将立即关闭,除非您明确告诉它不要使用IWebHost.WaitForShutdown()

 public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseStartup<Startup>()
            .UseUrls("http://*:0") // This enables binding to random port
            .Build();

        host.Start();

        foreach(var address in host.ServerFeatures.Get<IServerAddressesFeature>().Addresses)
        {
            var uri = new Uri(address);
            var port = uri.Port;

            Console.WriteLine($"Bound to port: {port}");
        }

        //Tell the host to block the thread just as host.Run() would have.
        host.WaitForShutdown();
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM