如何将 SignalR 集线器上下文传递给 ASP .NET Core 2.1 上的 Hangfire 作业?

Yah*_*hia 7 c# signalr hangfire asp.net-core asp.net-core-signalr

如何将 SignalR 集线器上下文传递给 ASP .NET Core 2.1 上的 Hangfire 作业?

似乎由于将参数传递给 Hangfire 是通过序列化/反序列化完成的,因此 Hangfire 似乎很难重建 SignalR 集线器上下文。

我使用以下方法安排工作(在我的控制器中):

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

然后 2 分钟后,当作业尝试执行时,出现错误:

Newtonsoft.Json.JsonSerializationException:无法创建 Microsoft.AspNetCore.SignalR.IClientProxy 类型的实例。类型是接口或抽象类,不能被实例化。

任何的想法?

更新 1

我最终使用了 Startup.cs 中定义的静态上下文,并从 Configure() 分配

hbctx = app.ApplicationServices.GetRequiredService<IHubContext<MySignalRHub>>(); 
Run Code Online (Sandbox Code Playgroud)

所以现在 Hangfire 安排了一个使用静态上下文的集线器助手:

BackgroundJob.Schedule(() => new MyHubHelper().Send(), TimeSpan.FromMinutes(2)); 
Run Code Online (Sandbox Code Playgroud)

并且集线器助手获取上下文 Startup.hbctx

即使这有效,它也有点臭

更新 2

我也尝试在没有构造函数注入的情况下使用Access SignalR Hub 中的方法:

我的后台作业调度变成了:

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

但是这一次,当我到达上述行时,我有一个例外:

执行请求 System.ObjectDisposedException 时发生未处理的异常:无法访问已处理的对象。对象名称:'IServiceProvider'。

更新 3

谢谢大家。解决方案是创建一个助手,通过其构造函数通过 DI 获取集线器上下文,然后使用 hangfire 将助手方法 Send 作为后台作业进行调度。

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

然后从任何地方启动后台作业:

BackgroundJob.Schedule<MyHubHelper>( x => x.SendOutAlert(userId), TimeSpan.FromMinutes(2));
Run Code Online (Sandbox Code Playgroud)

Yah*_*hia 5

Nkosi 建议使用Schedule<T>泛型的答案指出了我使用的最终解决方案:

首先,我的 MySignalRHub 只是一个继承自 Hub 的空类。

public class MySignalRHub 
{
}
Run Code Online (Sandbox Code Playgroud)

然后,我创建了一个集线器助手,它在我的 MySignalRHub 上维护一个集线器上下文。该hubcontext在通过ASP.Net核心的辅助类注射内置DI机制(如解释在这里)。

辅助类:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

辅助界面:

public interface IMyHubHelper
{
    void SendData(String data);
}
Run Code Online (Sandbox Code Playgroud)

最后,我可以使用 hangfire 从代码中的任何位置安排SendData()集线器助手的方法作为后台作业:

BackgroundJob.Schedule<MyHubHelper>(h => h.SendData(myData), TimeSpan.FromMinutes(2));
Run Code Online (Sandbox Code Playgroud)