如何将EventHandler与具有.NET核心的SignalR集线器结合?

时间:2018-09-25 14:33:13

标签: c# .net-core asp.net-core-signalr

使用.NET Core 2.1,我在其中具有以下服务:

public class OrderService : IOrderService
{
    public event EventHandler<OrderUpdatedEvent> OrderUpdatedEventHandler; 

    ...
}

我还创建了一个SignalR集线器,如下所示:

public class OrderHub : Hub
{
    private OrderService _orderService;
    private EventHandler<OrderUpdatedEvent> _eventHandler;

    public OrderHub(OrderService orderService)
    {
        Console.WriteLine("OrderHub created...");
        _orderService = orderService;
        _eventHandler = (sender, updateEvent) => { SendUpdateOverWebsocket(updateEvent); };
        _orderService.OrderEventHandler += _eventHandler;
        Console.WriteLine("Event handler added!");
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        _orderService.OrderUpdatedEventHandler -= _eventHandler;
    }

OrderService中,有以下一行:

OrderUpdatedEventHandler?.Invoke(this, new OrderUpdatedEvent(orderId, ...));

问题在于OrderUpdatedEventHandler始终是null,因为OrderHub的构造函数似乎不是在应用程序启动时创建的。

OrderService已注册为单例:

services.AddSingleton<IOrderService, OrderService>();

我确实在文档中发现.NET仅在“使用”时才会创建单例。我将其理解为“通过HTTP REST调用首次击中与该单例相关的控制器”。

在我的代码中也不是好的,OrderHub将构造函数DI参数声明为OrderService而不是IOrderService。我可以通过将集线器直接注入OrderService中来解决该问题,但是我想使用事件来在服务之间发生松散耦合,并在发生更改时将内容放到网络套接字上。

1 个答案:

答案 0 :(得分:0)

您已经担心,OrderHub不是在应用程序启动时创建的。当客户端连接或调用集线器上的方法时,将创建集线器。另一个问题是,在客户端已连接或调用了集线器方法之后,集线器将被直接处置。因此,在您的情况下,集线器将立即取消订阅EventHandler。另外,Hub实例不是单例。

当您的主要目标是松散耦合时,我建议以下解决方案:

创建一个IOrderBroadcaster接口,以便稍后将实现从SignalR更改为另一种技术:

public interface IOrderBroadcaster
{
    Task SendUpdate(string order);
}

SignalR版本的实现如下所示:

public class WebSocketOrderBroadcaster : IOrderBroadcaster
{
    private IHubContext<OrderHub> orderHubContext;

    public WebSocketOrderBroadcaster(IHubContext<OrderHub> orderHubContext)
    {
        this.orderHubContext = orderHubContext;
    }

    public Task SendUpdate(string order)
    {
        return this.orderHubContext.Clients.All.SendAsync("Update", order);
    }
}

还请注意,新广播公司已在Startup.cs中注册了DI:

services.AddSingleton<IOrderBroadcaster, WebSocketOrderBroadcaster>();

对于此解决方案,您的Hub可以保留为空:

public class OrderHub : Hub
{
}

然后在您的OrderService中,可以注入IOrderBroadcaster并调用您的更新方法:

public class OrderService : IOrderService
{
    private IOrderBroadcaster broadcaster;

    public OrderService(IOrderBroadcaster broadcaster)
    {
        this.broadcaster = broadcaster;
    }

    public void UpdateOrder(string order)
    {
        this.broadcaster.SendUpdate(order);
    }
}

通过这种解决方案,您已经实现了宽松的耦合,并且不需要EventHandlers,在我看来,应尽可能避免使用该事件处理程序。

编码愉快!