Как передать контекст-концентратор SignalR в задание Hangfire в ASP .NET Core 2.1? - PullRequest
0 голосов
/ 29 ноября 2018

Как передать контекст-концентратор SignalR в задание Hangfire в ASP .NET Core 2.1?

Кажется, что, поскольку передача аргументов в Hangfire осуществляется посредством сериализации / десериализации, кажется, что Hangfire имеетвремя восстановления контекста концентратора SignalR.

Я планирую задание (в моем контроллере), используя:

BackgroundJob.Schedule(() => _hubContext.Clients.All.SendAsync(
        "MyMessage",
        "MyMessageContent", 
        System.Threading.CancellationToken.None), 
    TimeSpan.FromMinutes(2));

Затем, через 2 минуты, когда задание пытается выполнить, у меня появляется ошибка:

Newtonsoft.Json.JsonSerializationException: Не удалось создать экземпляр типа Microsoft.AspNetCore.SignalR.IClientProxy.Тип является интерфейсом или абстрактным классом и не может быть создан.

Есть идеи?

Обновление 1

Я закончил использовать статическийконтекст, определенный в Startup.cs и назначенный из Configure ()

hbctx = app.ApplicationServices.GetRequiredService<IHubContext<MySignalRHub>>(); 

Так что теперь Hangfire планирует вместо помощника концентратора, который использует статический контекст:

BackgroundJob.Schedule(() => new MyHubHelper().Send(), TimeSpan.FromMinutes(2)); 

, и помощник концентратора получаетконтекст с Startup.hbctx

Несмотря на то, что это работает, это немного вонючий

Обновление 2

Я пытался также использовать подход в Access SignalR Hub без внедрения Constructor :

Мое планирование фоновых заданий стало:

BackgroundJob.Schedule (() => Startup.GetService (). SendOutAlert (2),TimeSpan.FromMinutes (2));

Однако на этот раз у меня возникает исключение, когда я достигаю вышеуказанной строки:

Произошло необработанное исключение при выполнении запроса System.ObjectDisposedException: Невозможно получить доступ к удаленному объекту.Имя объекта: 'IServiceProvider'.

Обновление 3

Спасибо всем.Решение состояло в том, чтобы создать помощника, который получает хабконтекст через его конструктор через DI, а затем с помощью Hangfire запланировать вспомогательный метод Отправить как фоновое задание.

public interface IMyHubHelper
{
    void SendOutAlert(String userId);
}

public class MyHubHelper : IMyHubHelper
{
    private readonly IHubContext<MySignalRHub> _hubContext;

    public MyHubHelper(IHubContext<MySignalRHub> hubContext)
    {
        _hubContext = hubContext;
    }

    public void SendOutAlert(String userId)
    {
        _hubContext.Clients.All.SendAsync("ReceiveMessage", userId, "msg");
    }
}

Затем запустить фоновое задание из любого места с помощью:

BackgroundJob.Schedule<MyHubHelper>( x => x.SendOutAlert(userId), TimeSpan.FromMinutes(2));

Ответы [ 2 ]

0 голосов
/ 09 декабря 2018

Ответ от Nkosi, предлагающий использовать Schedule<T> generics, указал мне на окончательное решение, которое я использовал:

Во-первых, мой MySignalRHub - это просто пустой класс, унаследованный от Hub.

public class MySignalRHub 
{
}
* 1006Затем я создал хаб-хелпер, который поддерживает хаб-текст на моем MySignalRHub.Hubcontext внедряется во вспомогательный класс через встроенный механизм DI ядра ASP.Net Core (как объяснено здесь ).

Вспомогательный класс:

public class MyHubHelper : IMyHubHelper
{
    private readonly IHubContext<MySignalRHub> _hubContext;

    public MyHubHelper(IHubContext<MySignalRHub> hubContext)
    {
        _hubContext = hubContext;
    }

    public void SendData(String data)
    {
        _hubContext.Clients.All.SendAsync("ReceiveMessage", data);
    }
}

Интерфейс помощника:

public interface IMyHubHelper
{
    void SendData(String data);
}

Наконец, я могу использовать hangfire для планирования из любого места в коде метода SendData() помощника концентратора в качестве фонового задания с:

BackgroundJob.Schedule<MyHubHelper>(h => h.SendData(myData), TimeSpan.FromMinutes(2));
0 голосов
/ 02 декабря 2018

Используя Schedule<T> обобщения, вы сможете воспользоваться возможностями внедрения зависимостей в фреймворке.

BackgroundJob.Schedule<IHubContext<MySignalRHub>>(hubContext => 
    hubContext.Clients.All.SendAsync(
        "MyMessage",
        "MyMessageContent", 
        System.Threading.CancellationToken.None), 
    TimeSpan.FromMinutes(2));
...