我如何从单例服务调用方法以在应用程序的整个生命周期中运行

时间:2018-07-31 14:38:03

标签: c# asp.net-core apache-kafka

我已经在Net Core中实现了Kafka事件总线作为单例服务。服务本身在Startup.cs中使用Autofac进行配置。该服务具有Listen()方法:

public void Listen()
{
    using(var consumer = new Consumer<Null, string>(_config, null, new StringDeserializer(Encoding.UTF8)))
    {
        consumer.Subscribe(new string[] { "business-write-topic" });

        consumer.OnMessage += (_, msg) =>
        {
            Console.WriteLine($"Topic: {msg.Topic} Partition: {msg.Partition} Offset: {msg.Offset} {msg.Value}");
            consumer.CommitAsync(msg);
        };

        while (true)
        {
            consumer.Poll(100);
        }
    }
}

我的理解是,为了使此方法在应用程序的生命周期内不断侦听消息,我必须通过某种方式使ServiceProvider与主机关联,然后从Web主机在Program.cs中对其进行调用。服务实例,并调用方法。

我已将我的Program.cs从默认的Net Core 2.1模板配置为以下内容:

public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateWebHost(args);
        host.Run();
    }

    public static IWebHost CreateWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
}

除了可以使用主机之外,我还可以通过某种方式访问​​服务,我不知道从这里去哪里。我搜索了类似的问题并阅读了官方文档,但似乎无法弄清楚如何访问该服务,以便可以调用Listen()方法。

这是实现目标的“必修”方法吗?如果是这样,我该如何进行?如果不是-也就是说-如果通常以另一种方式完成这种任务,我该怎么办?

2 个答案:

答案 0 :(得分:2)

我建议使用IHostedService。 IHostedService实现注册为单例,并且一直运行到服务器关闭为止。

创建此基类

public abstract class HostedService : IHostedService
{
    private Task executingTask;
    private CancellationTokenSource cancellationTokenSource;

    public Task StartAsync(CancellationToken cancellationToken)
    {
        this.cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

        this.executingTask = this.ExecuteAsync(this.cancellationTokenSource.Token);

        return this.executingTask.IsCompleted ? this.executingTask : Task.CompletedTask;
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        if (this.executingTask == null)
        {
            return;
        }

        this.cancellationTokenSource.Cancel();

        await Task.WhenAny(this.executingTask, Task.Delay(-1, cancellationToken));
    }

    protected abstract Task ExecuteAsync(CancellationToken cancellationToken);
}

然后创建消费者主机

public class ConsumerHost : HostedService
{
    protected override async Task ExecuteAsync(CancellationToken cancellationToken)
    {
        using (var consumer = new Consumer<Null, string>(_config, null, new StringDeserializer(Encoding.UTF8)))
        {
            consumer.Subscribe(new string[] {"business-write-topic"});

            consumer.OnMessage += (_, msg) =>
            {
                Console.WriteLine(
                    $"Topic: {msg.Topic} Partition: {msg.Partition} Offset: {msg.Offset} {msg.Value}");
                consumer.CommitAsync(msg);
            };

            while (!cancellationToken.IsCancellationRequested) // will make sure to stop if the application is being shut down!
            {
                consumer.Poll(100);
                await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);
            }
        }
    }
}

现在在您的启动类中的ConfigureService方法中添加单例

public void ConfigureServices(IServiceCollection services)
{
   services.AddSingleton<IHostedService, ConsumerHost>();
}

此服务现在将在网络主机完成构建时启动,并在您关闭服务器时停止。无需手动触发它,让虚拟主机为您完成。

答案 1 :(得分:1)

我认为BackgroundService是您所需要的。

public class ListnerBackgroundService : BackgroundService
{
    private readonly ListnerService service;

    public ListnerBackgroundService(ListnerService service)
    {
        this.service = service;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        service.Listen();

        return Task.CompletedTask;
    }
}

并注册:

public void ConfigureServices(IServiceCollection services)
{
   ...
   services.AddSingleton<IHostedService, ListnerBackgroundService>();
   ...
}