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

时间:2018-11-29 11:39:31

标签: c# asp.net-core signalr hangfire 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));

然后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 without Constructor Injection中的方法:

我的后台作业计划变为:

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");
    }
}

然后使用以下命令从任何地方启动后台作业:

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

2 个答案:

答案 0 :(得分:1)

使用Schedule<T>泛型,您应该能够利用框架的依赖项注入功能。

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

答案 1 :(得分:1)

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

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

public class MySignalRHub 
{
}

然后,我创建了一个集线器帮助程序,该程序在MySignalRHub上维护一个集线器上下文。通过ASP.Net Core内置的DI机制(如here所述)将hubcontext注入到帮助器类中。

助手类:

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));