Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Net核心:DI和事件_C#_Events_Asp.net Core_Dependency Injection - Fatal编程技术网

C# Net核心:DI和事件

C# Net核心:DI和事件,c#,events,asp.net-core,dependency-injection,C#,Events,Asp.net Core,Dependency Injection,我有一个ASP.NET核心项目,其中有一个类DataDistaptcher,它根据事件实现分派数据,另一个类LocationFilter,它正在侦听此事件,以便根据分派的数据执行一些操作 在DataDispatcher中有一种方法: public void UpdateData(string path) { //Upload Data ... //Fire event OnDataUpdated(EventArgs.Emp

我有一个ASP.NET核心项目,其中有一个类
DataDistaptcher
,它根据事件实现分派数据,另一个类
LocationFilter
,它正在侦听此事件,以便根据分派的数据执行一些操作

DataDispatcher
中有一种方法:

public void UpdateData(string path)
{   
        //Upload Data
        ...

        //Fire  event
        OnDataUpdated(EventArgs.Empty);

}
LocationFilter
构造函数类似于:

public LocationFilter(IDataDispatcher dispatcher)
{
        dispatcher.DataUpdated += new EventHandler((o,e) => UpdateData());
}
我在我的项目中使用依赖注入,我想在应用程序开始时更新数据,因此我从
IServiceProvider
获取
DataDispatcher
,并在
app.UseMvc()之后更新

如果我将dispatcher update移动到
Controller
,则会触发事件,并且
LocationFilter
确实已调度数据


因此,我不想对每个请求都触发更新,我只想在开始时进行更新,所以我应该将
dispatcher.update()
方法放在哪里?

据我所知,您的singleton LocationFilter对象仅在第一次调用控制器时创建(其构造函数是特定的)。这就是数据丢失的原因

在Configure startup方法中显式创建dispatcher时,尚未创建LocationFilter singleton对象。它仅在“第一次”被请求时创建(即,第一次调用控制器的构造函数-之后将使用相同的单例对象)

“Singleton生存期服务是在第一次请求时(或在运行ConfigureServices并使用服务注册指定实例时)创建的。”

添加singleton服务时,可以在ConfigureServices方法本身中显式创建LocationFilter singleton对象。根据您创建它的方式,您可能还需要处理它


看完整的。。阅读Singleton和Service lifetime部分。

我认为这里最好的解决方案是实现IHostedService接口并将您的调用添加到StartAsync方法中。运行asp.net核心应用程序时,该应用程序从DI容器获取所有iHostedService并执行start方法。当应用程序关闭时,将调用StopAsync方法。有关更多信息,请参阅本文档:

代码基于ASP.NET Core 3.1
您可以这样更改LocationFilter:

public class LocationFilter
{
    public LocationFilter()
    { } //constructor without dataDispatcher

    public void SubscribeToDataDispatcher(DataDispatcher instance)
    {
        // attach your event
        instance.DataUpdated += new EventHandler((o,e) => UpdateData());
    }
}
public class UpdateDataService : IHostedService
{
    private readonly DataDispatcher _dataDispatcher;
    private readonly LocationFilter _locationFilter;

    public UpdateDataService(DataDispatcher dataDispatcher, LocationFilter locationFilter)
    {
        _dataDispatcher = dataDispatcher;
        _locationFilter = locationFilter;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // connect the locationfilter to the data dispatcher and update the data.
        _locationFilter.SubscribeToDataDispatcher(_dataDispatcher);
        _dataDispatcher.UpdateData();
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        // detach your event?
        return Task.CompletedTask;
    }
}
public interface IDataDispatcherEventListener
{
    void OnEvent(DataModel data);
}

public class LocationFilter : IDataDispatcherEventListener
{
    public void OnEvent(DataModel data)
    {
        // do whatever with your data
    }
}

public class DataDispatcher : IHostedService
{
    private readonly IEnumerable<IDataDispatcherEventListener> _eventListeners;

    public DataDispatcher(IEnumerable<IDataDispatcherEventListener> eventListeners)
    {
        _eventListeners = eventListeners;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        var workResult = DoWork();
        foreach(var listener in _eventListeners)
        {
            listener.OnEvent(workResult);
        }
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    { }
}
现在,您的托管服务将如下所示:

public class LocationFilter
{
    public LocationFilter()
    { } //constructor without dataDispatcher

