【问题标题】:SignalR continuous messagingSignalR 连续消息传递
【发布时间】:2023-04-06 18:09:01
【问题描述】:

我有一个网络项目,它需要从外部肥皂服务更新网页上的统计信息/日志。我决定采用的方法是使用 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 控制器吗?所以一个请求进来,集线器处理它,请求完成。故事结束。
  3. 另一种方法是将集线器传递到数据服务中。然后它可以调用客户端。但我真的不想传递 IHubContext 对象。我想让服务尽可能简单。
  4. ASP.NET 后台任务在这里更合适吗?

如果有人能指出正确/最佳的方法,将不胜感激!

【问题讨论】:

标签: c# asp.net signalr async-await


【解决方案1】:

我制作了一个库,将您的域与 SignalR 分离,它将为您解决问题 1-3。

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

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

【讨论】:

  • 谢谢。我去看看!
【解决方案2】:

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

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

【讨论】:

  • 是的,我正在考虑将集线器包装在自定义类中并将其传递给我的服务。感谢您的回复。
【解决方案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 函数)。解决此问题后,一切都会按预期进行。

【讨论】:

    猜你喜欢
    • 2015-09-16
    • 2016-10-11
    • 1970-01-01
    • 1970-01-01
    • 2019-06-03
    • 1970-01-01
    • 2018-10-23
    • 2020-12-16
    • 2014-04-07
    相关资源
    最近更新 更多