我的问题很简单,我想在IHostedService
中访问服务器URL。
我找不到方法去实现它。因为没有请求,所以我不能使用IHttpContextAccessor
。
IServer
的特性属性没有任何地址,我无计可施。
我不想在配置中硬编码服务器的URL。
我正在运行的.NET Core版本是3.0。
我的问题很简单,我想在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
}
}
IHostApplicationLifetime
的对象,它允许您钩入ApplicationStarted
生命周期事件。
奇怪的是,ApplicationStarted
是一个CancellationToken
,而不是C#事件。
您可以使用取消令牌上的Register
方法在Web应用程序启动时运行代码。
此时,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
,在这种情况下,我认为它的效果更好,因为您可以创建自己的任务并等待它。以下是一个示例: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
中从 IServerAddressesFeature
获取地址,因为 IHostedService
在 Server
之前启动。请参见此 issue。
为了在您的发生变化的是调用 IHostedService 的顺序。这在 3.0 中被移动了,但仍然在 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>());
}
IHttpContextAccessor
注入到你的类中... 如果你能提供更多关于何时何地需要这些信息的上下文,我认为我们可以更好地帮助你。 - Heretic Monkey