    public void SubscribeToDataDispatcher(DataDispatcher instance)
    {
        // attach your event
        instance.DataUpdated += new EventHandler((o,e) => UpdateData());
    }
}
public class UpdateDataService : IHostedService
{
    private readonly DataDispatcher _dataDispatcher;
    private readonly LocationFilter _locationFilter;

    public UpdateDataService(DataDispatcher dataDispatcher, LocationFilter locationFilter)
    {
        _dataDispatcher = dataDispatcher;
        _locationFilter = locationFilter;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // connect the locationfilter to the data dispatcher and update the data.
        _locationFilter.SubscribeToDataDispatcher(_dataDispatcher);
        _dataDispatcher.UpdateData();
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        // detach your event?
        return Task.CompletedTask;
    }
}
public interface IDataDispatcherEventListener
{
    void OnEvent(DataModel data);
}

public class LocationFilter : IDataDispatcherEventListener
{
    public void OnEvent(DataModel data)
    {
        // do whatever with your data
    }
}

public class DataDispatcher : IHostedService
{
    private readonly IEnumerable<IDataDispatcherEventListener> _eventListeners;

    public DataDispatcher(IEnumerable<IDataDispatcherEventListener> eventListeners)
    {
        _eventListeners = eventListeners;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        var workResult = DoWork();
        foreach(var listener in _eventListeners)
        {
            listener.OnEvent(workResult);
        }
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    { }
}
最后一步,您必须将托管服务添加到
Startup.cs
中的依赖项注入容器中,以便在应用程序中执行该服务

public void ConfigureServices(IServiceCollection services)
{
    services.AddHostedService<UpdateDataService>();
}
public void配置服务(IServiceCollection服务)
{
services.AddHostedService();
}

额外说明: 上面编写的代码只演示了如何在应用程序启动时附加事件。如果只在应用程序启动时触发事件,我不建议使用类似的事件。更好的方法是将DataDispatcher转换为托管服务,并为其提供对LocationFilter实例的引用。大概是这样的:

public class LocationFilter
{
    public LocationFilter()
    { } //constructor without dataDispatcher

    public void SubscribeToDataDispatcher(DataDispatcher instance)
    {
        // attach your event
        instance.DataUpdated += new EventHandler((o,e) => UpdateData());
    }
}
public class UpdateDataService : IHostedService
{
    private readonly DataDispatcher _dataDispatcher;
    private readonly LocationFilter _locationFilter;

    public UpdateDataService(DataDispatcher dataDispatcher, LocationFilter locationFilter)
    {
        _dataDispatcher = dataDispatcher;
        _locationFilter = locationFilter;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // connect the locationfilter to the data dispatcher and update the data.
        _locationFilter.SubscribeToDataDispatcher(_dataDispatcher);
        _dataDispatcher.UpdateData();
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        // detach your event?
        return Task.CompletedTask;
    }
}
public interface IDataDispatcherEventListener
{
    void OnEvent(DataModel data);
}

public class LocationFilter : IDataDispatcherEventListener
{
    public void OnEvent(DataModel data)
    {
        // do whatever with your data
    }
}

public class DataDispatcher : IHostedService
{
    private readonly IEnumerable<IDataDispatcherEventListener> _eventListeners;

    public DataDispatcher(IEnumerable<IDataDispatcherEventListener> eventListeners)
    {
        _eventListeners = eventListeners;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        var workResult = DoWork();
        foreach(var listener in _eventListeners)
        {
            listener.OnEvent(workResult);
        }
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    { }
}
公共接口IDataDispatcherEventListener
{
void OnEvent(数据模型数据);
}
公共类位置筛选器:IDataDispatcherEventListener
{
public void OnEvent(数据模型数据)
{
//用你的数据做任何事
}
}
公共类数据调度器:IHostedService
{
私有只读IEnumerable\u事件侦听器;
公共数据调度器(IEnumerable eventListeners)
{
_eventListeners=eventListeners;
}
公共任务StartSync(CancellationToken CancellationToken)
{
var workResult=DoWork();
foreach(事件监听器中的var监听器)
{
OnEvent(workResult);
}
返回Task.CompletedTask;
}
公共任务StopAsync(CancellationToken CancellationToken)
{ }
}
现在,您的工作已在启动时完成,您的位置过滤器将收到工作通知。
通过实现此接口,可以删除DataDispatcher和LocationFilter之间的依赖关系。通过使用
IEnumerable
,asp.net核心环境将注入您在构造函数中注册的IDataDispatcherEventListener的所有实例,因此,如果您也想通知其他服务,您只需要在DI容器中注册它。

为什么要这样解决?为什么不使用将选项注入过滤器?