Click here to Skip to main content
15,867,568 members
Articles / Web Development / ASP.NET

Adding SignalR to an ASP.NET WebForms Project

Rate me:
Please Sign up or sign in to vote.
4.80/5 (13 votes)
22 May 2013Ms-PL5 min read 81.2K   37   8
How to add real-time interactivity to a website that is written with ASP.NET WebForms

In this post, I want to demonstrate how you can add real-time interactivity to a website that is written with ASP.NET WebForms. I'm going to show you how easily and quickly you can have SignalR update the content of a standard ListView webcontrol to show a 'live' log of events on your webserver.

Project Setup

For this sample, I'm going to start up a standard ASP.NET WebForms application with .NET 4.5 Once the project is created, I'm going to clear out the default content on the home page and insert my ListView control as shown in Code Listing 1:

ASP.NET
<asp:content runat="server" 
id="BodyContent" contentplaceholderid="MainContent">

    
    <h3>Log Items</h3>
    <asp:listview id="logListView" runat="server" 
    itemplaceholderid="itemPlaceHolder" 
    clientidmode="Static" enableviewstate="false">
        <layouttemplate>
            <ul id="logUl">
                <li runat="server" 
                id="itemPlaceHolder"></li>
            </ul>
        </layouttemplate>
        <itemtemplate>
            <li><span class="logItem">
            <%#Container.DataItem.ToString() %></span></li>
        </itemtemplate>
    </asp:listview>

</asp:content>
Code Listing 1 - Initial layout of the ListView

With this block configured, I can write a small snippet in the code-behind default.aspx.cs file to load some log information from some other datastore. For this example, I'm just going to bind to a List of strings to demonstrate the mix of server rendered content and dynamically added content:

C#
protected void Page_Load(object sender, EventArgs e)
{
    var myLog = new List<string>();
    myLog.Add(string.Format("{0} - Logging Started", DateTime.UtcNow));

    logListView.DataSource = myLog;
    logListView.DataBind();
}
Code Listing 2 - Code behind to load some rendered data

I should now be able to start my application and see a simple pair of lines added to the default page that appear something like this:

Figure 1 - Static Log Content

Adding SignalR to the Mix

At this point, we need to add SignalR to our project through the NuGet package manager. I prefer to use the 'Manage NuGet Packages' dialog window to add these packages, so I add the packages for SignalR by searching for and adding the "Microsoft ASP.NET SignalR JS" package and the "Microsoft ASP.NET SignalR SystemWeb" packages. At the time of this article's writing, these packages are available in the 'Pre-Release' state only.

When you craft code for SignalR, you need to write client-side and server-side code. The server-side code in this sample will be housed in a SignalR Hub.

A hub is a structure that facilitates simple communications to a collection of client systems that are listening for commands to execute.

In this project, we will create a LogHub class in C# that will allow log messages to be communicated to all listening client browsers. To simulate the repeated creation of log messages, I will use a timer to periodically transmit messages. The code for the LogHub.cs file appears below:

C#
public class LogHub : Hub
    {
        public static readonly System.Timers.Timer _Timer = new System.Timers.Timer();

        static LogHub()
        {
            _Timer.Interval = 2000;
            _Timer.Elapsed += TimerElapsed;
            _Timer.Start();
        }

        static void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            var hub = GlobalHost.ConnectionManager.GetHubContext("LogHub");
            hub.Clients.All.logMessage(string.Format("{0} - Still running", DateTime.UtcNow));
        }
    }
Code Listing 3 - LogHub source code

This hub contains 1 static event handler to listen for the timer's elapsed event. The first statement of this method gets a reference to the singleton LogHub that is running in our web server. The next statement issues a message to all clients using the "hub.Clients.All" structure. This is an interesting piece of code, as the "All" property of "hub.Clients" is a dynamic object. The "All" property is a proxy for the objects and their methods that are available to be called over the SignalR pipeline.

The object that is called over the SignalR pipeline by "All" from Code Listing 3, will be constructed in JavaScript and exposed to our hub in the following script block:

HTML
<script src="Scripts/jquery.signalR-1.0.0-rc1.min.js"></script>
<script src="http://www.codeproject.com/signalr/hubs" 
type="text/javascript"></script>
<script type="text/javascript">
    
    $(function() {

        var logger = $.connection.logHub;

        logger.client.logMessage = function(msg) {

            $("#logUl").append("<li>" + msg + "</li>");
        };

        $.connection.hub.start();
    });

