Practical ASP.NET

Extending Client-Side Programming in ASP.NET 4

ASP.NET 4 adds a wealth of features for client-side developers, including new ways of instantiating controls, a new infrastructure for managing libraries and some minor but much-needed tweaks. And there's more.

The first half of 2010 has seen tremendous change for ASP.NET client-side developers: the Microsoft commitment to jQuery at MIX10, the implementation of the Content Delivery Network (CDN), and the release of both Visual Studio 2010 and the Microsoft .NET Framework 4. Tracking these changes is difficult because support for client-side programming in ASP.NET 4 is spread over two different packages: ASP.NET itself and the ASP.NET AJAX Toolkit. And, with the CDN, client-side support also includes the Microsoft infrastructure. The changes run the gamut from the small (tweaking properties on existing controls) through the large (supplying completely new functionality at the client) to the all-encompassing (changing how script files are managed).

Here's an overview of what you can use now and what's waiting for you when you upgrade to .NET 4. You'll get a look at how these changes fit together to create a new environment for AJAX in ASP.NET - an environment that extends the power of client-side coding while simplifying both development and implementation.

New Infrastructure
Developers constantly find themselves adding standard libraries of JavaScript code to their Web sites in order to access the functionality in the library. Starting right now, you can use the CDN to simplify that process. The CDN provides a distributed repository for script libraries. To start using the beta of the AJAX library, for instance, you just have to add a script tag to your page that references the Start.js file (and add nothing at all to your site):

  <script type="text/javascript"
    src="http://ajax.microsoft.com/ajax/beta/0911/Start.js"></script>

You can find a complete list of the available libraries (which includes the Microsoft AJAX scripts, all the scripts in System.Web.dll and the core jQuery libraries) here.

There are several benefits to using CDN. First, of course, it reduces demand on your server by transferring requests to the Microsoft server closest to the user (a good thing if you assume that the Microsoft server is at least as fast as yours). More importantly, though, is that the request for a library might not generate any download at all. If lots of sites are using the CDN, then the odds that a browser has already retrieved the script you want from the CDN before hitting your site become very high. Instead of downloading the requested script, the browser may just fetch the script from its cache.

The CDN leads to a new feature on the ScriptManager in .NET 4: the EnableCdn property. Setting this property to true causes the ScriptManager to fetch the JavaScript libraries normally found in System.Web.dll or System.Web.Extensions.dll from the CDN.

To extend this feature to your own libraries, the WebResource object (used in the AppInfo file to point to DLLs holding scripts) has acquired a new property: CdnPath. This new property points to URLs that the ScriptManager should use when EnableCdn is set to true. You should be able to add your own custom libraries to the list by updating your AssemblyInfo file with a WebResource object that points to your script files. Just pass the URL to your library as the third parameter to the WebResource constructor. This example adds a script called MyScript.js:

  <Assembly: System.Web.UI.WebResource("MyScript.js", 
    "application/x-javascript", 
    CdnPath := "http://myserver/jslibrary/MyScript.js")> 

Controlling the ClientId
Your client-side scripts will interact with client-side objects, including the client-side objects generated by ASP.NET controls. In earlier versions of ASP.NET, determining the value of the id attribute for a server control's client-side object was difficult. The value of the id attribute could be read from a control's ClientId property but it couldn't be set by the developer. In what may be the .NET 4 change developers value the most, the ClientId property on a control -- in conjunction with the ClientIDMode property -- gives you three different ways for setting the value of the id attribute.

When ClientIDMode is set to AutoID, you get an automatically generated client-side id value that includes an arbitrary prefix: what you have in current versions of ASP.NET, with ct100 as the typical prefix. But if you set the control's ClientIDMode to static, then the element's id attribute will be the same as the server-side control's ID.

