Как объединить EventHandler с концентратором SignalR с ядром .NET? - PullRequest
0 голосов
/ 25 сентября 2018

Используя .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 Iесть такая строка:

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

Проблема в том, что OrderUpdatedEventHandler всегда null, потому что конструктор OrderHub не создается при запуске приложения.

The OrderService зарегистрирован как синглтон:

services.AddSingleton<IOrderService, OrderService>();

В документах я обнаружил, что .NET будет создавать синглтоны только тогда, когда он «используется».Который я понимал как «контроллер, зависящий от этого синглтона, впервые получает доступ через HTTP-вызов REST».

Что не очень хорошо в моем коде, так это то, что OrderHub объявляет конструктор DIпараметр как OrderService вместо IOrderService.Я мог бы, вероятно, обойти это, непосредственно вставив концентратор в мой OrderService, но я хочу использовать события, чтобы иметь слабую связь между службой и помещением материала в веб-сокет, когда что-то меняется.

1 Ответ

0 голосов
/ 27 сентября 2018

Как вы уже опасались, OrderHub не создается при запуске приложения.Концентратор будет создан, когда клиент подключится или вызовет метод на Концентраторе.Другая проблема заключается в том, что концентратор напрямую удаляется после подключения клиента или вызова метода концентратора.Таким образом, в вашем случае, Hub будет немедленно отписаться от 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);
    }
}

Также позаботьтесь, чтобы новый вещатель был зарегистрирован для DI в Startup.cs:

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, которых, на мой взгляд, следует избегать, если это возможно.

Удачного кодирования!

...