从IIS运行时,服务未向Consul注册

问题描述 投票:0回答:1

我在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");
        }
    }
}
iis asp.net-core consul iis-10
1个回答
0
投票

为了warm up您的微服务,您可以将Start Mode设置为AlwaysRunning。模式细节:How do I get a .Net Core website hosted in IIS to start immediately?

但听起来你需要自己照顾first request作为部署过程的最后一步,因为你提到客户的“自然请求”可以用作warm up

注意:一般情况下,当应用程序根据ConfigureServices启动时,运行时会调用Configuredocumentation。您也可以尝试通过配置没有Startup类的微服务来解决问题 - 通过HostBuilder(类似于WebHostBuilder) - 检查Using HostBuilder and the Generic Host in .NET Core Microservices。还可以看看IHostedService方法,它可能更符合您的需求:Implementing IHostedService in ASP.NET Core 2.0

© www.soinside.com 2019 - 2024. All rights reserved.