确定端口Kestrel绑定到

Reg*_*ent 6 kestrel-http-server asp.net-core asp.net-core-2.0

我正在使用ASP.NET Core空(web)模板编写一个简单的ASP.NET Core服务。

默认情况下,它绑定到端口5000,但我希望它绑定到系统上的随机可用端口。

我可以通过修改BuildWebHost为:

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .UseUrls("http://*:0") // This enables binding to random port
            .Build();
Run Code Online (Sandbox Code Playgroud)

它绑定到随机端口,但是如何从应用程序中确定我正在侦听哪个端口?

Cod*_*ler 6

可以通过IServerAddressesFeature.Addresses集合访问 ASP.NET Core 应用程序的托管地址。

主要挑战是在正确的时间调用将分析此集合的代码。实际的端口绑定在IWebHost.Run()被调用时发生(来自Program.Main())。因此您还不能在Startup.Configure()方法中访问托管地址,因为在此阶段尚未分配端口。并且您在调用 后失去控制IWebHost.Run(),因为该调用在 Web 主机关闭之前不会返回。

在我看来,分析绑定端口最合适的方法是通过IHostedService 的实现。这是工作示例:

public class GetBindingHostedService : IHostedService
{
    public static IServerAddressesFeature ServerAddresses { get; set; }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        var address = ServerAddresses.Addresses.Single();
        var match = Regex.Match(address, @"^.+:(\d+)$");
        if (match.Success)
        {
            int port = Int32.Parse(match.Groups[1].Value);
            Console.WriteLine($"Bound port is {port}");
        }

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

Startup课堂上:

public class Startup
{

    //  ...

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddSingleton<IHostedService, GetBindingHostedService>();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseMvc();

        GetBindingHostedService.ServerAddresses = app.ServerFeatures.Get<IServerAddressesFeature>();
    }
}
Run Code Online (Sandbox Code Playgroud)

的实例IServerAddressesFeature通过GetBindingHostedService. 我没有看到其他方式如何将它注入到服务中。

GitHub 上的示例项目

总的来说,我对这样的解决方案并不满意。它完成了这项工作,但它似乎比它应该的要复杂得多。

  • 为我工作。但是我很惊讶你需要通过这么多圈来获得这样的基本信息。 (5认同)

Pre*_*n S 5

您可以拨打电话IWebHost.Start()代替这里的IWebHost.Run()建议。这将允许您继续执行方法,以便从中获取所需的信息。请记住,您的应用程序将立即关闭,除非您明确告诉它不要使用。MainIWebHost.ServerFeaturesIWebHost.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();
    }
Run Code Online (Sandbox Code Playgroud)