Static, however, creates problems when used with repeating controls in, for instance, a GridView. To handle this, the GridView and other repeating controls now have a ClientIDRowSuffix property that you set to the name of a data field. Once you've set the ClientIDRowSuffix, you can set the ClientIDMode of your control to predictable. When the client-side object is generated, the value of the ClientIDRowSuffix field will be appended to the id you assign to the control on the server. Provided you pick a field that has a different value on each row, the id attribute on your control will be different for each row.

So that you don't have to set the ClientIDMode on every control on a page, by default controls inherit their ClientIDMode setting from whatever container they're in. (If you check, you'll find that your control's ClientIDMode has defaulted to "inherit.") The one exception is the Page object, whose ClientIDMode defaults to AutoID. All controls are contained by the Page object, which causes AutoID to cascade down to all other controls on the page. This results in the ClientId property on those controls behaving as it did in previous versions of ASP.NET.

Putting it all together, you'd set a GridView's ClientIDMode to Predictable and its ClientIDRowSuffix to a field with unique values (such as the CustomerId field). Any control in the GridView will inherit the ClientIDMode of Predictable. So a control with a server-side id of ContactName, when displayed on the row for the customer with a CustomerId of "ALFKI," will end up with an id set to "ContactName_ALFKI."

Preloading Scripts
Adding client-side functionality means adding more JavaScript libraries that must be downloaded by the browser. This creates two problems. First, developers often end up downloading a "standard set" of script libraries in every page to ensure any library that might be needed is present. Second, developers need to ensure all libraries are downloaded before any code that depends on them executes.

To simplify this process, ASP.NET 4 has a require method on the client-side Sys object that comes with the Start.js file. The require method downloads all the script libraries (in parallel) for the components passed to it. Once the libraries are downloaded, the require method executes a function. This example downloads the dataView and WebServices libraries, with all of their dependences, before calling a function that uses them:

  Sys.require
   ([Sys.components.dataView, Sys.scripts.WebServices],
      function () 
      {
	     //use the dataView in here
      }
);

Of course, you don't want to call your function until the page is fully loaded and ready. That's also handled by a method on the Sys object. The onReady method calls a function only when the DOM and all other resources are ready:

  Sys.onReady
   (function () 
    {
    }
  );

The create method on the Sys object allows you to create new controls on the fly, called "imperative instantiation." In this example, I've combined the creation of the ASP.NET AJAX calendar extender (added to a control with an id of "projectStart") with a check to ensure that the page is ready and request for all the necessary scripts with their dependencies to be downloaded:

  Sys.onReady(function () {
       Sys.require(Sys.components.calendar, function () {
            Sys.create.calendar("#projectStart");
            });
       });

The calendar control, however, is part of the AJAX Toolkit and is not included in ASP.NET DLLs whose scripts are fetched by setting the EnableCdn property on the ScriptManager. You can still get the library from the CDN, but you'll have to add an explicit script reference to do it:

  <script type="text/javascript" src="http://ajax.microsoft.com/ 
    ajax/beta/0911/extended/ExtendedControls.debug.js"></script>

Client-Side Data Processing
While it's possible to display data using client-side code in ASP.NET, more work is required than using a server-side control like the GridView. The new dataView is a client-side control that will display rows of data just by specifying three properties: The Web Service to call (dataProvider), the method to call (fetchOperation) and whether to retrieve data when the page loads (autoFetch). This example creates a dataView bound to a method named GetCustomers in a Web Service called CustomerServices.svc:

  Sys.create.dataView("#customerData",
    {
      dataProvider: "CustomerServices.svc",
      fetchOperation: "GetCustomers",
      autoFetch:      true 
    }
  );

The dataView is an extender that you can use with almost any HTML structure that supports repeated entries. In the following HTML, I use a table, but I could just as easily have used a list. Note: You do need to assign the structure to the CSS class "sys-template." To data bind to properties on the objects being returned to the client from the service, you just enclose the property name in double curly braces. This example displays the CustomerId and CompanyName properties:

  <table id="customerData" class="sys-template">
    <tr>
      <td>{{CustomerId}}</td><td>{{CompanyName}}</td>
    </tr>
  </table>  

