two stacks of rounded river stones

A Nice Pairing

Silverlight and ASP.NET AJAX

Creating Silverlight 1.0 applications can be much like creating typical HTML-based pages. Very often it is about displaying information to the user to entertain, inform, or educate. HTML and Silverlight both do this quite well. But in today s world, the Internet browser is fast becoming an application platform itself. This means you can create truly interactive applications directly in the browser. Silverlight is a natural solution for creating these experiences on the Web and in the browser. In this same sense, these interactive applications would like to be able to communicate with data centers and servers. Because Silverlight 1.0 applications exist on traditional Web pages, we can use well-worn techniques for communicating with the server. This is where ASP.NET AJAX presents a great opportunity to repurpose this technology for use with Silverlight. In this article, I ll dive into the why and how of using ASP.NET AJAX with your Silverlight applications or controls.

The Problem

Creating standalone applications with Silverlight can be very compelling. The first time you create a media player or game with Silverlight is an exciting time. But in the majority of cases, the real power of Silverlight applications will be in creating connected applications.

At first blush, many developers new to Silverlight find it difficult to understand that they are writing applications meant to be running within the client s browser. The Silverlight story is all about running client-side code. The drawing palette and animation stack are great, but it is forcing us as developers to look at writing code that runs in the client again. This is a jarring experience for many ASP.NET developers. Many may have become complacent, trying to do all the coding on the server to avoid the complexities of the client-side development model.

Once the connected application development is being done on the client, we must have a cohesive way to communicate with the server. We could write Web services for the communication layer, but calling Web services from client code is often difficult and complex. In addition, it would be nice if we had a way of writing our client code to hide some of the cross-browser bugs that tend to cause problems between the way different browsers have interpreted the specifications (or to what extent they ve implemented those standards). That s where ASP.NET AJAX can really help us integrate with Silverlight, as well as much of the code we are going to write on the client.

Pairing Silverlight with ASP.NET AJAX

Using your Silverlight application with ASP.NET AJAX is a natural pairing, as AJAX is all about providing services to the client-side code. Let s start with a simple Silverlight control that shows a star rating that allows users to select a rating (see Figure 1).

Figure 1: A simple Silverlight ratings control.

To convince you of the natural pairing with ASP.NET AJAX, I ll show you two types of integration. We ll host our RatingsControl in an AJAX page, then create a Web service that allows us to communicate bi-directionally with the server.

Hosting Silverlight with ASP.NET AJAX

Like other Silverlight projects, we need to use the Silverlight.js API to load our control on to our page. This is normally done with a JavaScript function named createSilverlight, which is generated by the Silverlight 1.0 templates. In our example, I ve renamed this function as createRatingsControl, and added a parameter for the HTML host so I can host this multiple times on a single page (see Figure 2).

