订阅事件 c#

Subscribe to event c#

提问人:Gabriel 提问时间:10/27/2023 最后编辑:maciekGabriel 更新时间:11/9/2023 访问量:120

问:

我有一个正在上升事件的 EventManager 服务。 我正在尝试在 Razor 页面中订阅事件,但我无法将 OnEvent 方法绑定到该事件。我正在使用 Blazor 服务器。

这是程序中的依赖注入 .cs

builder.Services.AddTransient<IEventsManager, EventsManager>();

在这里,我有正在上升事件的服务(瞬态)

public class EventsManager:IEventsManager
{

    public delegate void EventReceivedEvenHandler(EventsManager evManager, EventsView ev);
    public event EventReceivedEvenHandler EventReceived;


    public async Task ProcessEvents(List<Telemetry> telemetryList, string deviceProtocolId)
    {
            //Some code...

            var eventView = new EventsView()
            OnEventReceived(eventView);
    }

    public virtual void OnEventReceived(EventsView ev)
    {
            EventReceived?.Invoke(this, ev);
    }
}

在这里,我有一个 Razor 页面,我在其中注入了服务:

@inject IEventsManager eventManager



protected override async Task OnInitializedAsync()
{
    eventManager.EventReceived += OnEventReceived;
}

public void OnEventReceived(EventsManager evMan,  EventsView ev)
{
 //some code
}

程序正在运行,但公共事件 EventReceivedEvenHandler EventReceived 始终为 null。

C# 事件 Blazor-Server-Side

评论

0赞 maciek 10/27/2023
Blazor 服务器端还是 WebAssembly?
0赞 Gabriel 10/27/2023
Blazor 服务器端
0赞 ℍ ℍ 10/27/2023
并且您缺少 Dispose() 和 ,这可能是一个很大的内存泄漏。-=
0赞 maciek 10/27/2023
试用服务。AddSingleton<EventsManager>()
0赞 Gabriel 10/27/2023
我已经编辑了这篇文章,以便 DI.Is 不是将 EventsManager 设置为单例的选项,以防我在 EventsManager 中注入了 DB olso 并且不是单例。

答:

1赞 MrC aka Shaun Curtis 10/28/2023 #1

如果我没看错你的问题,你有一些后台进程捕获数据。此过程会在 中引发事件。因此,您必须注册为后台服务和 UI 的单一实例才能访问同一实例。EventsManagerIEventsMansger

由于您还在执行数据库操作,因此需要将它们与 分开。为此,可以在单独的作用域内或瞬态服务中处理数据库操作。该服务在 中注入并引发事件。IEventManagerIEventsManagerIEventsManager

下面是代码的重构版本。

各种对象。我在这里做了一些猜测。

public delegate void EventReceivedEvenHandler(EventsManager evManager, EventsView ev);

public interface IEventsManager
{
    public event EventReceivedEvenHandler EventReceived;
    public Task ProcessEvents(List<Telemetry> telemetryList, string deviceProtocolId);
    public void OnEventReceived(EventsView ev);
}

public class EventsManager : IEventsManager
{
    public event EventReceivedEvenHandler? EventReceived;

    public async Task ProcessEvents(List<Telemetry> telemetryList, string deviceProtocolId)
    {
        //Some async code...
        await Task.Yield();

        var eventView = new EventsView();
        OnEventReceived(eventView);
    }

    public virtual void OnEventReceived(EventsView ev)
    {
        EventReceived?.Invoke(this, ev);
    }
}

public class EventsView
{
    public string? Value { get; set; }
}

public class Telemetry { }

新服务:EventsHandler

namespace SO77374228.Data;

public class EventsHandler { 

    private IEventsManager _eventsManager;

    public EventsHandler(IEventsManager eventsManager)
    {
        _eventsManager = eventsManager;
        // get your Database stuff here
    }

    public async Task HandleEventAsync()
    {
        // Do your database saving here
        // You must use the DBContextFactory with using within the method to ensure correct handling of disposal of the context 
        await Task.Yield();
        //_eventsManager.ProcessEvents();
        _eventsManager.OnEventReceived(new() { Value = $"Hello at {DateTime.Now.ToLongTimeString()} " });
    }

}

服务注册:

builder.Services.AddSingleton<IEventsManager, EventsManager>();
builder.Services.AddTransient<EventsHandler>();

Index显示数据

@page "/"
@inject IEventsManager EventsManager
@implements IDisposable

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

<div class="alert alert-primary">@_eventsView.Value</div>

@code {
    private EventsView _eventsView = new();

    protected override void OnInitialized()
        => this.EventsManager.EventReceived += this.OnEvent;

    private void OnEvent(object sender, EventsView eventsView)
    {
        _eventsView = eventsView;
        // as this is not a UI event we need to render the component to display any chnges
        this.InvokeAsync(this.StateHasChanged);
    }

    // Must Dispose properly
    public void Dispose()
        => this.EventsManager.EventReceived -= this.OnEvent;

}

并引发事件。Counter

@page "/counter"
@inject EventsHandler EventsHandler

<PageTitle>Counter</PageTitle>

<button class="btn btn-primary" @onclick="IncrementCount">Raise an Event</button>

@code {

    private async Task IncrementCount()
    {
        await this.EventsHandler.HandleEventAsync();
    }
}

这是一张图片,显示了两个浏览器窗口打开。单击该按钮,该事件将显示在另一个按钮中。

enter image description here

评论

0赞 Gabriel 10/29/2023
谢谢你的帮助。事实上,EventManager 的作用域是有限制的,我使用一个实例来接收消息,而用户正在订阅 EventManager 的其他实例。我已经纠正了这一点,新的工作正常。