Tag Archives: asp.net

Adding SignalR to an ASP.Net WebForms Project

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.

UPDATE Jan 28, 2013: I have uploaded the source to this post to my GitHub account.  Go get some sample code!

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: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:

        protected void Page_Load(object sender, EventArgs e)
        {

            var myLog = new List();
            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-sharp 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:

    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();
            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:

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

        var logger = $.connection.logHub;

        logger.client.logMessage = function(msg) {

            $("#logUl").append("<li><span class="logItem">" + msg + "</span></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:

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 Hubs Route

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.

ASP.Net AJAX Controls for MVC developers

I’ve been spending a bit of time over the past month looking into ALL of Asp.Net, not just MVC or SignalR or WebAPI.  I’ve even gone back and spent some time with good old WebForms.  When we think back to ASP.Net webforms, many of us cringe and get upset when we think about ViewState, ClientId naming, and PostBack processing.  However, I think there are some really good things in WebForms that many of us need to be reminded of.  Let’s take a look at a quick sample, comparing a “modern” MVC AJAX approach to a web page being built with the tried and true WebForms approach.

Our Data Sample

To start, I’m going to create an MVC4 project in Visual Studio and add the EntityFramework.SqlServerCompact nuget package.  With this in place, I created a Product object and a simple data context using Entity Framework Code First:

    public class Product
    {

        public int ProductId { get; set; }
        public string Name { get; set; }
        public string Manufacturer { get; set; }
        public decimal Price { get; set; }

    }

    public class ProductContext : DbContext
    {
        public DbSet Products { get; set; }
    }

    public class ProductDbInitializer : DropCreateDatabaseAlways
    {

        protected override void Seed(ProductContext context)
        {

            var checkers = new Product()
            {
                ProductId = 1,
                Name = "Checkers",
                Manufacturer = "Milton Bradley",
                Price = 5.99M
            };
            context.Products.Add(checkers);

            var chess = new Product
            {
                ProductId = 2,
                Name = "Chess",
                Manufacturer = "Parker Brothers",
                Price = 8.99M
            };
            context.Products.Add(chess);

            var backgammon = new Product
            {
                ProductId = 3,
                Name = "Backgammon",
                Manufacturer = "Hasbro",
                Price = 12.99M
            };
            context.Products.Add(backgammon);

            var connectFour = new Product
            {
                ProductId = 4,
                Name = "Connect Four",
                Manufacturer = "Milton Bradley",
                Price = 7.49M
            };
            context.Products.Add(connectFour);

            base.Seed(context);
        }

    }

Note the DbInitializer class – this will create some seed data for us to display in this sample.  

The ‘standard’ MVC approach

Typically, an MVC view will output a grid of data with a simple for-loop over some data.  With the razor-formatting engine, this becomes a trivial piece of work in our view:

        @foreach (var product in Model)
        {
            
                @Html.ActionLink(product.Name, "Details", new { id = product.ProductId })
                @product.Manufacturer
                @product.Price.ToString("$0.00")
            
        }

This is a simple approach that dumps the data to screen.  For a prototype it may be enough, but in today’s web, we want something more dynamic.  We’d prefer an AJAX solution that allows us to search, sort and flip through pages of content.  

If you’re like me, you went looking for a jQuery plugin to do some of this work for you.  There are a number of great grid controls available like KendoUI or jqGrid.  I first used the jqGrid and ran into configuration after configuration that was undocumented that I needed to test and ensure behaved the way I needed it to.  Then I had to chase down a handful of additional methods I needed to add to my MVC controllers to perform the search and sort operations.  After that, I had to update those controller methods to handle paging.  All in all, I ended up adding more server-side methods in my MVC controller and writing client-side javascript wrapper methods for the grid control to simplify my data access needs.  I could move my data searching and sorting methods on the server-side into an ApiController, but my problem remains the same: I’m writing a lot of code to massage the data in the grid to fit my user’s needs.

The WebForms AJAX way

If we go back to the WebForms technique using the standard gridview control, we could directly databind to our Products DbSet in our context.  Our construction steps would be as simple as this:

    1. Drag a LinqDataSource onto the webform designer surface
    2. Configure the LinqDataSource to connect to our ProductContext and use the Products dataset
    3. Drag a GridView onto the webform designer surface
    4. Connect the GridView to the LinqDataSource
    5. Configure the GridView to enable paging and sorting

    Done.. I’ve written no code, and using only the designer tools I have a functional grid. However, this doesn’t have the cool filtering and AJAX features like our jqGrid.  We can theme the GridView easily, but its still not quite… polished.  We would need to add additional controls to the page and additional code to connect some filter controls to the grid.

    Enter a commercial grid

    A commercial grid control will take our capabilities on the WebForm even further, with even less work.  Let’s consider the Telerik ASP.Net Grid… With Telerik’s grid, we need to configure our web project to handle the Telerik controls by adding some entries into web.config.  These can be copied directly from another Telerik ASP.Net controls  project.   Once those settings are in place, adding and configuring our grid is as simple as:

    1. Drag a LinqDataSource onto the webform designer surface
    2. Configure the LinqDataSource to connect to our ProductContext and use the Products dataset
    3. Drag a RadGrid onto designer surface
    4. From the RadGrid smart-tag, click the linkbuttons to add the RadScriptManager and RadAJAXManager
    5. From the RadGrid smart-tag click the checkboxes to turn on the sorting, filtering, and paging functionality as desired
    6. From the RadAJAXManager smart-tag, click the checkboxes to enable the RadGrid as an AJAX trigger and enable the RadGrid as an AJAX target

    Without any coding, using just the designer tools, I’ve completed the task again.  We now have a grid that will sort, page, and filter on AJAX queries back to the website. Additionally, we can turn on other cool functionality that is built in to the control like “Column Grouping”, “Export to Excel” or “Export to PDF”.  Once again, no coding is needed to enable this functionality.  The volume of features in these commercial controls is amazing, and they really are worth it when you look at the time it would take you to build each of these features.  There are significant templating and coding options available if you want to turn this Telerik grid into something more unique for your customer.

    Summary

    The amount of hand coding and mix of client and server side coding to make an MVC solution work just takes too much of my valuable development time.  I can put together a great looking webpage very quickly using a WebForms approach.  Finally, I can make that WebForm really shine if I use a set of controls from a vendor that are really polished.  Asp.Net developers, don’t limit your projects to just MVC or WebForms.  Try mixing and matching capabilities to make your development tasks easier.

    kick it on DotNetKicks.com

    Future is set: Telerik Asp.Net AJAX!

    After last week’s events, the floodgates of opportunity opened, and I evaluated my options very closely.

    It is with great pride that I announce:  On December 3rd I will be a Developer Evangelist with the Asp.Net AJAX product team at Telerik!

    I’ve been a (quiet) fan of Telerik tools for the past two years.  It’s hard to miss the advertisements on the trade magazines, podcasts, and websites that I consume regularly.  After reviewing a handful of Telerik tools, they grew on me.  I’ve used JustCode for the last few months and find it to be a valuable asset in my daily coding tasks.  I’ve been using the AJAX Controls in a handful of prototypes and really enjoy the flexibility offered to me without having to focus on UI work.  It’s a good fit for me, as I believe I can share my infectious enthusiasm for this technology with others and bring great value to Telerik.

    I’m going to still be the wise-cracking passionate Asp.Net developer.  I’m not going to turn into the Sham-Wow guy for Telerik overnight… but I will be using the Telerik tools in everything that I do.  

    Those of you who have worked with me know: I am a very loyal and passionate employee who goes out of his way to ensure the success of my employer and my customers.  This is not a position I take lightly, and I feel that this attitude matches the role of Evangelist perfectly.  As an evangelist, I’ll be the technical conduit between sales, customer service, marketing, and the dev team.  I’m going to help take an award winning product and make it even better.

    A colleague at my previous employer, after watching me coach a junior developer in a coding technique of some sort commented to me: “Jeff, you’re such a good trainer – you should do this more often.”  Little did I know at that time, just how right she was.  I presented at the Philly Code Camp last weekend (wrapup post to come), and that teaching buzz grabbed me after my session on SignalR, and it was then that I knew that I was so right for this position.

    Over the next few weeks, you’ll see my blog ramp up.  I’ll be migrating to a better engine, a better layout, and LOTS more content.  You’ll see my twitter activity ramp up, my StackOverflow interactions ramp up, and most of all: you’ll start to find more video content from me.

    The best part about this:  I will not be limited to my budget, or INETA’s budget in my travels to present at your event.  We’ll soon see what my availability looks like, but I’ll be doing a lot more travelling to some places that would NEVER be on my current travel itinerary.  I’m already getting my passport renewed so that I can depart from my friendly confines of the Northeastern United States to bring the good word of Asp.Net and Telerik to conferences and User Groups around the world.

    My family and I are positively thrilled about this change, and I know that my teammates at Telerik are VERY eager for me to get started.  Stay tuned friends, because you’re going to get a lot more great content from yours truly!

    Personal Asp.Net with IISExpress builds

    Recently, I ran into an issue where my team wanted to run their local Asp.Net project builds so that their IISExpress instances were visible to the other team members.  This is a non-trivial setup, as a simple checkbox in the Asp.Net project properties window activates IISExpress to host the project, but does not make it visible outside of the local machine.

    To configure IISExpress to answer to other names (besides localhost) the following steps are needed:

    From an administrative command prompt issue the following command:  

    netsh http add urlacl url=http://mymachinename:50333/ user=everyone

    “mymachinename” is the hostname that you want to respond to, and 50333 is the port that Visual Studio assigned to my project.  Your port may be different, change this value to match the port that Visual Studio assigned to you.

    In the applicationhost.config file at %userprofile%DocumentsIISExpressconfigapplicationhost.config find the website entry for the application you are compiling and add a binding like the following:

    <binding protocol="http" bindingInformation=":50333:mymachinename" />

    Finally, restart IISExpress to force the web server to re-load the settings you have just changed.  This should allow the service to answer to the appropriate host.

    However, if you would like to configure Visual Studio to launch and browse to “mymachinename” instead of localhost, you need to change 1 more setting in your web project’s config.  On the “Start Action” section, set this to start with a ‘Specfic Page’ and key in the appropriate full machine name and port combination in the textbox to the right.

    This preference entry is saved in the YOURWEBPROJECT.csproj.user file. By making this decision, you will allow the .csproj file to be checked in to your source control without impacting the other members of your team.