.NET Core 3.0 IHostedService 访问 Web 服务器 URL - 方案、主机、端口等
.NET Core 3.0 IHostedService access web server URL - scheme, host, port etc
我遇到的问题很简单。我想在我的 IHostedService
.
中访问服务器 URL
我找不到办法。那里没有任何请求,所以我不能使用 IHttpContextAccessor
.
IServer
功能 属性 没有任何地址,我没有选择。
我不想在配置中对服务器的 URL 进行硬编码。
我运行的.NET core版本是3.0.
您可以使用 Startup.cs
中的依赖注入框架注册您的托管服务:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHostedService, MyHostedService>();
}
然后,您可以将 IServer
注入托管服务并使用 IServerAddressesFeature
:
获取地址
public class MyHostedService : IHostedService
{
private readonly IServer _server;
public MyHostedService(IServer server)
{
_server = server;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
var features = _server.Features;
var addresses = features.Get<IServerAddressesFeature>();
var address = addresses.Addresses.FirstOrDefault(); // = http://localhost:5000
}
}
在完全启动服务器之前,您无法从服务器获取 address/url。
如果您需要本地主机地址,请从 ./Properties/launchSettings.json
中查找(以编程方式或其他方式)。
如果您在现场环境中需要地址,则必须等待服务器加载。
对于 Asp.Net Core 3.1,您无法在 IHostedService
中从 IServerAddressesFeature
获取地址,因为 IHostedService
在 Server
之前启动。看到这个 issue.
What has changed is the ordering of IHostedService's being called. This was moved up in 3.0, but still runs after Configure.
要在您的 IHostedService
中获取地址,您可以将它们设为 运行 在 Startup
之后。我发现其中一种方法是在 Program.cs
中注册您的服务,详情请参阅 here。
public class Program
{
public static void Main(string[] args)
=> CreateHostBuilder(args).Build().Run();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => // The GenericWebHostSevice is registered here
{
webBuilder.UseStartup<Startup>();
})
// Register your HostedService AFTER ConfigureWebHostDefaults
.ConfigureServices(
services => services.AddHostedService<ProgramHostedService>());
}
在 .NET 6 中,我找不到影响托管服务启动顺序的方法,所以我不得不寻找另一种方法。
幸运的是,有 IHostApplicationLifetime
可以让您连接到 ApplicationStarted
生命周期事件。
奇怪的是,ApplicationStarted
是一个 CancellationToken
,而不是 C# 事件。
当 Web 应用程序启动时,您可以在取消令牌上使用 Register
方法来 运行 代码。
此时,URL 将填充到 IServer
对象上。
这里有一个 IHostedService
的例子:
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
public class MyHostedService : IHostedService
{
private readonly IServer _server;
private readonly IHostApplicationLifetime _hostApplicationLifetime;
public MyHostedService(IServer server, IHostApplicationLifetime hostApplicationLifetime)
{
_server = server;
_hostApplicationLifetime = hostApplicationLifetime;
}
public Task StartAsync(CancellationToken cancellationToken)
{
Console.WriteLine($"Address before application has started: {GetAddress()}");
_hostApplicationLifetime.ApplicationStarted.Register(
() => Console.WriteLine($"Address after application has started: {GetAddress()}"));
return Task.CompletedTask;
}
private string GetAddress()
{
var features = _server.Features;
var addresses = features.Get<IServerAddressesFeature>();
var address = addresses.Addresses.FirstOrDefault();
return address;
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
当您 运行 应用程序时,输出将如下所示:
Address before application has started:
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7012
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5012
Address after application has started: https://localhost:7012
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: C:\Users\niels\RiderProjects\UrlsInHostedService\UrlsInHostedService\
从输出中可以看出,托管服务启动时 IServer
上没有地址,但随后服务器启动,ApplicationStarted
取消令牌被取消,这触发了回调,现在 IServer
.
上有 URL
就我而言,我实际上 BackgroundService
需要它,在这种情况下,IMO 效果更好,因为您可以创建自己的任务并 await
它。这是一个例子:
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
public class MyBackgroundService : BackgroundService
{
private readonly IServer _server;
private readonly IHostApplicationLifetime _hostApplicationLifetime;
public MyBackgroundService(IServer server, IHostApplicationLifetime hostApplicationLifetime)
{
_server = server;
_hostApplicationLifetime = hostApplicationLifetime;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Console.WriteLine($"Address before application has started: {GetAddress()}");
await WaitForApplicationStarted();
Console.WriteLine($"Address after application has started: {GetAddress()}");
}
private string GetAddress()
{
var features = _server.Features;
var addresses = features.Get<IServerAddressesFeature>();
var address = addresses.Addresses.FirstOrDefault();
return address;
}
private Task WaitForApplicationStarted()
{
var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
_hostApplicationLifetime.ApplicationStarted.Register(() => completionSource.TrySetResult());
return completionSource.Task;
}
}
结果与托管服务相同,但您必须使用 BackgroundService
和 ExecuteAsync
,这对您的用例可能没有意义。
我遇到的问题很简单。我想在我的 IHostedService
.
我找不到办法。那里没有任何请求,所以我不能使用 IHttpContextAccessor
.
IServer
功能 属性 没有任何地址,我没有选择。
我不想在配置中对服务器的 URL 进行硬编码。
我运行的.NET core版本是3.0.
您可以使用 Startup.cs
中的依赖注入框架注册您的托管服务:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHostedService, MyHostedService>();
}
然后,您可以将 IServer
注入托管服务并使用 IServerAddressesFeature
:
public class MyHostedService : IHostedService
{
private readonly IServer _server;
public MyHostedService(IServer server)
{
_server = server;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
var features = _server.Features;
var addresses = features.Get<IServerAddressesFeature>();
var address = addresses.Addresses.FirstOrDefault(); // = http://localhost:5000
}
}
在完全启动服务器之前,您无法从服务器获取 address/url。
如果您需要本地主机地址,请从 ./Properties/launchSettings.json
中查找(以编程方式或其他方式)。
如果您在现场环境中需要地址,则必须等待服务器加载。
对于 Asp.Net Core 3.1,您无法在 IHostedService
中从 IServerAddressesFeature
获取地址,因为 IHostedService
在 Server
之前启动。看到这个 issue.
What has changed is the ordering of IHostedService's being called. This was moved up in 3.0, but still runs after Configure.
要在您的 IHostedService
中获取地址,您可以将它们设为 运行 在 Startup
之后。我发现其中一种方法是在 Program.cs
中注册您的服务,详情请参阅 here。
public class Program
{
public static void Main(string[] args)
=> CreateHostBuilder(args).Build().Run();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => // The GenericWebHostSevice is registered here
{
webBuilder.UseStartup<Startup>();
})
// Register your HostedService AFTER ConfigureWebHostDefaults
.ConfigureServices(
services => services.AddHostedService<ProgramHostedService>());
}
在 .NET 6 中,我找不到影响托管服务启动顺序的方法,所以我不得不寻找另一种方法。
幸运的是,有 IHostApplicationLifetime
可以让您连接到 ApplicationStarted
生命周期事件。
奇怪的是,ApplicationStarted
是一个 CancellationToken
,而不是 C# 事件。
当 Web 应用程序启动时,您可以在取消令牌上使用 Register
方法来 运行 代码。
此时,URL 将填充到 IServer
对象上。
这里有一个 IHostedService
的例子:
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
public class MyHostedService : IHostedService
{
private readonly IServer _server;
private readonly IHostApplicationLifetime _hostApplicationLifetime;
public MyHostedService(IServer server, IHostApplicationLifetime hostApplicationLifetime)
{
_server = server;
_hostApplicationLifetime = hostApplicationLifetime;
}
public Task StartAsync(CancellationToken cancellationToken)
{
Console.WriteLine($"Address before application has started: {GetAddress()}");
_hostApplicationLifetime.ApplicationStarted.Register(
() => Console.WriteLine($"Address after application has started: {GetAddress()}"));
return Task.CompletedTask;
}
private string GetAddress()
{
var features = _server.Features;
var addresses = features.Get<IServerAddressesFeature>();
var address = addresses.Addresses.FirstOrDefault();
return address;
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
当您 运行 应用程序时,输出将如下所示:
Address before application has started:
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7012
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5012
Address after application has started: https://localhost:7012
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: C:\Users\niels\RiderProjects\UrlsInHostedService\UrlsInHostedService\
从输出中可以看出,托管服务启动时 IServer
上没有地址,但随后服务器启动,ApplicationStarted
取消令牌被取消,这触发了回调,现在 IServer
.
就我而言,我实际上 BackgroundService
需要它,在这种情况下,IMO 效果更好,因为您可以创建自己的任务并 await
它。这是一个例子:
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
public class MyBackgroundService : BackgroundService
{
private readonly IServer _server;
private readonly IHostApplicationLifetime _hostApplicationLifetime;
public MyBackgroundService(IServer server, IHostApplicationLifetime hostApplicationLifetime)
{
_server = server;
_hostApplicationLifetime = hostApplicationLifetime;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Console.WriteLine($"Address before application has started: {GetAddress()}");
await WaitForApplicationStarted();
Console.WriteLine($"Address after application has started: {GetAddress()}");
}
private string GetAddress()
{
var features = _server.Features;
var addresses = features.Get<IServerAddressesFeature>();
var address = addresses.Addresses.FirstOrDefault();
return address;
}
private Task WaitForApplicationStarted()
{
var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
_hostApplicationLifetime.ApplicationStarted.Register(() => completionSource.TrySetResult());
return completionSource.Task;
}
}
结果与托管服务相同,但您必须使用 BackgroundService
和 ExecuteAsync
,这对您的用例可能没有意义。