我如何从单例服务调用方法以在整个应用程序生命周期中运行 [英] How do i call a method from a singleton service to run throughout the application lifetime

查看:26
本文介绍了我如何从单例服务调用方法以在整个应用程序生命周期中运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have implemented a Kafka event bus as a singleton service in Net Core. The service itself is configured with Autofac in Startup.cs. The service has a Listen() method:

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 中调用它,然后检索一个服务的实例,并调用方法.

My understanding is that in order for this method to constantly listen for messages during the lifetime of the application, i have to call it in Program.cs from the web host by somehow getting the ServiceProvider associated with the host, then retrieving an instance of the service, and calling the method.

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

I have configured my Program.cs from the default Net Core 2.1 template to the following:

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() 方法.

Beyond having the host available so i can somehow access the services, i don't know where to go from here. I have searched for similar questions and read around in the official docs but i can't seem to figure out how to access the service so that i can call the Listen() method.

这是实现我的目标的首选"方式吗?如果是这样,我该如何进行?如果不是 - 也就是说 - 如果这种任务通常以另一种方式完成,我该怎么做?

Is this the "go-to" way of accomplishing my goal? If so, how do i proceed? And if not - that is - if this kind of task is commonly accomplished in another way, how do i go about it?

推荐答案

下面的答案仍然完全有效.微软提供了一个名为 BackgroundService 的基类,可以在你只需要实现 ExecuteAsync(CancellationTokentoppingToken) 而不是 IHostedService 的整个接口的地方使用.您可以在此处找到它.为此,您需要安装包 Microsoft.Extensions.Hosting.

The answer below is still perfectly valid. There is a base-class called BackgroundService provided by Microsoft that can be used where you only need to implement ExecuteAsync(CancellationToken stoppingToken) rather than the whole interface of IHostedService. You can find it here. For that you will need to install the package Microsoft.Extensions.Hosting.

上一个仍然有效的答案:我建议使用 IHostedService.IHostedService 实现注册为单例,它们一直运行,直到服务器关闭.

Previous and still valid answer: I would suggest to use IHostedService. IHostedService implementations are registered as singletons and they run the whole time until the server shuts down.

创建这个基类

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 方法的启动类中添加单例

Now in your startup-class in the ConfigureService method add the singleton

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

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

This service will now kick in when the webhost finished building and stop when you shutdown the server. No need to manually trigger it, let the webhost do it for you.

这篇关于我如何从单例服务调用方法以在整个应用程序生命周期中运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