使用SignalR

时间:2018-11-08 02:15:56

标签: c# asp.net-mvc events signalr

我目前正在为一些当前的工具构建一些SignalR概念证明,并且我正在寻找实现某种服务器端事件平台的最佳方法。我们的许多工具都非常具有程序性和直接性,但是我确实有一些长期运行的任务,我想改变它们。

这样的例子就是我们的报告平台。我们的网络应用程序内置了一个内部的基本报告系统,该系统可以执行一些预建的报告。这些报告可能需要30秒钟到5分钟才能运行。它们的运行方式是通过向服务器发送带有所需参数的请求。服务器接收到请求后,它将唯一的GUID返回给客户端。然后,服务器启动报告运行器,这基本上只是一个小的未曾等待的异步方法,它执行一些功能并在数据库中设置报告的状态。

当前,存在一种客户端轮询机制,该机制反复询问服务器报告的状态,并且一旦运行该报告,便会获取并显示该报告。我已经切换了报表运行器方法,并对其进行了更改,以启动服务器端轮询机制,该机制不断检查不同线程上的数据库。报告完成后,它将调用我们的signalR集线器,并将其广播给客户端。

我正在寻找一种方法来修改服务器,而不是通过轮询获取状态,而是以某种方式挂接到报告运行器,然后在完成后调用signalR集线器。

我当前的想法是在运行器上创建一个可选参数,以接受实现简单接口IBasicEvent的对象。该界面可能类似于:

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

从那里,我可以在我的WebUI项目中实现该接口,并将其简单地传递到另一个项目的报表运行器中。这似乎是相对简单的,但是我也看到了一些有关潜在使用委托的信息,就像使用javascript中的回调一样。我真的不确定最好的方法是什么。

1 个答案:

答案 0 :(得分:1)

使用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);
    }
}