function createRatingsControl(host)
{
 var scene = new RatingsControl.Page();
 Silverlight.createObjectEx({
   source: "Page.xaml",
   parentElement: host,
   id: "SilverlightControl",
   properties: {
     width: "150",
     height: "25",
     version: "1.0",
     isWindowless: "true",
      background: "transparent"
   },
   events: {
     onLoad: Silverlight.createDelegate(scene, scene.handleLoad),
     onError: null
 });
}

Normally, the template calls this creation function within a script block on a particular HTML (see Figure 3).


 
   RatingsControl
   
   
 
 
   

In this approach, we are loading the scripts required in the header and calling the creation function (createRatingsControl) in the body of the div that we want to host our Silverlight control. The problem with this approach is that for a simple HTML page, we can be virtually certain the scripts will load in time for the function to be available once the div is reached. As a page gets more and more complex, it becomes more difficult to be certain about the load order of scripts. We could move the script block to the end of the page to increase the chance that the scripts are loaded in time.

Luckily, ASP.NET AJAX comes to the rescue by providing a couple of services that help us solve this problem. Using ASP.NET AJAX requires that we use a server-side control called a ScriptManager. As we ll see in this article, the ScriptManager control provides a number of services to our page. To get started with solving our loading issue, let s first drop a new ScriptManager on our page (see Figure 4).

<%@ Page Language="C#"
        AutoEventWireup="true"
        CodeBehind="Default.aspx.cs"
        Inherits="RatingTester._Default" %>


 
   Ratings Control Tester
 
 
   

By including this control, we are effectively telling the page to be prepared to use some AJAX functionality. Next, we need to add our scripts to our new AJAX-enabled page. To do this, we d normally add script tags to the page (usually in the header) to import them into our page. In ASP.NET AJAX, we ll instead allow the ScriptManager to manage them for us. The benefit of using the ScriptManager is to ensure that the scripts are loaded in a timely fashion, as well as ensuring that every script is only included once. The duplication functionality in the ScriptManager may not seem obvious, but as you use master pages and controls, you might run into multiple places where the same script might be required by different parts of a particular page. But using the ScriptManager, it guarantees that all the scripts on a particular page are not repeated (which can cause a number of different issues).

To let the ScriptManager import our scripts, we ll add a new Script tag inside the ScriptManager, then add each of our scripts inside that new tag (see Figure 5).


 
   
   
 

Once our scripts are imported using the ScriptManager, we can add a new div to host our Silverlight control:

This is a tester for the RatingsControl. Please select a rating!

We now are ready to load our Silverlight control into the div named ratingHost. Instead of arbitrarily loading a script somewhere on the page, hoping it is called only after the scripts are loaded on a page, we can use another service of ASP.NET AJAX: the pageLoad function. ASP.NET AJAX supports a specially named function, pageLoad, that is called after the scripts are loaded. It s like an OnLoaded event in ASP.NET. To use it, simply define it on a particular page (see Figure 6).

Note that this function is case-sensitive (so make sure it is capitalized as pageLoad). In Figure 6 you should see that we are calling the createRatingsControl, just as we did earlier in the div s script block. The only change is that we are using another feature of the ASP.NET AJAX framework, the $get function. This function is a cross-browser-friendly version of document.getElementById (or similar methods). Not only is it easier to type, but it will work on more browsers than even Silverlight.

We now have our control hosted on an ASP.NET AJAX page and, by using some of the services provided, we should have a more stable story than we would ve had in traditional ASP.NET hosting of the Silverlight control. Next, we ll delve into the communication with the server, which is at the heart of the AJAX stack.

Communicating with the Server via AJAX

In my interaction with many different types of developers, I run into numerous people who are actively using ASP.NET AJAX. A majority of these developers are using it for the controls: UpdatePanel and the AJAX Control Toolkit. While these controls are certainly laudable for their usefulness, I think the real power of ASP.NET AJAX is the ability to create a simple server communication API.

For our example we want to be able to communicate bi-directionally with the server. Bi-directional communication with AJAX is really a push-pull model. Because the HTTP protocol is connectionless, we need to have our client code initiate all the communications. When we need to tell the server something, we need to send it a message; whereas, if we need to get information from the server, we need to make a server request. For developers used to non-Web-based communication, this is a different mindset that they ll need to get used to.

ASP.NET AJAX allows us to create a simple client-side JavaScript API by providing two services: Proxy Generation and Marshalling. Essentially, ASP.NET AJAX allows us to expose particular Web services to the client-side JavaScript and create proxy class(es) for Web services to make them simple to call. In addition, ASP.NET AJAX will convert types between the client and the server (using JSON) so we can use complex types, as well as simple types from JavaScript without having to do much in the way of type conversion. These services will become clearer as we develop our Web service and use it in code.

In our RatingsControl, we want to communicate two things: set the ratings for a particular item and get any previously rated items. To do this, we want to create a simple Web service that exposes two methods: SetRating and GetRating. Let s start with the SetRating call. We can define our traditional ASP.NET Web service like that shown in Figure 7.


Service to get and set ratings for use with the Silverlight Ratings Control

[WebService(Namespace = "http://adoguy.com/ratingservice")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class RatingsService : System.Web.Services.WebService
{
}

The only difference between a traditional ASP.NET .asmx service and one that will work with ASP.NET AJAX is the addition of the ScriptService attribute. This attribute tells ASP.NET that we want to be able to use the service from ASP.NET AJAX; therefore, all types must be convertible to JavaScript Object Notation (JSON). JSON is a format that is easy for JavaScript to deal with, is compact, and is a data-only copy of structures. JSON is not a proxy to the real object, but instead is equivalent to a copy of the structure of the data within an object. See the Resources section at the end of this article for more information on JSON. ASP.NET AJAX uses JSON under the covers to convert objects across the wire.

Next, we ll want to add our SetRating method to allow us to tell the server that someone has selected a rating. In our simple implementation, we are allowing the client code to specify a name for the rating, and we are simply storing it in an ASP.NET Session (instead of storing it in a database or file). This approach is not appropriate for most cases, but it makes our example very concise and easy to understand. Here s our SetRating method:

[WebMethod(EnableSession = true)]
public void SetRating(string ratingName, double rating)
{
 Session[string.Concat("RATINGFOR", ratingName)] = rating;
}

The EnableSession property on the WebMethod is only required because we are using Session to store our rating. When this method is called, we simply store the rating in Session for later use. The real magic for us happens when we go back to our page and tell the ScriptManager that we want to use this Web service on a page (see Figure 8).


 
   
 
 
   
   
 

By adding a Services section to the ScriptManager, we can add any Web services for which we need a JavaScript proxy on the client side. In this example, we create a ServiceReference to our RatingsService itself. Once this is added, it allows us to use the new proxy from JavaScript. The RatingsService itself is created as a JavaScript class in the client that we can call directly. Here s our use of this new Proxy class in code:

// Let the server know that a rating was picked
if (RatingsService) // Is the defined?
{
 var svc = new RatingsService();
 svc.SetRating("TestRating", this.currentRating);
   // Fire and Forget!
}

This code first tests to see if the RatingsService is defined as a class. By testing this we can write this code to work both in an ASP.NET project that has it defined and a test page that doesn t have access to the Web service. Once we are satisfied that it does exist, we can simply create a new instance of the service using the new syntax. The service instance is really just a proxy that knows how to call each of the methods asynchronously. In our case, we want to call the SetRating method. Because we want to let the server know the value, we can simply set the value to match our signature (where we want the name of the rating, then a number that represents the actual star rating, which is stored in a local class variable in our Silverlight project named currentRating).

More interestingly is if we request data from the server. To show this, we have a new method named GetRating that takes the name of the rating from the client and returns the actual rating. The Web service implementation is shown in Figure 9.

[WebMethod(EnableSession = true)]
public double GetRating(string ratingName)
{
 object rating = Session[string.Concat("RATINGFOR",
                                       ratingName)];
 if (rating == null) return -1.0;
 else return (double) rating;
}

In this code we attempt to find the rating in the Session; if we don t find it, we return -1; otherwise, we return the actual rating. In our client code, we want to call this new method and have access to the returned number (see Figure 10).

// Get the Current Rating From Web Service
if (RatingsService) // Is the defined?
{
 var svc = new RatingsService();
 svc.GetRating("TestRating",
               Silverlight.createDelegate(this,
               this.getRatingComplete));
}

Just like before, we want to be sure that the Web service is defined, and, if so, create a new instance of the service. Unlike before, when we call the method, we are specifying a callback function (in this case, we are using the Silverlight.createDelegate call to allow us to call back into a member of our implementation class). Calling GetRating will asynchronously call the server, then call our getRatingComplete function with the result of the Web service call once it completes. The getRatingComplete function is shown in Figure 11.

getRatingComplete: function(rating)
{
 // Set the current rating and recalculate it
 if (rating >= 0)
 {
   this.ratingPicked = true;
   this.setRating(rating);
 }
},

In the callback function, we are being passed the rating (which is just the return type of our Web service). If the rating is greater than or equal to zero, we know the service found a valid rating and we can tell the control that a rating was picked and set the rating (to show the correct number of stars).

Conclusion

Silverlight represents a new platform in the Microsoft Web-space. Instead of reinventing the entire stack or forcing developers to use a single-use set of technologies, Silverlight and ASP.NET AJAX represent an example of using existing skill-sets in these new development models. By leveraging existing knowledge, Silverlight can fit comfortably into existing Web sites and developer toolboxes. Using ASP.NET AJAX s Web service proxy creation services allows the developer to continue to focus on the functionality and concern themselves less with the plumbing. At the end of the day that means we ll be able to deliver better solutions in less time.

Resources

The source code accompanying this article is available for download.

Shawn Wildermuth is a Microsoft MVP (C#), MCSD.NET, MCT, and the founder of Wildermuth Consulting Services, LLC, a company dedicated to delivering architecture, mentoring, and software solutions in the Atlanta, GA area. He also is a speaker on the INETA Speaker s Bureau, and has appeared at several national conferences to speak on a variety of subjects. He currently is teaching Silverlight across the country during his Silverlight Tour (http://silverlight-tour.com). Shawn also is the author of several books, including Pragmatic ADO.NET (Addison-Wesley), and co-author of four Microsoft Certification Training Kits for MS Press, as well as the upcoming book, Prescriptive Data Architectures. He has been writing articles for a number of years for a variety of magazines and Web sites, including MSDN, MSDN Online, DevSource, InformIT, Windows IT Pro, The ServerSide .NET, ONDotNet.com, and Intel s Rich Client Series. Shawn has enjoyed building data-driven software for more than 20 years. He can be reached at his Web site at http://www.wildermuthconsulting.com.

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish