SignalR连续消息

本文关键字:消息 连续 SignalR | 更新日期: 2023-09-27 18:08:31

我有一个web项目,需要从外部soap服务更新web页面上的统计信息/日志。我决定采用的方法是使用signalR,通过代码执行服务方法并将结果返回给所有连接的客户端。此代码将连续执行,在服务调用之间有延迟。

我很难把所有的碎片放在一起,可能是因为我不确定所有的东西应该放在哪里!以下是我到目前为止所做的工作的大致分类

class Data { ... }
interface IDataService
{
    Task GetDataAsync(TimeSpan interval, CancellationToken cancellationToken, Action<Data> callback);
}
class DataService : IDataService
{
    private readonly ExternalService _externalService;
    public async Task GetDataAsync(TimeSpan interval, CancellationToken cancellationToken, Action<Data> callback)
    {
         while (!cancellationToken.IsCancellationRequested)
         {
              var data = await this._externalService.GetData();
              callback(data);
              await Task.Delay(interval).ConfigureAwait(false);
         }
    }
}

所以上面的逻辑是从外部服务获取数据,并执行回调。对于signalR,我只做了如下操作

public class DataHub : Hub
{
    private readonly IDataService _service;
    public DataHub(IDataService service)
    {
        this._service = service;
    }
    public async Task GetData()
    {
        var tenSeconds = new TimeSpan(0, 0, 10);
        var token = new CancellationToken();
        await _service.GetDataAsync(tenSeconds, token, d =>
        {
             // signal all connected clients
        });
    }
}

GetData()方法可以在客户端连接时调用(如果它还没有运行),并且当没有更多的客户端连接到集线器时可以取消令牌。

(潜在的)问题:

  1. SignalR集线器不是单例的,是吗?我假设它们在需要时被创建,在不再需要时(请求已经完成)被处理。在这种情况下,我将有GetData方法的多个实例运行(除非我使DataService类为单例/注入为单例)。
  2. 集线器不像是做这件事的合适地方。集线器应该像MVC/Web Api控制器一样对待吗?一个请求进来,hub处理它,请求完成。故事结束了。
  3. 另一种方法是将集线器传递给数据服务。然后它可以呼叫客户端。但我不想传递IHubContext对象。我想保持服务尽可能简单。
  4. 将ASP。NET后台任务在这里更合适吗?
如果有人能告诉我正确/最好的方法,我将不胜感激!

SignalR连续消息

我做了一个库,从SignalR解耦你的域,它将为你解决问题1-3。

请看这里https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/wiki

问题4,你绝对应该使用ASP。. NET后台工作线程的标准线程,否则ASP将不知道它的存在,并回收应用程序等

1,2,4:我将使用后台任务,然后利用Connectionmanager类检索适当的集线器。在这里,您可以找到有关如何从集线器外拨打电话的更多信息。

3:为了保持我的服务干净,我通常注册所谓的消息服务。然后,我的数据服务从消息服务调用一个方法,该方法在内部解析集线器并传播消息。通过这种方式,我使数据服务保持整洁,因为它们只调用特定的消息服务方法(通常是一行代码)。我的数据服务不需要知道我的消息服务在做什么

我已经设法通过使用System.Web.Hosting命名空间中的IRegisteredObject接口来解决这个问题。所以我的计划任务是:

public class DataTask : IRegisteredObject
{
     private readonly IGlobalData _global;
     private readonly IDataService _service;
     private readonly IHubContext _hub;
     private Timer _timer;
     public DataTask(IGlobalData global, IDataService service, IHubContext hub)
     {
          this._global = global;
          this._service = service;
          this._hub = hub;
          var interval = new TimeSpan(0, 0, 10);
          this._timer = new Timer(updateClients, null, TimeSpan.Zero, interval);
          // register this task with asp.net
          HostingEnvironment.RegisterObject(this);
     }
     public void Stop(bool immediate)
     {
          _timer.Dispose();
          HostingEnvironment.UnregisterObject(this);
     }
     private async void updateClients(object state)
     {
          var result = await this._service.GetData();
          // call the hub
          this._hub.Clients.All.updateData(result);
     }
}

我确实有不少问题!但这是由于我为signalR使用的自定义依赖解析器(问题是客户端js函数没有从这个任务中调用)。一旦解决了这个问题,一切都按预期进行。