Telerik blogs

Over the last year, Microsoft has introduced two new frameworks to deliver data from our web servers: WebAPI and SignalR.  With these two frameworks, we can request and interact with our own custom data services on ASP.Net enabled servers.  There are tremendous features available in both frameworks, but after some experimentation and work with both, I am ready to declare SignalR the clear winner.

In this post, I will show you the advantages SignalR has over WebAPI and demonstrate a simple asynchronous application that provides content asynchronously to attached clients.  We will redefine asynchronous web programming, and I think you will agree with me, the new definition is much more compelling.

WebAPI in Review

WebAPI is the framework that Microsoft delivered that behaves like ASP.Net MVC, with a controller pattern and adheres to the HTTP verbs that are available and managed by our web server.  WebAPI can accept data in JSON and XML format by default.  It can also be extended to support a limitless number of formats.  Of note, any client that can connect with HTTP to the server can interact with data.  The catch is that there is an unwritten rule that defines how the data is formatted to the service.  This can get frustrating, and become difficult to manage.  WebAPI provides for asynchronous controllers, that is the interaction with a controller can yield the thread they are operating on, but will maintain the connection to the client while awaiting asynchronous processes to complete.

SignalR in Review

SignalR is the latest framework in ASP.Net, the “real-time” framework that allows the server to execute methods on the client.  We are not limited to this interaction, and we can expose server-side methods to our clients.  This potentially allows for a much cleaner interaction between client and server, as all data is passed through arguments or the result of a method call.  SignalR clients are available for a variety of platforms, and a client-side shim is generated for all of the server-side methods that are exposed to the clients.

Asynchronous Data

As more and more developers are working with data frameworks on the client, the idea of an asynchronous query against the web server is becoming more and more compelling.  With an asynchronous WebAPI controller, the server will wait for all requests to finish before sending bytes over the wire to an attached client.  In SIgnalR, we can change the paradigm.

With a SignalR hub, we can call a server-side method to request the execution of a method.  As that method begins operating, we can instruct SignalR to execute a call-back method on the calling client and push the results to that client instead of waiting for entire server-side method to complete executing.  In the following sample project, I have built a simple RSS reader that uses a Telerik ListView control to present the most recent headlines from three RSS feeds – Reddit, Telerik Blogs, and TechCrunch.

Each of my three listviews has a layout markup defined like this:

<telerik:RadListView runat="server" ID="lvReddit">
    <ClientSettings>
        <DataBinding ItemPlaceHolderID="redditContainer">
            <ItemTemplate>
                <a href="#= Url #">#= Title #</a>
            </ItemTemplate>
            <ItemSeparatorTemplate><br /></ItemSeparatorTemplate>
            <LayoutTemplate>
                <div id="redditContainer"></div>
            </LayoutTemplate>
        </DataBinding>
    </ClientSettings>
</telerik:RadListView>

Code Listing 1 – ListView markup

This ListView will be bound to client-side data delivered from SignalR, so I have configured the client-side templates appropriately.  The objects that should be received and processed with this ListView will have Url and Title properties.  If they do NOT have those properties, the ListView object will ignore the object that was passed in to be bound to it.

I have my SignalR initialization JavaScript configured as follows:

var $connection;
var hubs;
 
$().ready(function () {
 
    var lists = {
      reddit: $find("<%= lvReddit.ClientID %>"),
      telerik: $find("<%= lvTelerik.ClientID %>"),
      techCrunch: $find("<%= lvTechCrunch.ClientID %>"),
    }
 
  $rssHub = $.connection.rssHub;
  $rssHub.client.PostResponseItems = function (arrItems, listToUpdate) {
 
    lists[listToUpdate].appendData(arrItems);
 
  };
 
  $.connection.hub.start().done(function () {
 
    $("#fetchButton").click(function () {
      $rssHub.server.fetchItems();
      return false;
    });
 
  })
 
});

Code Listing 2 – Client Side Script to configure SignalR

With this code, I obtain references to the client-side objects for my 3 lists that will show the headlines.  I then capture a reference to my server-side RssHub SignalR component.  More on that source code later…  I connect to the client-side functions of the hub a method called “PostResponseItems” that receives an array of items to post and a string indicating the list to update.  This method grabs the Telerik ListView object and appends the objects that were passed to it.  Finally, I start the SignalR connection, and once the connection is established I use the done promise method to connect a button I have called “fetchButton” to make requests to the server.  Notice that no other actions are taken at the time the button is pressed.  We want to have our rssHub object push data, as it retrieves it into the ListViews.  In this way, if Reddit is slow it will not prevent the other websites content from being delivered.

Server-Side Configuration – How to Configure an Asynchronous API

The rssHub defined in Code Listing 2 is a standard SignalR hub that uses Task objects to process requests in parallel and push the output of those requests to the client.  The FetchItems method referenced in Listing 2 looks like this:

public void FetchItems()
{
 
  var redditResponse = GetArticleItemsAsync(rssReddit);
  var telerikResponse = GetArticleItemsAsync(rssTelerik);
  var tcResponse = GetArticleItemsAsync(rssTechCrunch);
 
  redditResponse.ContinueWith(titles => { Thread.Sleep(5000); Clients.Caller.PostResponseItems(titles.Result, "reddit"); });
  telerikResponse.ContinueWith(titles => { Clients.Caller.PostResponseItems(titles.Result, "telerik"); });
  tcResponse.ContinueWith(titles => { Clients.Caller.PostResponseItems(titles.Result, "techCrunch"); });
 
}

Code Listing 3 – The FetchItems server-side method

I initially have the method make three requests to the rss locations for Reddit, Telerik Blogs, and TechCrunch.  The GetArticleItemsAsync method returns a Task<RssItem[]>  where RssItem is a plain-old-CLR-object that is defined to have a Title and Url property.  I complete implementing this method by instructing the response of those tasks to complete their processing by executing a method on the client machine that called this method (Clients.Caller) called PostResponseItems.  This is the method that was configured in listing 2 in JavaScript.  Coolness!

Follow me on this one…  when the request for RSS content to each of the sites completes, it will push that content to the client for processing using the JavaScript defined PostResponseItems method.  Each one of the sites will be updated independently of the others, regardless of any delays (like the Thread.Sleep I introduced for Reddit).

The final layout of the page looks like the following:



Figure 1 – Final Layout of our Sample page

Summary

In this sample, we demonstrated how we can call a server-side API and have it return data asynchronously to a call-back method on the client.  The server does not block processing between calls while it is collecting data, and can return blocks of information independent of the remainder of the actions in the server-side method through the use of a SignalR client-side method.

The source code used in this article is available for download.  A trial version of the AJAX controls is also available for download.

Telerik ASP.Net AJAX Controls - Download a trial version

About the Author

Jeffrey T. Fritz

Jeffrey T. Fritz is a Microsoft MVP in ASP.Net and an ASPInsider with more than a decade of experience writing and delivering large scale multi-tenant web applications. After building applications with ASP, ASP.NET and now ASP.NET MVC, he is crazy about building web sites for all sizes on any device. You can read more from Jeffrey on his personal blog or on Twitter at @csharpfritz. Google Profile


Related Posts

Comments

Comments are disabled in preview mode.