SignalR On OWIN & JavaScript
The purpose of this post is to show the different SignalR implementations available for an OWIN WebApi & JavaScript.
OWIN WebApi
NuGet Packages used:
- Microsoft.Owin.SelfHost
- Microsoft.AspNet.SignalR.SelfHost
- And all related dependencies
To get started, follow the tutorial here
In the Startup class, where the OWIN configuration is set, we must include the SignalR configuration to run in the same pipeline.
1 | public void Configuration(IAppBuilder app) |
The following 2 hubs purely to show the difference of how they will be used in the front-end.
Generated Proxy Hub
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class GeneratedProxyHub : Hub
{
// http://stackoverflow.com/questions/31169509/signalr-how-to-truly-call-a-hubs-method-from-the-server-c-sharp
private static IHubContext context = GlobalHost.ConnectionManager.GetHubContext<GeneratedProxyHub>();
public override Task OnConnected()
{
var qs = Context.QueryString["user"];
Send("GeneratedProxyHub", qs);
return base.OnConnected();
}
public void Send(string name, string message)
{
Clients.All.addMessage(name, "Generated Proxy Hub: " + message);
}
public static void Push(string name, string message)
{
context.Clients.All.addMessage(name, "Generated Proxy Hub: " + message);
}
}
There is nothing special in the setup between them, except for the IHubContext
in the Generated Proxy Hub (above). That is only used when calling Push()
from a controller as explained later. So the IHubContext
can be removed safely without breaking the normal functionality.
Manual Proxy Hub
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class ManualProxyHub : Hub
{
public override Task OnConnected()
{
var qs = Context.QueryString["manualProxyUser"];
ManualProxySend("ManualProxyHub", qs);
return base.OnConnected();
}
public void ManualProxySend(string name, string message)
{
Clients.All.addManualMessage(name, "Manual Proxy Hub: " + message);
}
public void ManualProxyPush(string name, string message)
{
Clients.All.addManualMessage(name, "Manual Proxy Hub: " + message);
}
}
Front-End
The 2 front-end implementations are: (best explained here)
- Generated Proxy
- Manual Proxy (without generated proxy)
The major difference being:
Generated Proxy: Gets the hub’s context in a
.js
script generated by the SignalR WebApi on page load via<script>
tags from theindex.html
1
2<script src="bower_components/signalr/jquery.signalR.js"></script>
<script src="http://localhost:9000/signalr/hubs"></script>Usage:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26var generatedProxy = function() {
// By default, the hub location is the current server
// if you are connecting to a different server, specify the URL before calling the start method,
$.connection.hub.url = "http://localhost:9000/signalr";
// Declare a proxy to reference the hub.
var generatedProxyHub = $.connection.generatedProxyHub;
// Create a function that the hub can call to broadcast messages.
generatedProxyHub.client.addMessage = function (name, message) {
addMessage(name, message);
};
// add querystring to send data to server on connect
$.connection.hub.qs = { 'user' : username };
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
generatedProxyHub.server.send($('#displayname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
}Manual Proxy: Only accessing the hubs when needed. Notice the custom
createHubProxy("ManualProxyHub")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22var manualProxy = function() {
// declare connection and proxy to communicate with the hub
var hubConnection = $.hubConnection("http://localhost:9000/signalr");
var hubProxy = hubConnection.createHubProxy("ManualProxyHub");
hubProxy.on("addManualMessage", function(name, message) {
addMessage(name, message);
});
// add querystring to send data to server on connect
hubConnection.qs = { 'manualProxyUser' : username };
hubConnection.start().done(function () {
$('#sendManualProxyMessage').click(function () {
// Call the Push method on the manual proxy hub.
hubProxy.invoke('ManualProxyPush', $('#displayname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
}
Other small differences include dynamic function calls vs event binding and invoking methods.
SignalR access from ApiController
As requests to an ApiController has a HTTP Context, we need to get the context for the Hub’s WebSocket protocol.
For ease of use I have created a static IHubContext in the Generated Proxy Hub (above) which can be used when calling the Hub’s methods from the controllers, as seen here.
1 | public class TestController : ApiController |
Resources
Demo Source Code: https://github.com/johan-v-r/SignalR
http://www.asp.net/signalr/overview/deployment/tutorial-signalr-self-host
http://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-javascript-client