首页 > 解决方案 > 在哪里实例化处理 .NET Core 中的服务事件的类?

问题描述

我遇到的问题是关于设计和结构方法,当在 ASP.NET Core 中需要处理服务事件时,我应该在哪里实例化一个这样做的类/接口?例如,我可以为 MyClass 注册一个作用域,该作用域将通过构造函数注入 MyService ,但然后又将这个 MyClass 放在哪里?

我创建了一个服务并将其注册为单例范围,该服务正在运行。

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddEntityFrameworkSqlServer()
            .AddDbContext<Senseflow.Database.SolutionModuleContext>(opts => opts.UseSqlServer
            (Configuration.GetConnectionString("Database")));

        services.Configure<MQTTConfig>(Configuration.GetSection("MQTT"))
            .AddSingleton<Microsoft.Extensions.Hosting.IHostedService, MQTTService>();

        services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

        var container = ContainerConfig.Build();
        container.Populate(services);
        AppContainer = container.Build();

        return new AutofacServiceProvider(AppContainer);
    }

现在,您可以看到 MQTTService 已注册并正在运行。我应该采取什么方法来注册可以处理由 MQTTService 触发的“EventX”的 MyClass?以及在哪里实例化/注入它?

标签: c#.netasp.net-core

解决方案


你的是一个网络应用程序。通常,类是为了响应 Web 请求而实例化的。当应用程序收到请求时,它会创建一个控制器,然后如果其他类被注入到控制器中,它会创建这些类,依此类推。

这使得它不清楚如何响应来自MQTTService适合的事件,因为您的控制器正在响应 Web 请求,而不是来自MQTTService.

如果应用程序的目的只是响应来自MQTTService. 您可以在 Web 应用程序中执行相同的操作:

首先,定义响应事件的类,注入MQTTService其中并分配事件处理程序。顺便说一句,我假设您正在使用此页面上的代码:

public class MqttServiceEventListener // first name that popped into my head
{
    private readonly MQTTService _mqttService;

    public MqttServiceEventListener(MQTTService mqttService)
    {
        _mqttService = mqttService;

        // add event handlers
    }
}

ConfigureServices. 这是因为您可能希望将处理事件所需的其他依赖项注入到此类中。只要所有内容都注册了,IServiceCollection您就可以从容器中解析整个类。

接下来,您将需要一个MqttServiceEventListener. 它可以由静态类或 t 拥有,但如果它不会被实例化以响应 Web 请求,那么另一个解决方案就是在启动时创建一个实例并让它监听事件。有几种方法可以做到这一点,并且偏好会有所不同。

你可以这样做:

public static class MqttServiceEventListenerExtensions
{
    private static MqttServiceEventListener _eventListener;

    public static void UseMqttServiceEventListener(this IApplicationBuilder app)
    {
        if (_eventListener == null) return; //or throw an InvalidOperationException

        _eventListener = app.ApplicationServices.GetService<MqttServiceEventListener>();
    }
}

现在,在 中Startup.Configure,调用它:

app.UseMqttServiceEventListener();

对此有一个很大的警告是,我不知道您的事件侦听器的生命周期需要是什么,或者它的依赖项的生命周期需要是什么。使用像这样的单个实例可能就是您所需要的,或者它可能会导致问题。

如果注册为单例的类在您的场景中不好:

一个类似的选项可能是跳过事件侦听器的静态实例,只注册一个处理事件的类(或者甚至是不同的类来处理不同的事件),如下所示:

public class MqttServiceEventHandler
{
    public void MqttServerClientConnected(object sender, MqttClientConnectedEventArgs e)
    {
        // handle the event
    }
}

IServiceProvider同样的事情 - 向容器注册事件处理程序。如果它们需要更短的生命周期,您可以将它们设为瞬态。

现在,在您的扩展类中,改为执行以下操作:

public static class MqttServiceEventListenerExtensions
{
    private static MQTTService _mqttService; // likely unnecessary

    public static void UseMqttServiceEventListener(this IApplicationBuilder app)
    {
        var serviceProvider = app.ApplicationServices;

        // This is registered as a singleton, so there's only going to be on instance.

        _mqttService = serviceProvider.GetService<MQTTService>();

        // Add event handlers that resolve the needed class and pass the
        // event to it.

        _mqttService.ClientDisconnected += (sender, eventArgs) =>
        {
            var handler = serviceProvider.GetService<MqttServiceEventHandler>();
            handler.MqttServerClientConnected(sender, eventArgs);
        };
    }
}

同样的事情Startup.Configureapp.UseMqttServiceEventListener();

首先,您要解析MQTTService,将其注册为单例,因此服务提供者将始终返回相同的实例。是否需要在类中实际存储对它的引用是有争议的。您始终可以删除_mqttService,将其解析MQTTService为局部变量,并向其中添加事件处理程序。

接下来,您将添加事件处理程序来解析处理事件所需的类,然后将事件参数传递给它。同样,这需要预先注册所有这些类。但这很好,因为这意味着您可以在需要时将更多依赖项注入这些类,依此类推。

如果一个类太大,它还使您可以灵活地创建不同的类来处理不同的事件。扩展方法可以解析一个类来处理一个事件,另一个类来处理另一个事件,等等。并且生命周期不是问题,因为事件处理程序类在您需要它们之前不会被解析。根据您的需要,它们可以是临时的或单例的。


推荐阅读