我目前正在为一些当前的工具构建一些SignalR概念证明,并且我正在寻找实现某种服务器端事件平台的最佳方法。我们的许多工具都非常具有程序性和直接性,但是我确实有一些长期运行的任务,我想改变它们。
这样的例子就是我们的报告平台。我们的网络应用程序内置了一个内部的基本报告系统,该系统可以执行一些预建的报告。这些报告可能需要30秒钟到5分钟才能运行。它们的运行方式是通过向服务器发送带有所需参数的请求。服务器接收到请求后,它将唯一的GUID返回给客户端。然后,服务器启动报告运行器,这基本上只是一个小的未曾等待的异步方法,它执行一些功能并在数据库中设置报告的状态。
当前,存在一种客户端轮询机制,该机制反复询问服务器报告的状态,并且一旦运行该报告,便会获取并显示该报告。我已经切换了报表运行器方法,并对其进行了更改,以启动服务器端轮询机制,该机制不断检查不同线程上的数据库。报告完成后,它将调用我们的signalR集线器,并将其广播给客户端。
我正在寻找一种方法来修改服务器,而不是通过轮询获取状态,而是以某种方式挂接到报告运行器,然后在完成后调用signalR集线器。
我当前的想法是在运行器上创建一个可选参数,以接受实现简单接口IBasicEvent
的对象。该界面可能类似于:
public interface IBasicEvent
{
void OnSuccess();
void OnError();
void Complete();
}
从那里,我可以在我的WebUI项目中实现该接口,并将其简单地传递到另一个项目的报表运行器中。这似乎是相对简单的,但是我也看到了一些有关潜在使用委托的信息,就像使用javascript中的回调一样。我真的不确定最好的方法是什么。
答案 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);
}
}