</script>
Code Listing 4 - JavaScript to log messages

There are a few pre-requisites here that I need to discuss first. In my sample project, there is a reference to the jQuery library in my layout page. If you do not have that reference available, I recommend you add it to simplify the volume of JavaScript code you will be writing. Next, I have added script references to the "jquery.signalR" library to give us access to the SignalR functionality. The second reference is to a "magic URL" at /signalr/hubs. This is a virtual location that exposes the methods that the hub classes have in public scope. These methods can be called from the browser, through the plumbing established in this file.

The JavaScript in this listing is a normal jQuery enclosure, to ensure its contents do not get executed until after jQuery is loaded. The first line gets a reference to the LogHub object that we created in listing 3. We then connect a function to our client's "logMessage" property. This is the same function that is referenced in listing 3's dynamic "All" object. Thankfully, since we marked our ListView object with a static ClientIDMode and disabled ViewState, there are no hoops for us to go through to get a reference to the DOM objects that were created. In this case, we're simply going to append a list item (LI) to the unordered list (UL) with the message submitted to the function. The last line of this enclosure is very important. The start() method must always be called in order for SignalR to know to start listening for invocations from the server.

Before we can run our sample, we need to add one last piece of plumbing. We need to tell the server to expose that magic URL at "/signalr/hubs". This is accomplished by adding a line to the Application_Start event handler in global.asax.cs:

C#
void Application_Start(object sender, EventArgs e)
{
    // Code that runs on application startup
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    AuthConfig.RegisterOpenAuth();

    RouteTable.Routes.MapHubs("~/signalr");
}
Code Listing 5 - Mapping the HubsRoute

Once this line is added, we can start our application. You should see a result screen similar to the following:

Figure 2 - Static and Live Log Content

Summary

With a few simple settings on our WebForms project and the controls I wanted to modify for this sample, I was able to dramatically simplify the SignalR interactions with WebForms. In this case, I didn't run into any issues with the parts of WebForms that developers try to avoid like PostBack, Page Lifecycle, ViewState, and ClientID rendering. Next time, we'll confront those issues head on as I'll show you how to interact between SignalR and controls that post back to the server.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Program Manager
United States United States
Jeff Fritz is a senior program manager in Microsoft’s Developer Division working on the .NET Community Team. As a long time web developer and application architect with experience in large and small applications across a variety of verticals, he knows how to build for performance and practicality. Four days a week, you can catch Jeff hosting a live video stream called 'Fritz and Friends' at twitch.tv/csharpfritz. You can also learn from Jeff on WintellectNow and Pluralsight, follow him on twitter @csharpfritz, and read his blog at jeffreyfritz.com

Comments and Discussions

 
Question$.connection.logHub crashes Pin
duncanthescot7-Apr-16 12:20
duncanthescot7-Apr-16 12:20 
QuestionSmall Update on Code Pin
Ricky Stam23-Aug-15 23:47
Ricky Stam23-Aug-15 23:47 
Regarding this part of the code
C#
void Application_Start(object sender, EventArgs e)
{
    // Code that runs on application startup
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    AuthConfig.RegisterOpenAuth();

    RouteTable.Routes.MapHubs("~/signalr");

}


it's now obsolete and the project won't build.
You have to Add a Startup.cs (need to have Owin) and in there add the following:

C#
public void Configuration(IAppBuilder app)
       {
           // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
           app.MapSignalR();
       }


there was no need for
C#
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterOpenAuth();

it worked like a charm :P

***Please note that i created a completely Empty Solution and didn't need any kind of Bundling etc it was just a proof of concept what i was building
QuestionUpdates from SQL Pin
lastos2-Jun-15 22:03
lastos2-Jun-15 22:03 
GeneralMy vote of 1 Pin
Soner433523-May-14 2:10
Soner433523-May-14 2:10 
QuestionUpdates for SignalR 2.0? Pin
jovball28-Nov-13 5:00
jovball28-Nov-13 5:00 
QuestionGot a run time error. Pin
youngtexas22-May-13 9:19
youngtexas22-May-13 9:19 
AnswerRe: Got a run time error. Pin
Jeffrey T. Fritz22-May-13 15:32
sponsorJeffrey T. Fritz22-May-13 15:32 
GeneralMy vote of 4 Pin
arbinda_dhaka13-Jan-13 9:04
arbinda_dhaka13-Jan-13 9:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.