首页 > 解决方案 > 防止 Kestrel 在端口使用时崩溃

问题描述

我怀疑这是我正在尝试做的一件“奇怪”的事情,但是......我已经将 Kestrel 配置为监听多个端口。问题是,有时,其中一个端口已经在使用中。

这目前导致我的应用程序崩溃。

我希望看到的行为是它侦听我指定的所有可用端口。但我无法找到有关该主题的任何示例/文档。

例如,我可以将其配置为侦听 90、91、92、93……但如果端口 91 已在使用中,我希望它仅侦听端口 90、92、93。我不介意它是否抛出异常或记录错误,只要我可以让它继续。我想避免“先检查”然后更改配置,因为这感觉就像等待发生的竞争条件)

谁能告诉我如何让 Kestrel 仅在可用端口上启动?

标签: asp.net-core.net-corekestrel-http-server

解决方案


您可以使用端口 0这样,Kestrel在运行时动态绑定到可用端口,如下所述:

private static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .UseUrls("http://*:0");

此外,您可以确定 Kestrel 在运行时实际绑定的端口,如下所示:

public static void Main(string[] args)
{
    IWebHost webHost = CreateWebHostBuilder(args).Build();

    webHost.Start();

    string address = webHost.ServerFeatures
        .Get<IServerAddressesFeature>()
        .Addresses
        .First();

    int port = int.Parse(address.Split(':')[4]);
}

更新:

如果指定的端口未被其他应用程序使用,您可以检查端口可用性并启动项目:

private static string[] GenerateUrls(IEnumerable<int> ports)
{
    return ports.Select(port => $"http://localhost:{port}").ToArray();
}

private static IEnumerable<int> GetAvailablePorts(IEnumerable<int> ports)
{
    IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
    IPEndPoint[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpListeners();

    IEnumerable<int> allActivePorts = tcpConnInfoArray.Select(endpoint => endpoint.Port).ToList();

    return ports.Where(port => !allActivePorts.Contains(port)).ToList();
}

最终结果将是这样的:

public static void Main(string[] args)
{
    CreateWebHostBuilder(args).Build().Run();
}

private static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
    IWebHostBuilder webHost = WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>();

    int[] ports = { 5000, 5050, 8585 };

    IEnumerable<int> availablePorts = GetAvailablePorts(ports).ToList();
    if (!availablePorts.Any())
        throw new InvalidOperationException("There are no active ports available to start the project.");

    webHost.UseUrls(GenerateUrls(availablePorts));

    return webHost;
}

推荐阅读