簡體   English   中英

使用 SignalR 實現服務器端事件

[英]Implementing Server-Sider Events with SignalR

我目前正在為我們當前的一些工具構建一些 SignalR 概念證明,我正在尋找實現某種服務器端事件平台的最佳方法。 我們的許多工具都非常程序化且簡單明了,但我確實有一些長期運行的任務需要改變。

其中一個例子是我們的報告平台。 我們在我們的 web 應用程序中內置了一個內部的基本報告系統,可以執行一些預構建的報告。 運行這些報告可能需要 30 秒到 5 分鍾不等。 它們的運行方式是向服務器發送帶有所需參數的請求。 服務器收到請求后,將唯一的 guid 返回給客戶端。 然后服務器啟動報表運行器,它基本上只是一個小的未等待異步方法,它執行一些功能並設置數據庫中報表的狀態。

目前有客戶端輪詢機制,反復向服務器詢問報告的狀態,一旦報告運行,它就會獲取並顯示報告。 我已經切換了報告運行程序方法並將其更改為觸發服務器端輪詢機制,該機制在不同的線程上不斷檢查數據庫。 報告完成后,它會調用我們的 signalR 集線器並將其廣播給客戶端。

我正在尋找一種方法來修改服務器,而不是通過輪詢來獲取狀態,而是以某種方式掛接到報告運行器,然后在完成時調用 signalR 集線器。

我目前的想法是在 runner 上創建一個可選參數,該參數接受一個實現簡單接口IBasicEvent的對象。 該界面可能如下所示:

public interface IBasicEvent
{
    void OnSuccess();
    void OnError();
    void Complete();
}

從那里,我可以在我的 WebUI 項目中實現該接口,然后簡單地將它傳遞到我的另一個項目中的報表運行器中。 這似乎相對簡單,但我也看到了一些關於可能使用委托的信息,就像 JavaScript 中的回調一樣。 我真的不確定這里最好的方法是什么。

我設法使用 C# 的委托和事件處理程序獲得了一個非常酷的概念證明,它們似乎可以處理我需要的一切。 這是去掉無關邏輯的基本設置。

在我的報告運行器中:

public class ReportRunner
{
    public delegate Task RunCompleteHandler(ReportRunner runner, ReportStatusEventArgs eventArgs);
    public event RunCompleteHandler RunComplete;

    protected void OnRunComplete(ReportRunner runner, ReportStatusEventArgs eventArgs)
    {
        RunComplete?.Invoke(runner, eventArgs);
    }

    private async Task ExecuteReport(FilterSet filters, Guid guid)
    {
        try
        {
            // run the report
        }
        catch (Exception ex)
        {
            // log and set the report to error status
        }
        finally
        {
            var status = _reportLogic.GetReportRunStatus(guid);
            var eventArgs = new ReportStatusEventArgs(status);

            OnRunComplete(this, eventArgs);
        }
    }
}

public class ReportStatusEventArgs : EventArgs
{
    public readonly ReportRunStatus ReportRunStatus;
    public ReportStatusEventArgs(ReportRunStatus reportRunStatus)
    {
        ReportRunStatus = reportRunStatus;
    }
}

在我的控制器中:

public async Task<IActionResult> Run(FiltersRequest request)
{
    // basic checks omitted
    var factory = new ReportFactory();
    var reportModel = factory.CreateReport(reportType);
    var runner = new ReportRunner(reportModel, _contexts);
    var eventHandler = new ReportRunnerSubscriber(_reportHub, HttpContext.User.Identity.Name);
    eventHandler.Subscribe(runner);

    var guid = await runner.Run(filterSet);

    return Json(guid);
}

還有我的訂閱者課程

public class ReportRunnerSubscriber
{
    private readonly IHubContext<ReportHub> _reportHub;
    private readonly string _userId;

    public ReportRunnerSubscriber(IHubContext<ReportHub> reportHub, string userId)
    {
        _reportHub = reportHub;
        _userId = userId;
    }

    public void Subscribe(ReportRunner reportRunner)
    {
        reportRunner.RunComplete += NotifySubscribers;
    }

    public async Task NotifySubscribers(ReportRunner reportRunner, ReportStatusEventArgs eventArgs)
    {
        var status = eventArgs.ReportRunStatus;
        status.ReportRuns = null;
        await _reportHub.Clients.User(_userId).SendAsync("ReportComplete", status);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM