我想将 SignalR 消息直接从我的 Azure WebJob 发送到在我的 Web 服务器上运行的浏览器客户端,因此我将 SignalR 配置为使用 Azure 服务总线作为 WebJob 和我的服务器上的背板。从 WebJob 发送的消息将进入服务总线主题队列,并被 Web 服务器接收,但不会发送到连接的 SignalR Web 客户端。我认为这会自动发生,我是否必须以某种方式从网络服务器订阅我的 WebJob SignalR 消息并手动将它们传播到浏览器客户端?
我会粘贴一些代码,但我不确定什么是相关的,因为我没有收到任何错误。我可以通过服务总线跟踪从 WebJob 到我的 Web 服务器的消息,但没有任何东西到达每个 Web 服务器上运行的 SignalR 浏览器客户端。
重点;
- 每个 Hub 实例都使用相同的 Hub 名称注册
- WebJob 和 Web 服务器都使用相同的服务总线背板连接字符串
- 我可以看到消息被发送到正确的主题,并且正在阅读正确的订阅
来自 WebJob 的跟踪信息:
SignalR.ServiceBusMessageBus 信息:0:订阅服务总线中的 5 个主题... SignalR.ServiceBusMessageBus 信息:0:新主题客户端 SIGNALR_TOPIC_SignalREvents_0 的创建成功完成。SignalR.ServiceBusMessageBus 信息:0:在服务总线中为主题 SIGNALR_TOPIC_SignalREvents_0 创建新订阅 2ea68ce5-58fe-4218-8768-e03675be8e74 已成功完成。SignalR.ServiceBusMessageBus 信息:0:为服务总线中的订阅实体路径 SIGNALR_TOPIC_SignalREvents_0/Subscriptions/2ea68ce5-58fe-4218-8768-e03675be8e74 创建消息接收成功完成。SignalR.ScaleoutMessageBus 信息:0:Stream(0) - 将状态从初始更改为打开 (x5) SignalR.ServiceBusMessageBus 信息:0:订阅服务总线中的 5 个主题主题服务已成功完成。SignalR.ServiceBusMessageBus 详细:0:通过服务总线发送 68 个字节:{"H":"auctionHub","M":"Init","A":[{"Price":569.72,"Symbol":"GOOG" }]} SignalR.ServiceBusMessageBus 详细:0:通过服务总线发送 68 个字节:{"H":"auctionHub","M":"Init","A":[{"Price":577.38,"Symbol": "APPL"}]} SignalR.ServiceBusMessageBus 详细:0:通过服务总线接收 68 个字节:{"H":"auctionHub","M":"Init","A":[{"Price":569.72," Symbol":"GOOG"}]} SignalR.ScaleoutMessageBus 信息:0 : OnReceived(4, 65, 1)
来自网络服务器的跟踪
SignalR.ServiceBusMessageBus 信息:0:订阅服务总线中的 5 个主题... SignalR.ServiceBusMessageBus 信息:0:新主题客户端 SIGNALR_TOPIC_SignalREvents_0 的创建成功完成。SignalR.ServiceBusMessageBus 信息:0:在服务总线中为主题 SIGNALR_TOPIC_SignalREvents_0 创建新订阅 e6afd744-7724-4ab5-8fd9-2717a62caf61 已成功完成。SignalR.ServiceBusMessageBus 信息:0:为服务总线中的订阅实体路径 SIGNALR_TOPIC_SignalREvents_0/Subscriptions/e6afd744-7724-4ab5-8fd9-2717a62caf61 创建消息接收成功完成。SignalR.ScaleoutMessageBus 信息:0:Stream(0) - 将状态从初始更改为打开 SignalR.ServiceBusMessageBus 信息:0:新主题客户端 SIGNALR_TOPIC_SignalREvents_1 的创建成功完成。SignalR.ServiceBusMessageBus 信息:0:为服务总线中的主题 SIGNALR_TOPIC_SignalREvents_1 创建新订阅 2c155757-123f-44ba-ace7-96a6b390234e 已成功完成。SignalR.ServiceBusMessageBus 信息:0:为服务总线中的订阅实体路径 SIGNALR_TOPIC_SignalREvents_1/Subscriptions/2c155757-123f-44ba-ace7-96a6b390234e 创建消息接收成功完成。SignalR.ScaleoutMessageBus 信息:0:Stream(1) - 将状态从初始更改为打开 SignalR.ServiceBusMessageBus 信息:0:新主题客户端 SIGNALR_TOPIC_SignalREvents_2 的创建成功完成。SignalR.Transports.TransportHeartBeat 信息:0:
SignalR.ServiceBusMessageBus 详细:0:通过服务总线接收 37 个字节:{"H":"auctionHub","M":"Init","A":[1]} SignalR.ScaleoutMessageBus 信息:0:OnReceived(4, 221, 1)
SignalR 服务总线配置代码(在 WebJob 和 Web 服务器上相同)
var scaleOutConfig = new ServiceBusScaleoutConfiguration(ConfigurationManager.ConnectionStrings["AzureWebJobsServiceBus"].ConnectionString, "SignalREvents");
GlobalHost.DependencyResolver.UseServiceBus(scaleOutConfig);
如果我还有头发,我会把它撕掉。我已经对此进行了广泛的搜索,但找不到任何有用的东西。任何指针将不胜感激。
编辑>>
[HubName("auctionHub")]
public class AuctionHub : Hub<IAuctionHubClientMethods>
{
private readonly IAuctionHubService _auctionHubService;
public AuctionHub(IAuctionHubService auctionHubService)
{
_auctionHubService = auctionHubService;
}
public override Task OnConnected()
{
var userId = Context.User.Identity.GetUserId();
var connectionId = Context.ConnectionId;
_auctionHubService.OnConnected(Groups, userId, connectionId);
return base.OnConnected();
}
public interface IAuctionHubClientMethods
{
Task Heartbeat(string now);
Task Init(AuctionViewModel eventId);
}
public class AuctionHubService : IAuctionHubService
{
<snip>
public AuctionHubService(IAuctionServices auctionServicesProxy, IQueryProcessor queryProcessor, ApplicationUserManager userManager)
{
<snip>
}
public void OnConnected(IGroupManager groups, string userId, string connectionId)
{
var user = _userManager.FindById(userId);
var client = user.Client;
var id = client?.Id;
groups.Add(connectionId, user.Client.Id.ToString());
}
public void Init(int eventId, IHubCallerConnectionContext<IAuctionHubClientMethods> clients)
{
var query = new GetAuctionViewModelByEventIdQuery { EventId = eventId };
var eventState = _queryProcessor.Process(query);
eventState.Suppliers.ForEach(x => clients.Group(x.SupplierId.ToString()).Init(eventState));
}
}
OnDisconnected
并且OnReconnected
未受影响。
我正在使用 SimpleInjector 根据需要提供 SignalR 上下文,这个实现会有什么效果吗?
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors = true,
EnableJavaScriptProxies = false,
Resolver = new SignalRDependencyResolver(MvcApplication.Container),
};
app.MapSignalR<SignalRHubDispatcher>("/signalr", hubConfiguration);
public class SignalRHubDispatcher : HubDispatcher
{
public SignalRHubDispatcher(Container container, HubConfiguration configuration) : base(configuration)
{
_container = container;
}
protected override Task OnConnected(IRequest request, string connectionId)
{
return Invoke(() => base.OnConnected(request, connectionId));
}
protected override Task OnReceived(IRequest request, string connectionId, string data)
{
return Invoke(() => base.OnReceived(request, connectionId, data));
}
protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
{
return Invoke(() => base.OnDisconnected(request, connectionId, stopCalled));
}
protected override Task OnReconnected(IRequest request, string connectionId)
{
return Invoke(() => base.OnReconnected(request, connectionId));
}
private async Task Invoke(Func<Task> method)
{
using (_container.BeginExecutionContextScope())
{
await method();
}
}
private readonly Container _container;
}