确定 Kestrel 绑定到的端口
Determine port Kestrel binded to
我正在使用 ASP.NET 核心空 (web
) 模板编写一个简单的 ASP.NET 核心服务。
默认情况下,它绑定到端口 5000,但我希望它绑定到系统上的随机可用端口。
我可以通过将 BuildWebHost
修改为:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseUrls("http://*:0") // This enables binding to random port
.Build();
它绑定到一个随机端口,但我如何从应用程序中确定我正在监听哪个端口?
可以通过 IServerAddressesFeature.Addresses
集合访问 ASP.NET 核心应用程序的托管地址。
主要挑战是在正确的时间调用将分析此集合的代码。实际的端口绑定发生在调用 IWebHost.Run()
时(从 Program.Main()
)。因此,您还不能在 Startup.Configure()
方法中访问托管地址,因为在此阶段尚未分配端口。你在调用 IWebHost.Run()
后失去了控制,因为这个调用不会 return 直到网络主机关闭。
在我看来,分析绑定端口最合适的方法是通过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;
}
}
在Startup
class:
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>();
}
}
IServerAddressesFeature
的实例在 GetBindingHostedService
中通过丑陋的静态 属性 传递。我没有看到其他方式如何将它注入服务。
总的来说,我对这样的解决方案不满意。它完成了工作,但它似乎比它应该的要复杂得多。
您可以调用 IWebHost.Start()
而不是建议的 IWebHost.Run()
here。这将允许您的 Main
方法继续执行,以便您可以从 IWebHost.ServerFeatures
获得所需的信息。请记住,除非您明确告诉它不要使用 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();
}
我正在使用 ASP.NET 核心空 (web
) 模板编写一个简单的 ASP.NET 核心服务。
默认情况下,它绑定到端口 5000,但我希望它绑定到系统上的随机可用端口。
我可以通过将 BuildWebHost
修改为:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseUrls("http://*:0") // This enables binding to random port
.Build();
它绑定到一个随机端口,但我如何从应用程序中确定我正在监听哪个端口?
可以通过 IServerAddressesFeature.Addresses
集合访问 ASP.NET 核心应用程序的托管地址。
主要挑战是在正确的时间调用将分析此集合的代码。实际的端口绑定发生在调用 IWebHost.Run()
时(从 Program.Main()
)。因此,您还不能在 Startup.Configure()
方法中访问托管地址,因为在此阶段尚未分配端口。你在调用 IWebHost.Run()
后失去了控制,因为这个调用不会 return 直到网络主机关闭。
在我看来,分析绑定端口最合适的方法是通过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;
}
}
在Startup
class:
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>();
}
}
IServerAddressesFeature
的实例在 GetBindingHostedService
中通过丑陋的静态 属性 传递。我没有看到其他方式如何将它注入服务。
总的来说,我对这样的解决方案不满意。它完成了工作,但它似乎比它应该的要复杂得多。
您可以调用 IWebHost.Start()
而不是建议的 IWebHost.Run()
here。这将允许您的 Main
方法继续执行,以便您可以从 IWebHost.ServerFeatures
获得所需的信息。请记住,除非您明确告诉它不要使用 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();
}