C# 使用信号器实现服务器端事件
我目前正在为我们当前的一些工具构建一些signar概念验证,我正在寻找实现某种服务器端事件平台的最佳方法。我们的很多工具都是非常程序化和简单的,但我确实有一些长期运行的任务,我希望改变 我们的报告平台就是这样一个例子。我们的webapp内置了一个内部的基本报告系统,可以执行一些预构建的报告。运行这些报告可能需要30秒到5分钟。运行它们的方式是向服务器发送带有所需参数的请求。一旦服务器接收到请求,它就会将唯一的guid返回给客户端。然后,服务器启动报表运行程序,它基本上只是一个小的未等待的异步方法,用于执行某些功能并在数据库中设置报表的状态 目前,有一种客户端轮询机制,它反复向服务器询问报告的状态,一旦报告运行,它就会获取并显示报告。我已经改变了ReportRunner方法,并将其更改为启动服务器端轮询机制,该机制在不同线程上连续检查数据库。报告完成后,它会调用我们的信号集线器并将其广播给客户端 我正在尝试找到一种方法来修改服务器,而不是轮询以获取状态,而是以某种方式连接到报表运行程序,然后在完成后调用signalR hub 我目前的想法是在运行程序上创建一个可选参数,该参数接受一个实现简单接口的对象,C# 使用信号器实现服务器端事件,c#,asp.net-mvc,events,signalr,C#,Asp.net Mvc,Events,Signalr,我目前正在为我们当前的一些工具构建一些signar概念验证,我正在寻找实现某种服务器端事件平台的最佳方法。我们的很多工具都是非常程序化和简单的,但我确实有一些长期运行的任务,我希望改变 我们的报告平台就是这样一个例子。我们的webapp内置了一个内部的基本报告系统,可以执行一些预构建的报告。运行这些报告可能需要30秒到5分钟。运行它们的方式是向服务器发送带有所需参数的请求。一旦服务器接收到请求,它就会将唯一的guid返回给客户端。然后,服务器启动报表运行程序,它基本上只是一个小的未等待的异步方法
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);
}
公共异步任务运行(FiltersRequest请求)
{
//省略基本检查
var factory=new ReportFactory();
var reportModel=factory.CreateReport(reportType);
var runner=new ReportRunner(reportModel,_上下文);
var eventHandler=new ReportRunnerSubscriber(_reportHub,HttpContext.User.Identity.Name);
订阅(运行程序);
var guid=wait runner.Run(filterSet);
返回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);
}
}
公共类ReportRunnerSubscriber
{
私有只读IHubContext\u reportHub;
私有只读字符串_userId;
public ReportRunnerSubscriber(IHubContext reportHub,字符串用户ID)
{
_reportHub=reportHub;
_userId=userId;
}
公开作废订阅(ReportRunner ReportRunner)
{
reportRunner.RunComplete+=NotifySubscribers;
}
公共异步任务NotifySubscribers(ReportRunner ReportRunner、ReportStatusEventArgs eventArgs)
{
var status=eventArgs.ReportRunStatus;
status.ReportRuns=null;
wait _reportHub.Clients.User(_userId).SendAsync(“ReportComplete”,status);
}
}