SignalR.MagicHub is a publish-subscribe framework built on top of ASP.NET SignalR, which is an Open Source Microsoft.NET-based WebSockets framework. WebSockets is an Internet standard created in 2011 that provides for a realtime communication channels to be open between a web browser and a server. MagicHub makes it possible to use a single WebSocket channel to transmit messages and data of any topic to UI components on the browser. Without MagicHub each component would have to open its own channel, which is inefficient on the browser and requires more server capacity in data center.
Read ASP.NET SignalR Documentation
git clone git@git:SignalR.MagicHub
cd SignalR.MagicHub
build && build install
By default MagicHub requires user to be authenticated. Context.User.Identity.IsAuthenticated
is used in authentication.
To disable authentication: sample Startup
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
GlobalHost.Configuration.AllowAnonymous();
}
}
For further documentation on how authentication works; see SignalR Hub Authorizaton
To add topic level authorization, Implement IAuthorize
and register in startup
GlobalHost.DependencyResolver.Register(typeof(IAuthroize), () => ClaimsAuthrorization());
See SignalR Extensibility on how to replace dependency resolver.
To listen and send messages coming on the message bus to browser clients, implement IMessageBus
and register
GlobalHost.DependencyResolver.Register(typeof(IMessageBus), () => MessageBus());
To integrate with magic-hub browser side including following javascript on the page
<script src="scripts/jquery.magichub.min.js></script>
- jquery
- json parser
For convenience magic-hub javascript packages SignalR and dynamically generated hub javascript into one file.
Magic hub doesn't establish connection unless explicitly started. To start magic hub call start:
$.connection.magicHub.start(url)
.done(function(){ console.log('Connected'); })
.fail(function(){ console.log('Houston, We have a problem'); });
- url
- string
- optional
- The
url
of the websocket domain. If url is not passed in magic-hub defaults to dynamic domain.
$.connection.magicHub.on(topic, filter, callback)
.done(function() { console.log('Thank you for subscribing'); })
.fail(function() { console.log('Why no like?'); } );
- topic
- string
- The
topic
defines the event that you would be interested to get messages on. - filter
- string
- optional
- The
filter
defines the condition that you would be interested to get messages on. Filters are defined using SQL 92 syntax and typically apply to message headers. - callback
- function
callback
would be called when magic hub receives a message on thetopic
$.connection.magicHub.on('echo', function(topic, data) {
alert("callback for echo"); });
$.connection.magicHub.on('echo', "PatientID='1'", function(topic, data) {
alert("callback for echo patientid 1"); });
$.connection.magicHub.send(topic, message)
.done(function() { console.log('Thank you for sending message'); })
.fail(function() { console.log('What's up with you?'); } );
- topic
- string
- The
topic
defines the eventmessage
is applicable to. - message
- json
message
preferred format is json
$.connection.magicHub.send('echo', { message: "hello world!" });
$.connection.magicHub.off(topic, filter, callback)
.done(function() { console.log('Thank you for unsubscribing'); })
.fail(function() { console.log('Why no like?'); } );
- topic
- string
- The
topic
defines the event that you would like to unsubscribe on. - filter
- string
- optional
- The
filter
defines the condition that you would be interested to get messages on. Filters are defined using SQL 92 syntax and typically apply to message headers. - callback
- function
callback
reference should be the same one that was used in subscription
var callback = function(topic, data) { alert("callback for echo"); };
$.connection.magicHub.off('echo', callback);
var callback = function(topic, data) { alert("callback for echo"); };
$.connection.magicHub.off('echo', "PatientID='1'", callback);
At the time of subscription for topic, filters can be provided as an argument. Filters follow the SQL 92 syntax.
Filtering has been moved into MagicHub. We support a subset of the SQL-92 syntax. The BETWEEN
operator is not supported, and dates are not supported.
The project is configured to cache filters in memory to avoid repeated parsing of the same string.
For long polling each requests go through the authentication; but for websockets once the channel is established even though session is expired the channel would not expire. To secure this there is an intelligent background worker that runs in-process which detects the session expiration. Once the session expiration is detected all subscriptions for activemq for that session is disconnected. All messages to that channel are stopped from server side.
Implement ISessionStateProvider
and register.
GlobalHost.DependencyResolver.Register(typeof(ISessionStateProvider), () => SessionStateProvider());
We have observed that one of the components we use sometimes experiences a timeout when subscribing to a topic. Despite this, everything seems to continue functioning according to specification. We have only observed this for connections using the longpolling transport. In order to monitor this, we log a warning
Groups add seems to have timed out. ConnectionId=GUID Topic=TOPIC Filter=FILTER
To log any unhandled exception NLog + NLog.Syslog formatter can be used. NLog configuration can be found in Web.config. Out of the box there is a single log target defined: Event Log. All messages with minimum level of "Warn" will be sent to Event Log.
Any exceptions on client side are logged to browser console window.
Messages can be traced by setting tracing_enabled:true
in the json body. When tracing is enabled in the message, the message is logged. On the server side message is logged to Trace listener; On the client side message is logged to console window.
On the server side, there will be up to 4 messages in the event log / splunk:
- [only if application sends message, which doesn't happen currently].
Receiving message (nnt:trace-test0): {"message":"","tracing_enabled":true}
- [see below] message with tracking id when ServiceHost component receives message from bus
- When MagicHub receives message from ServiceHost
Received message from messagebus (nnt:trace-test0): {"message":"","tracing_enabled":true}
- When MagicHub dispatches the message to SignalR to send to the web browser
Sending message (nnt:trace-test0): {"message":"","tracing_enabled":true}