In the past you'd also need to spend an inordinate amount of time converting between HTTP-friendly data transfer objects and, for instance, Entity Framework objects used in the service. The new dataContext object simplifies the process of getting data from the server, down to the client and back up again using either LINQ to SQL or Entity Framework. For developers working with ADO.NET, the AdoNetContext object provides the same kind of support for ADO.NET objects.

However, with the new Microsoft commitment to jQuery, it will be interesting to see how the dataContext -- with its ability to call server-side resources -- integrates with the jQuery post function. As my example shows, Microsoft had started to develop its own syntax for client-side templating in .NET 4. Long-term, as templating moves into the jQuery code, this syntax could also change.

Creating a WCF Service that works with client-side code is also considerably easier in Visual Studio 2010: Select the right template in the Add New Item dialog. No more fiddling with attributes and configuration settings to make it all work. Stephen Walther, senior program manager for ASP.NET at Microsoft, says that further integration of Windows Communication Foundation (WCF) with JSON is going to be a major effort for Microsoft over the near term along with more jQuery plug-ins to support Microsoft technologies.

Managing Scripts
Because we've come back to managing scripts, I'll finish this overview by looking at the new features for managing scripts with the ScriptManager. Developers often have conflicting demands on JavaScript libraries. In production, developers want minimized libraries that will download quickly; in development, developers want the full source code to support debugging (the CDN provides separate URLs for both debug and production versions of the scripts it makes available). Rather than rewrite your script tags, you can ensure that the right library is loaded automatically by using the ScriptManager and ScriptResourceMapping.

To implement ScriptResoureMapping, you create a ScriptResourceDefinition object that has properties that hold the paths for production, debug and CDN versions of a script. Typically, you'll do this in the Application Start event in your Global.asax file. This example sets up just the debug and production URLs that point to a custom library:

  Dim src As New ScriptResourceDefinition
  src.Path = "~/js/CustomerUtilities.min.js"
  src.DebugPath = "~/js/ CustomerUtilities.js"

You then add the object to a ScriptManager ScriptResourceMapping collection. This example adds the object just created with the name "Customers":

  ScriptManager.ScriptResourceMapping.AddDefinition("Customers", src)

To use the mapping, add a ScriptReference to ScriptManager and set its Name property to the name you gave to your ScriptResourceDefinition (here, it's "Customers"). ScriptManager will automatically switch between the production and debug versions of your libraries. (It already does this with Microsoft AJAX libraries.)

If you liked some of the features of ScriptManager but were unhappy about the amount of JavaScript that it downloaded -- and the number of downloads it incurred -- you'll be happy to know that you now can select which scripts ScriptManager will download. To select the files you want, first set the ScriptManager AjaxFrameworkMode to Disabled and then add the scripts you want to the ScriptReferences collection.

The ScriptManager also has a new CompositeScript collection that causes ScriptManager to combine multiple script libraries into a single download and do it without having to create an .AXD file. You can pick and choose the scripts you want from any source -- including the scripts embedded in the Microsoft DLLs -- to create a single download: Simply specify the name of the script and the name of the assembly.

But Wait! There's More
This isn't everything that's new for client-side development in ASP.NET 4/Visual Studio 2010. IntelliSense for JavaScript is much improved, for instance. In previous versions of Visual Studio, if any piece of your JavaScript didn't compile, you'd lose IntelliSense support for all of your libraries. In Visual Studio 2010 that's no longer the case. And there are, of course, new controls in the AJAX Toolkit.

You'll want to explore those new features, but it's the changes to core functionality covered in this article that really matter. These changes give .NET 4 client-side developers better control over their environment and more powerful tools to deliver applications while simplifying development and implementation with multiple script libraries.

comments powered by Disqus
Upcoming Events

.NET Insight

Sign up for our newsletter.

I agree to this site's Privacy Policy.