我在IIS 10.0下运行ASP.NET Core微服务,我正在尝试在启动时向Consul注册它。我在Startup.ConfigureServices中添加了以下代码:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<IHostedService, ConsulHostedService>();
services.Configure<ConsulConfig>(Configuration.GetSection("consulConfig"));
services.AddSingleton<IConsulClient>(p => new ConsulClient(ConfigOverride));
}
private void ConfigOverride(ConsulClientConfiguration config)
{
var address = Configuration["ConsulConfig:ConsulAddress"];
config.Address = new Uri(address);
}
这在作为独立项目运行时工作正常,但在IIS中运行时,在我点击“浏览”之前,服务不会自行注册。 According to Cesar de la Torre,ConsulHostedService.Startup应该在应用程序启动时调用,但这似乎不会发生。
考虑到这个问题在单独运行时似乎不是一个问题,这似乎是一个IIS问题,但我无法弄清楚哪个,只需要切换的设置。我发现的唯一一个似乎相关的是网站高级设置中的“Preload Enabled”,但没有成功。
如果我的代码中有东西我缺少,这里是完整的Startup类:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<IHostedService, ConsulHostedService>();
services.Configure<ConsulConfig>(Configuration.GetSection("consulConfig"));
services.AddSingleton<IConsulClient>(p => new ConsulClient(ConfigOverride));
}
private void ConfigOverride(ConsulClientConfiguration config)
{
var address = Configuration["ConsulConfig:ConsulAddress"];
config.Address = new Uri(address);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
else
app.UseHsts();
app.UseMvc();
}
}
和ConsulHostedService:
public class ConsulHostedService : IHostedService
{
private CancellationTokenSource _cts;
private readonly IConsulClient _consulClient;
private readonly IOptions<ConsulConfig> _consulConfig;
private readonly ILogger<ConsulHostedService> _logger;
private readonly IServer _server;
private string _registrationId;
public ConsulHostedService(IConsulClient consulClient, IOptions<ConsulConfig> consulConfig,
ILogger<ConsulHostedService> logger, IServer server)
{
_consulClient = consulClient;
_consulConfig = consulConfig;
_logger = logger;
_server = server;
}
public async Task StartAsync(CancellationToken token)
{
_cts = CancellationTokenSource.CreateLinkedTokenSource(token);
var uri = GetServerAddress();
_registrationId = $"{_consulConfig.Value.ServiceId}-{_consulConfig.Value.ServicePort}";
AgentServiceRegistration registration = MakeConsulRegistration(uri);
await Register(registration);
}
private Uri GetServerAddress()
{
var features = _server.Features;
var addresses = features.Get<IServerAddressesFeature>();
var address = addresses.Addresses.First();
return new Uri(address);
}
private AgentServiceRegistration MakeConsulRegistration(Uri uri)
{
return new AgentServiceRegistration()
{
ID = _registrationId,
Name = _consulConfig.Value.ServiceName,
Address = $"http://localhost",
Port = _consulConfig.Value.ServicePort,
Tags = _consulConfig.Value.ServiceTags,
Check = MakeConsulCheck(uri)
};
}
private AgentServiceCheck MakeConsulCheck(Uri uri)
{
return new AgentServiceCheck()
{
HTTP = $"http://localhost:{_consulConfig.Value.ServicePort}/api/meta/status",
Timeout = TimeSpan.FromSeconds(3),
Interval = TimeSpan.FromSeconds(10)
};
}
private async Task Register(AgentServiceRegistration registration)
{
_logger.LogInformation("Registering in Consul");
await _consulClient.Agent.ServiceDeregister(registration.ID, _cts.Token);
await _consulClient.Agent.ServiceRegister(registration, _cts.Token);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
_cts.Cancel();
_logger.LogInformation("Deregistering from Consul");
try
{
await _consulClient.Agent.ServiceDeregister(_registrationId, cancellationToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Deregistration failed");
}
}
}
为了warm up
您的微服务,您可以将Start Mode
设置为AlwaysRunning
。模式细节:How do I get a .Net Core website hosted in IIS to start immediately?
但听起来你需要自己照顾first request
作为部署过程的最后一步,因为你提到客户的“自然请求”可以用作warm up
。
注意:一般情况下,当应用程序根据ConfigureServices
启动时,运行时会调用Configure
和documentation。您也可以尝试通过配置没有Startup
类的微服务来解决问题 - 通过HostBuilder
(类似于WebHostBuilder
) - 检查Using HostBuilder and the Generic Host in .NET Core Microservices。还可以看看IHostedService
方法,它可能更符合您的需求:Implementing IHostedService in ASP.NET Core 2.0