I have four KendoUI jQuery grids in my web application that use SignalR to manage their data. Having built and testing my application locally, everything works well, however, when I uploaded my application my Azure web app I ran into problems. Nothing would load correctly except for one single grid, the rest were empty.
There are no console errors however, investigations into the network traffic show a large amount of hub connections attempting to be made and then, the time for those connections says "pending" and nothing is ever loaded.
To help with our use of SignalR we have created an Azure SignalR Service in our tenant but the problem remains, the pending flag can still be seen along with the words "preflight".
Here is how the application is set up.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR(options => {
//Debugging only
options.EnableDetailedErrors = true;
})
.AddAzureSignalR() //for our azure service
.AddJsonProtocol(options => {
//Prevents signalr converting all text to lower case.
options.PayloadSerializerOptions.PropertyNamingPolicy = null;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseAzureSignalR(endpoints =>
{
endpoints.MapHub<RequirementHub>("/requirementHub");
endpoints.MapHub<PositionHub>("/positionHub");
endpoints.MapHub<FixtureHub>("/fixtureHub");
endpoints.MapHub<NewswireHub>("/newswireHub");
});
}
appsettings.json
//For debug only
"Azure": {
"SignalR": {
"ConnectionString": "Endpoint=https://mycompany- signalr.service.signalr.net;AccessKey=xxx;Version=1.0;",
"Enabled": "true"
}
}
hubs.js
var requirement_url = "/requirementHub";
var fixture_url = "/fixtureHub";
var position_url = "/positionHub";
var newswire_url = "/newswireHub";
var newswire_hub = new signalR.HubConnectionBuilder().withUrl(
newswire_url, {
transport: signalR.HttpTransportType.LongPolling
}).build();
var fixture_hub = new signalR.HubConnectionBuilder().withUrl(
fixture_url, {
transport: signalR.HttpTransportType.LongPolling
}).build();
var requirement_hub = new signalR.HubConnectionBuilder().withUrl(
requirement_url, {
transport: signalR.HttpTransportType.LongPolling
}).build();
var position_hub = new signalR.HubConnectionBuilder().withUrl(
position_url, {
transport: signalR.HttpTransportType.LongPolling
}).build();
var position_hub_start = position_hub.start({
json: true
});
var requirement_hub_start = requirement_hub.start({
json: true
});
var fixture_hub_start = fixture_hub.start({
json: true
});
var newswire_hub_start = newswire_hub.start({
json: true
});
newswireHub.cs
All the hubs are structured in the same way as this, so I've only shown one here.
using MyProject.Data;
using MyProject.Data.Views;
using MyProject.Repo;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace MyProject.UI.Hubs
{
public class NewswireHub : Hub
{
private readonly IRepository<Newswire> _newswire;
private readonly IRepository<ViewNewswires> _allNewswires;
public NewswireHub(IRepository<Newswire> newswire, IRepository<ViewNewswires> allNewswires)
{
_newswire = newswire;
_allNewswires = allNewswires;
}
public override Task OnConnectedAsync()
{
Groups.AddToGroupAsync(Context.ConnectionId, GetGroupName());
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception e)
{
Groups.RemoveFromGroupAsync(Context.ConnectionId, GetGroupName());
return base.OnDisconnectedAsync(e);
}
[AllowAnonymous]
public IEnumerable<ViewNewswires> Read()
{
var data = _allNewswires.GetAll();
return data;
}
[AllowAnonymous]
public async Task Update(Newswire model)
{
await _newswire.UpdateAsync(model);
await Clients.OthersInGroup(GetGroupName()).SendAsync("update", model);
}
public string GetGroupName()
{
return GetRemoteIpAddress();
}
public string GetRemoteIpAddress()
{
return Context.GetHttpContext()?.Connection.RemoteIpAddress.ToString();
}
}
}
The grids
Here is a copy of the grid code, again, the same as above, the code for the grids is always the same with each one being names appropriately. The only thing that ever changes in the grids is the columns used and the hub that they point to which are named accordingly.
$('#newswire_grid').kendoGrid({
dataSource: {
type: "signalr",
autoSync: true,
pageSize: 20,
sort: [
{
field: "Id",
dir: "desc"
}
],
schema: {
model: {
id: "Id",
fields: {
"Id": {
editable: false,
nullable: true
}
}
}
},
transport: {
signalr: {
promise: newswire_hub_start,
hub: newswire_hub,
server: {
read: "read",
update: "update",
create: "create",
destroy: "destroy"
},
client: {
read: "read",
update: "update",
create: "create",
destroy: "destroy"
}
}
}
},
filterable: true,
autoBind: true,
reorderable: true,
sortable: true,
pageable: {
pageSize: 40,
refresh: true
},
columns: [
{
field: "Id",
hidden: true
},
{
field: "Newswire_Title",
title: "Source"
},
{
field: "Newswire_Text",
title: "Text"
}
]
});
At this point, we are a bit confused. The setup for this was taken from the KendoUI Documentation however, one thing that's not covered is multiple hub and I think that is what's causing this problem. Has anyone every had this happen before?
Here is a an image of the network traffic that demonstrates the preflight and pending status. Please note there are a couple of extra hubs in this screenshot as it was from our previous iteration but shows the problem either way.