ASP.NET SignalR and LightSwitch (VS 2012 Update 2, VS 2013 and later)!!!


 Update – I uploaded the code and project to MSDN Code Gallery here: http://code.msdn.microsoft.com/LightSwitch-and-SignalR-4d7ff7a8 

 I have updated the article to work with the latest version of SignalR on NuGet (which is currently version 2.0.3) – also feel free to test out this feature here on this website we made to show off SignalR with LightSwitch: http://signalrlightswitchapp.azurewebsites.net/htmlclient/ 

SignalR? What is that?

SignalR is described as “Incredibly simple real-time web for .NET”.

It’s a great way for a JavaScript client to call directly into Server side methods, and a great way for the Server to push up updates or notifications to the JavaScript client.

I heard a couple people raving about SignalR recently, and figured it was time to see if we could get LightSwitch and SignalR to meet.

LightSwitch…meet SignalR

We’re going to make a simple LightSwitch (LS) application here. And then we are going to use SignalR to push up some real-time notifications to the LightSwitch HTML Client.

We’ll end up with a LS HTML App that receives a notification every time a new entity is inserted or updated.

This would allow for any user to know when ever data has been changed.

Let’s start out with a simple “Contacts” LS app.  Everything here should be pretty basic if you’ve done any LS stuff before.

  1. Create a new project – LightSwitch HTML Application (Visual C#)
  2. Call it – “ContactsSignalR”
  3. Add a table – call it “Contact”
  4. The table should look something like this when you are done:
  5. image
  6. Now let’s make a simple HTML Browse Screen around the “Contacts” data
  7. In the screen designer, select “Screen | Browse Contacts (Browse Screen)” and set the property “Behavior – ScreenType” to “Edit”. This will enable the “Save” button to show on our screen.
  8. Now let’s add a data item to our screen – so in the Screen Designer click your “Add Data Item…” button
  9. image
  10. That’ll open up a dialog – let’s call this property “updates” and make sure “Is Required” is unchecked. It should look like this:
  11. image
  12. Now drag and drop your updates data item onto your screen – put it right below the “Command Bar” so that it looks like:
  13. image
  14. Select the “updates” control on the screen designer and set the following properties:
    1. Label Position: Hidden
    2. Font Style: Large
  15. We’ll use this control later on to post our “real-time” updates to the screen
  16. Now I’d like to be able to Add and Edit new Contacts entities here, so select the Command bar, right click and say “Add button”
  17. Select Contacts.addAndEditNew and Navigate To: New Screen like this:
  18. image
  19. This is a easy way to quickly create a new Add/Edit screen for the Contacts entity
  20. Important! – After the screen is created your Screen Designer changes to show the AddEditContact screen. Make sure you double click the “BrowseContacts” screen again to set focus back.
  21. Do the same thing again – add an EditSelected button this time for the existing screen you just made, like this:
  22. image

 

Basic App is done. Onto SignalR

At this point, we’ve basically made a simple LS App to add and edit new Contacts.

Now we need to shove in some SignalR.  To do that we first need to “NuGet” our projects.

    1. In the Solution Explorer toolbar switch to “File View” like so:
    2. image
    3. Now right click the HTMLClient project and select Manage NuGet Packages:
    4. image
    5. Now select Online packages, search on SignalR and install the below entry:
    6. image
    7. This will add the SignalR JavaScript references to your HTML Client
      1. If you get an error here about NuGet package not being applied correctly, then double check that you selected the JavaScript Client SignalR package and NOT the .NET SignalR package (we apply the .NET SignalR package on the Server later)
    8. But we need to add them to the default.htm file as well, so open up that file and these two lines:

<script type=”text/javascript” src=”Scripts/jquery.signalR-2.0.3.js”></script>
< script src=”../signalr/hubs”></script>

  1. The first line is a reference to the SignalR library
  2. The second line is actually a reference to some JavaScript that will be dynamically generated by our SignalR server later on.
  3. Now right click the Server project, and select “Manage NuGet Pacakages…”
  4. This time we want to install the SignalR package for .NET server components:
  5. image

 

NuGet is done. Put SignalR code into the Server!

We’ll need to add some Server side code here to start up the SignalR Server Hub. And to allow for the client and the server to talk to each other.

      1. Right click the Server project again and say “Add –> New Item”
      2. This time add a “Web Api Controller” class to our project.
        1. We only do this because it will automatically pull in some dll references for us that we’ll need later.
      3. Right-click the solution, and select Add, New Item…. In the dialog, select Owin Startup Class. Name the new class Startup.cs.
      4. image
      5. Replace the contents of Startup.cs with the following code:
3.    using Microsoft.Owin;
4.    using Owin;
5.    
6.    [assembly: OwinStartup(typeof(SignalRChat.Startup))]
7.    namespace SignalRChat
8.    {
9.       
10.        public class Startup
11.        {
12.            public void Configuration(IAppBuilder app)
13.            {
14.                app.MapSignalR();
15.            }
16.        }
17.    }
      1. This code will get called when our LS app starts.  It starts up the SignalR server hub so that the clients can connect to it.
      2. Right click your Server project and add one more file – a class file and call it ContactHub
      3. Past the below code into your class:
using Microsoft.AspNet.SignalR;
namespace LightSwitchApplication
{
    public class ContactHub : Hub
    {
    }
}
All we are doing is creating our own Hub here that we’ll use later to talk to the client from the server.

Put SignalR into the Client!

We need to put some basic JavaScript code into our Browse screen so that it can modify the “updates” label, and so that the Server has a function to call on the Client.

    1. Open up the Browse Contacts screen
    2. Select the Write Code – create method:
    3. image
    4. This is where we’ll add our basic JavaScript. So copy and paste the below code into the BrowseContacts.js file
/// <reference path="../GeneratedArtifacts/viewModel.js" />
/// <reference path="../Scripts/jquery.signalR-2.0.3.js" />

myapp.BrowseContacts.created = function (screen) {
    // Write code here.
    $(function () {
            
        contact = $.connection.contactHub;
        contact.client.broadcastMessage = function (message) {
            screen.updates = message;
        };     

        $.connection.hub.start()
        .done(function () {
        })
        .fail(function () {
            alert("Could not Connect! - ensure EnableCrossDomain = true");
        });
    });
};
  1. Here’s what this does:
    1. $.connection.contactHub <- This is our connection to the ContactHub we made on our server
    2. contact.client.broadcastMessage <- this is the JavaScript function we are going to invoke from the Server (which we’ll do shortly).  This function will set the “updates” screen item with some text.
    3. $.connection.hub.start() – this just “starts” up the connection from the client to the SignalR Hub

Almost done! Let’s have the Server call the Client.

We need one final piece here – call into the JavaScript client every time a Contact is inserted or edited.

    1. Open up the Contacts entity (make sure the “Server” is selected here and not the Client)
    2. Select Write Code – > Contacts_Inserted
    3. Paste in the below code:
        partial void Contacts_Inserted(Contact entity)
        {
            string message = "A contact for " + entity.FirstName + " " + entity.LastName + " was just created";
            var context = GlobalHost.ConnectionManager.GetHubContext<ContactHub>();
            context.Clients.All.broadcastMessage(message);      
        }
    1. This will call the the “broadcastMessage” JavaScript function we wrote earlier for ALL active LightSwitch clients when a Contact is inserted. When that function is called – the updates label will automatically be updated to show our message.
    2. Do this again for the Contacts_Updated method. So open up the entity again. Select Write Code –> Contacts_Updated.
    3. Paste in the below code:
        partial void Contacts_Updated(Contact entity)
        {
            string message = "A contact for " + entity.FirstName + " " + entity.LastName + " was just updated";
            var context = GlobalHost.ConnectionManager.GetHubContext<ContactHub>();
            context.Clients.All.broadcastMessage(message);
        }
  1. Same thing here as the Inserted method, except it will only be called when a Contact is updated.

 

That’s it! F5 it and hang on.

F5 the LS app to build it and run it.

A browser should launch.

Go ahead and create a new Contact and Save it.  You should see something like this after you save.

image

This is cool…BUT try this with 2 browsers opened to really blow your mind.

So launch another instance of your web browser.

Copy and paste your http://localhost:NNNN/HTMLClient URL from your first browser into the second browser’s address bar.

Now create another record again. You’ll see this:

image

 

Both browsers got updated at the same time!

That’s pretty awesome, IMO.

So awesome, that I had to make a YouTube video for it:

 

Please feel free to leave any feedback, and I’ll post my app up on Code Gallery for others to check out (will update this once the application is available).

Thanks All!

Comments (32)

  1. adefwebserver says:

    Yes!

  2. Robert Langer says:

    Hi Matt,

    Yes, SignalR is great; thanks for the example with HTML Client!

    To refine your sample a little bit: What to do on the client to refresh the data (contacts list)on notification by SignalR? Add the new contact / refresh an existing… Any suggestion?

    Best Regards, Robert

  3. @Robert – A good place to invoke an auto-refresh of some kind would be the SaveChanges_Executed/Failed.  You could call back into the some HTML Function that simply does a Refresh. Javascript function would be something like: "window.location.reload(true);"

  4. Paolo says:

    Hi Matt, strange issue here, I can't add that code working in global.asax.cs because I can't add system.web.http reference !!! It seems to be vanished and I can't say why. Could you gimme some hint ?

    Thanks in advance.

    Ciao.

  5. PAOLO –

    Did you try this step below?  That should add the dll's that you would need…If that doesn't work let me know.

    -Right click the Server project again and say “Add –> New Item”

    This time add a “Web Api Controller” class to our project.

    -We only do this because it will automatically pull in some dll references for us that we’ll need later.

  6. Hi Matt,

    This is great! Is there any way of getting this to work with the Silverlight client? I know the HTML client is all the rage at the moment, but there are still plenty of us using the Silverlight client as the primary front-end, and something this would be hugely useful there as well.

    Thanks

  7. @Mr Yossu – You bet man. Silverlight Client is still important enough to have SignalR work with it – github.com/…/wiki You can check out the .NET Client portion of that wiki. Also check out this thread – forums.asp.net/…/1

  8. Paul Pitchford says:

    I tried posting a problem I had here earlier and it turned out to be a typo from copying and pasting your code. If you see it probably best to just not post it! 🙂 Thanks for a great post, this is working great. Paul.

  9. Hi Matt,

    Thanks for the reply. That post you linked mentioned SL5 specifically. Is there any problem with SignalR and SL4? I still have to use VS2010 for some Lightswitch apps (which isn't actually a bad thing, as it's much faster!), and that only targets SL4.

    Thanks again.

  10. @Mr Yossuf – Sorry man 🙁 – No support for Silverlight 4.0. I double checked with the SignalR team.

    I am very interested though in hearing about what is faster with your VS 2010 LS Apps?  You do mean like the Client load time? Or just designing is faster?

  11. Hi Matt,

    I (like many others) find that the new version of LS is slower at loading and saving data that the first version. I think this is because Microsoft forced oData on us, without giving us the option of what to use. The data format requires more bandwidth, which results in slower applications. Silverlight is noticeably slower than HTML-based apps anyway, and oData just slowed it down even more.

    I know quite a few developers who are put off using VS2012 for Silverlight-based Lightswitch apps for just this reason.

  12. JMontoya says:

    I am trying to use test this sample with jquery.signalr-1.1.1.js but I keep getting the following error:

    Unable to get property 'client' of undefined or null reference. I am aware of the camel notation: so I am using

       [Microsoft.AspNet.SignalR.Hubs.HubName("flashHub")]

       class FlashHub : Hub

    on the server side and :

          flash = $.connection.flashHub;

           flash.client.broadcastMessage = function (message) {

               screen.Updates = message;

           };

    on the client side. Any ideas what else can be wrong. Thanks in advance.

  13. Roger says:

    I had a few caveat’s to overcome to make this work.

    Needed to add the reference System.Web.Routing, and add the following using statements to the global.asax , ContactHub.cs, and the ApplicationDataService (i.e. within the inserting and inserted methods).

    using System.Web.Routing;

    using Microsoft.AspNet.SignalR;

    Make sure to install your script referencess in the correct order and after jquery-1.8.2.min.js and jquery.mobile-1.2.0.min.js within the default.htm file

    Make sure your referencing the latest version of SignalR. Ensure this reference is updated within the BrowseContacts.js file as well. As at now, the script reference should be:

    <script type="text/javascript" src="Scripts/jquery.signalR-1.1.2.js"></script>.

    And finally, SignalR will not run within Internet Explorer without json2 installed. You will need to download it into your Client’s script folder via nugget, and reference it between the jQuery and SignalR references, so your default.htm script references will look similar to this:

       <script type="text/javascript" src="Scripts/jquery-1.8.2.min.js"></script>

       <script type="text/javascript" src="Scripts/jquery.mobile-1.2.0.min.js"></script>

       <script type="text/javascript" src="Scripts/json2.min.js"></script>

       <script type="text/javascript" src="Scripts/jquery.signalR-1.1.2.js"></script>

       <script src="../signalr/hubs"></script>

    Hope this helps anyone else who is a HTMLClient/javascript newbie such as myself.

    Cheers,

    Roger

  14. What would really be mind blowing is how to send a message a the user client only which made the change in the record.

    Looks like the connectionID needs to be mapped to the user, which I am struggling in trying to accomplish within the Lightswitch context.

    A follow up blog in how best to accomplish this would truly be amazing.

    Roger

  15. @DedoOne – Hey Dedo.  Totally agree (it isn't trivial to do for sure, and I think it would be way cooler if it could be done).

    I was talking with someone yesterday about this on my team, and he gave me another idea to try. I'll see what I can do as far as getting more details. But if you could set a cookie on the HTML client that contains the client's "SignalR Id" (do this using JQuery – $.cookie("yourId")). And then somewhere (I don't know where yet) on the server side you could parse this cookie off the HTTP Request and that way you could track which client had made the request…Just a thought for now, I know I'm short on implementation details here.

  16. @MrYossu – OData is only part of the problem here, but you're right that ODATA was considerably more verbose than our old RIA format. I say "was" because now (ever since Update 2 of LightSwitch for sure) the Silverlight Client uses the "minimalMetadata JSON" format when talking with the Server. This is WAY less data going across the wire so way less bandwidth. We are talking about something like 80% less data for a Northwind Orders entity for example.  So I actually think we are very close to being on par with the RIA bandwidth usage now.  There are numerous other issues that arise from poor designs of one's SL Client (which I'm sure you already know about).  Do feel free to post your performance issues over on the MSDN Forums for LightSwitch. This really does help to raise awareness.  Thanks – Matt S

  17. @JMontoya – did you ever get this figured out? Sorry for the delay.  Check out Roger's post which fills in some details I apparently left out.

  18. Guy Godin says:

    In my opinion a feature like this should be built-in LightSwitch. A simple boolean property could be added to the Layout Item in the designer (something like "Enable Change Notifications") and LS would take care of  wiring up the required calls (since it knows how to do all this already).

    Just a thought

    Guy

  19. tobykraft says:

    global.asax.cs also needs using System.Web.Http;

  20. Thomas says:

    Does anyone has a Instruction (or little VS 2013 VB Project) to use SignalR 2.0.0 (or 2.0.1) with LS HTML Cleint?

    I tried it for Hours and cant get it to work. I tried the "Update vom signalr 1.x to 2.x" from the signalr blog but cant get it to work.

    Greets

    Thomas

  21. Hessc says:

    Yes, please update this post to work with current SignalR!

  22. Matt Sampson says:

    @ALL – I have heard you.  Will take a look at this here and see what I can get working

  23. DarkSideNRW says:

    Hi Matt,

    any idea how to get signalr 2.x to work with LS 2013?

    i tried it several times but cant get it there.

    Greets

    Thomas

  24. Matt Sampson says:

    @All – OK so definitely the NuGet package is no longer successfully being applied. And I'm following up with people here on my Visual Studio team. In the meantime I encourage you to read this thread for a possible workaround and explanation – social.msdn.microsoft.com/…/websockets-dont-work-when-using-signalr-200-with-lightswitch-2013

  25. Dat AU DUONG says:

    Hi Matt,

    Can you update the Article on "Put SignalR code into the Server", when I follow up to here the code is now changed because nugget now have the SignalR 2.

    I don't know where to start (EnableCrossDomain = true) has been removed. Also Does Step adding Web API Controller still require ?

    Thanks.

    Regards Dat.

  26. Dat AU DUONG says:

    Hi Matt,

    Thank you for the article.

    In case someone are doing the same thing.

    I was able to get it to work with the following step with VS2013 – SignalR-2.0.0.3,

    With the following changes to the article:

    0. Basic App is done. Onto SignalR (Step a. is not needed in VS2013)

    1. The following Script Reference bellow need to be below the <script .ready(function() … in default.htm

    <script type="text/javascript" src="Scripts/jquery.signalR-2.0.3.min.js"></script>

    <script src="../signalr/hubs"></script>

    2. With the help of article Upgrading SignalR 1.x to 2.0

    I have ignore the step adding global.asax

    then

        follow step Adding OWIN Startup class – (Step 6 and 7 in article Upgrading SignalR 1.x to 2.0)

    then continue Matt article Adding ContactHub

    3. in the step d. put SignalR into the Client copy and paste code into the BrowseContact.js file remember to change

    your: /// <reference path="../Scripts/jquery.signalR-2.0.3.js" />

    Follow to the end of Matt article.

    wola, run your app and it work.

  27. R. T. Watkins says:

    This no longer appears to work in the current version of SignalR (2.1.0). I've tried on two different VS2013 Update 2 machines, and no matter what I do, I get the Failure message referring to cross-domain enabling (probably not the real error, as that's just the only error message defined in the example.) I've tried correcting the Namespace in step 5e of "Basic App is done" to both the Project name and "LightSwitchApplication" instead of "SignalRChat", but neither seems to have any effect. I've tried enabling JSONP and OWIN.Cors, but those don't work either. Adding the WebController class (Step B under "NuGet Is Done…") doesn't seem to affect the server one way or the other, too.  

    Anyone have any ideas?

  28. R. T. Watkins says:

    Addendum: Just downloaded the code sample with 2.0.3, compiled it, and it works.  Then I tried updating its Packages to 2.1.0, and I get the same error I did when starting from scratch.  Looks like there is definitely something in 2.1 that broke the 2.0.3 functionality.

  29. Gene says:

    I got the same error as you. I changed the fail function to take in the error.

               .fail(function (error) {

                   console.log(error);

               });

    "No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization."

    Anyone can help?

  30. Gliter Zhang says:

    maybe it's the matter of hub proxy

    try to establish a connection manually:

    http://www.asp.net/…/hubs-api-guide-javascript-client

  31. R.T. Watkins says:

    Just to let everyone know that this example now works once again on VisualStudio 2013 Update 4 with SignalR 2.2.0. I did need to add "using Microsoft.AspNet.SignalR;" to the top of the ApplicationDataService.lsml.cs file (this is the file you add the Contacts_Inserted and Contacts_Updated functions to, so just add the using clause while you're doing that step.)  It was also unnecessary to change the namespace on the Owin class (Startup.cs) to "SignalRChat", as the default namespace of "LightSwitchApplication" works fine.

  32. Isaac says:

    Hello all!  Love this example…I'm working on a LS HTML app does some heavy and long processing server side…i'd like to wire up a "real time progress bar" using SignalR (i think its the best solution for this)….I've tried to follow this example (westcountrydeveloper.wordpress.com/…/client-server-progress-bar-using-signalr) but can't quite figure it all out.  Anyone have any ideas for examples?

    Thanks in advance!