Archives

Archives / 2008 / March
  • TDD : Introduction to Rhino Mocks

    Rhino Mocks is the most popular Mock Object Framework for .NET. The purpose of this blog entry is to provide a brief introduction to Rhino Mocks. In particular, I want to describe how you can use Rhino Mocks when building ASP.NET MVC web applications.

    In the first part of this entry, I explain why Mock Object Frameworks are critical tools when performing Test-Driven Development. Next, I discuss how you can use Rhino Mocks to create both state verification unit tests and behavior verification unit tests. Finally, I discuss how Rhino Mocks forces you to design your ASP.NET MVC web applications in a particular way.

    Why Mock?

    Why should you care about Mock Object Frameworks such as Rhino Mocks? If you want to practice Test-Driven Development, then there is no way to avoid using a Mock Object Framework. You need to use a Mock Object Framework to create effective unit tests.

    A unit test enables you to test a single unit of code in isolation. Typically, a unit of code corresponds to a single method in your application. Therefore, a unit test should enable you to test just the code inside a particular method and nothing else.

    A unit test created for the purposes of Test-Driven Development -- a TDD unit test -- has additional requirements. A unit test appropriate for TDD unit test should execute very quickly and should not require any application configuration.

    When practicing Test-Driven Development, you execute all of your tests whenever you make a code change. Most likely, you’ll execute your unit tests hundreds of times while building an application. If your unit tests are too slow or they take work to setup, then Test-Driven Development will no longer be practical.

    Let’s look at a particular code sample. The method in Listing 1 adds two numbers together.

    Listing 1 – Calculate.cs

       1:  using System;
       2:   
       3:  public class Calculate
       4:  {
       5:   
       6:      public int AddNumbers(int num1, int num2)
       7:      {
       8:          return num1 + num2;
       9:      }
      10:  }

    Listing 2 contains a unit test for the method in Listing 1. The unit test in Listing 2 tests whether the method in Listing 1 returns the correct value for 2 + 2.

    Listing 2 – AddNumbersTest Method

       1:  [TestMethod]
       2:  public void AddNumbersTest()
       3:  {
       4:      Calculate calculate = new Calculate();
       5:      int result = calculate.AddNumbers(2, 2);
       6:      Assert.AreEqual(2 + 2, result);
       7:  }

    There is nothing wrong with the unit test in Listing 2. This unit test enables you to test the AddNumbers() method in isolation. The unit test executes quickly without requiring you to perform any configuration. You could run hundreds of unit tests that look just like this one each time you make a code change without significantly slowing down the process of developing an application.

    Unfortunately, most real-world code looks nothing like the code in Listing 1. Most real-world code has dependencies on external objects. In many cases, these external objects have dependencies on resources like databases, configuration files, web services, or the file system.

    For example, consider the code in Listing 3. The GetProducts() method in Listing 3 looks more like it was ripped from an actual application.

    Listing 3 – GetProducts Method

       1:  public static List<Product> GetProducts()
       2:  {
       3:      // Get database connection string
       4:      string conString = ConfigHelper.GetDBConnectionString();
       5:      
       6:      // Get data provider
       7:      DataProvider dp = new DataProvider(conString);
       8:      
       9:      // Return list of products
      10:      return dp.GetProducts();
      11:  }

    The GetProducts() method references two external classes named ConfigHelper and DataProvider. The ConfigHelper class is used to retrieve a database connection string. The DataProvider class is used to access the database.

    The unit test in Listing 4 tests the GetProducts() method.

    Listing 4 – GetProductsTest Method

       1:  [TestMethod]
       2:  public void GetProductsTest()
       3:  {
       4:      List<Product> results = Product.GetProducts();
       5:      Assert.AreEqual(3, results.Count);
       6:  }

    The unit test in Listing 4 checks whether a particular number of products is returned by the GetProducts() method.

    Here’s the problem: the test in Listing 4 depends on external resources. These external resources violate the requirements for a good TDD test.

    Each time you execute the test in Listing 4, a connection string must be retrieved from the ConfigHelper class. The ConfigHelper class, in turn, retrieves the connection string from a configuration file. The test has a dependency on an external resource. In this case, the external resource is a configuration file. In order to run the unit test, you must have the right configuration file setup in your Test Project.

    Furthermore, the unit test in Listing 5 has a dependency on the DataProvider class. The DataProvider class relies on an external resource: a database. In order for the test to run, the product records must be retrieved from a database table. Retrieving data from a database is slow. Imagine running hundreds of tests that must access a database whenever you make a code change. You would never get any work done on your application. You would spend all day waiting for your unit tests to finish executing.

    If you want to be able to write an effective test for the GetProducts() method, then you need to take advantage of a Mock Object Framework. A Mock Object Framework enables you to mock external resources such as configuration files and databases. The remainder of this blog entry focuses on a particular Mock Object Framework: Rhino Mocks.

    State versus Behavior Verification

    A Mock Object Framework such as Rhino Mocks can be used to perform two very different types of unit tests. You can use Rhino Mocks to perform either state or behavior verification (This distinction used to be called state versus interaction-based testing and many people continue to use these terms).

    On the one hand, you can use a Mock Object Framework to create stubs. A stub acts as a stand-in for a normal object. There are multiple reasons that you might create a stub. For example, as discussed above, the actual object might access an external resource such as a database or the file system causing the actual object to be too slow to use in a unit test. The stub enables you to perform a test in a reasonable amount of time without requiring any configuration.

    Another and equally valid reason for using a stub is that you haven’t actually implemented a particular object required for a test. For example, you might want to unit test a method that relies on a DataProvider object, but you have not had a chance to implement the data provider object. In this case, the mock object is acting as a stand-in for the real object so that you can build other objects that depend on the stub.

    When performing state-based verification, the final statement in your unit test is typically an assert statement that asserts that some condition is true.

    When performing behavior verification (an interaction test), on the other hand, you are interested in verifying that a set of objects behave and interact in a particular way. For example, you might want to verify that that when the DataProvider.GetProducts() method is called, a second method named the SqlDataProvider.GetProducts() method is called exactly once with a particular set of parameters or that another method named the SqlDataProvider.ExecuteCommand() method is called exactly three times with another particular set of parameters .

    When performing behavior verification, your test typically does not end with an assert statement. Instead, the interaction of the objects being tested is verified. Rhino Mocks throws an exception automatically when mock expectations do not meet reality.

    To learn more about state versus behavior verification, and the distinction between mocks and stubs, see Martin Fowler’s article at:

    http://martinfowler.com/articles/mocksArentStubs.html

    Using Rhino Mocks

    Rhino Mocks was created and it is maintained by Ayende Rahien (AKA Oren Eini). You can download Rhino Mocks from the following URL:

    http://www.ayende.com/projects/rhino-mocks.aspx

    There is a Google group devoted to discussing Rhino Mocks (Ayende Rahien is an active participant) at:

    http://groups.google.com/group/RhinoMocks

    Rhino Mocks does not include an installer. After you download and unzip Rhino Mocks, you can use Rhino Mocks in a project by adding a reference to the Rhino.Mocks.dll assembly. There is also an XML file included with the download that provides Intellisense for Rhino Mocks within Visual Studio.

    One warning about using Rhino Mocks on Windows Vista. Vista will prevent you from using assemblies that you download from the Internet. Before you reference the Rhino.Mocks.dll assembly in Visual Studio, you need to Unblock the assembly: right-click the assembly file and click the Unblock button under the General tab (see Figure 1).

    clip_image002

    State Verification with Rhino Mocks

    You can use Rhino Mocks to create stubs for interfaces, abstract classes, and concrete classes. When creating a stub for class methods, the method must be marked as virtual. This last requirement places some significant limitations on what you can stub. You cannot use Rhino Mocks with static or sealed methods (we’ll return to this issue in the last section of this blog entry).

    Let’s start with a simple sample of a stub. Imagine that you have created the abstract base class in Listing 5.

    Listing 5 – ProductBase.cs

       1:  using System;
       2:   
       3:  namespace RhinoMockProject
       4:  {
       5:      public abstract class ProductBase
       6:      {
       7:          public abstract string Name { get; set; }
       8:   
       9:          public abstract decimal Price { get; set; }
      10:   
      11:          public abstract void Save();
      12:      }
      13:  }

    You intend, at some point in the future, to create particular types of products that derive from this base class – for example, ElectronicProduct, FoodProduct, SportsProduct -- but you haven’t gotten around to creating these concrete classes yet. No worries. By taking advantage of Rhino Mocks, you can pretend that you have already done the work. The test in Listing 6 uses Rhino Mocks to create a concrete instance of the class, set a property, and test the property.

    Listing 6 – RhinoMocksTest.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using RhinoMockProject;
       8:  using Rhino.Mocks;
       9:   
      10:  namespace RhinoMockProjectTests
      11:  {
      12:      [TestClass]
      13:      public class RhinoMocksTest
      14:      {
      15:   
      16:          [TestMethod]
      17:          public void TestStubAbstract()
      18:          {
      19:              // Setup product stub
      20:              ProductBase product = MockRepository.GenerateStub<ProductBase>();
      21:              product.Name = "Laptop Computer";
      22:              product.Price = 3200.00m;
      23:   
      24:              // Test
      25:              Assert.AreEqual(3200.00m, product.Price);
      26:          }
      27:   
      28:      }
      29:  }

    In Listing 6, the static method MockRepository.GenerateStub<T>() is called to generate a stub for the abstract ProductBase class. After you generate the stub, you can treat the stub as a normal class and set and read its properties. The last assert statement returns the value True since the stub product’s Price property was, in fact, set to the value $3,200.00.

    You also can create stubs for interfaces in the exact same way. For example, Listing 7 contains an IProduct interface.

    Listing 7 – IProduct.cs

       1:  using System;
       2:   
       3:  public interface IProduct
       4:  {
       5:      string Name { get; set; }
       6:   
       7:      decimal Price { get; set; }
       8:  }

    Imagine that you are adding a new feature to your store. You are creating a method that doubles the price of any product. The method is contained in Listing 8.

    Listing 8 – ProductManager.cs

       1:  using System;
       2:   
       3:  namespace RhinoMockProject
       4:  {
       5:      public class ProductManager
       6:      {
       7:   
       8:          public static void DoublePrice(IProduct product)
       9:          {
      10:              product.Price *= 2;
      11:          }
      12:   
      13:      }
      14:  }

    Before you can test the method in Listing 8, you need a class that implements the IProduct interface. If you don’t want to do the work to implement the interface at the moment, then you can use Rhino Mocks to create a stub from the interface automatically. The test in Listing 9, once again, takes advantage of the MockRepository.GenerateStub<T>() method to generate a concrete stub from an interface.

    Listing 9 – RhinoMocksTest.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using RhinoMockProject;
       8:  using Rhino.Mocks;
       9:   
      10:  namespace RhinoMockProjectTests
      11:  {
      12:      [TestClass]
      13:      public class RhinoMocksTest
      14:      {
      15:   
      16:          [TestMethod]
      17:          public void TestStubInterface()
      18:          {
      19:              decimal price = 3200.00m;
      20:   
      21:              // Setup product stub
      22:              IProduct product = MockRepository.GenerateStub<IProduct>();
      23:              product.Name = "Laptop Computer";
      24:              product.Price = price;
      25:   
      26:              // Call method being tested
      27:              ProductManager.DoublePrice(product);
      28:   
      29:              // Test
      30:              Assert.AreEqual(price * 2, product.Price); 
      31:          }
      32:      }
      33:  }

    The test in Listing 9 creates a concrete instance of a class that implements the IProduct interface and passes the instance to the DoublePrice() method. The test demonstrates that the DoublePrice() method does, in fact, double the price of the product correctly.

    Setting Up Return Values from Stub Methods

    You also can use Rhino Mocks to generate fake return values from classes and interfaces that you have stubbed. Here’s a common scenario. Imagine that you need to test a method that relies on database data. However, you don’t want to access the database when you execute the unit test because accessing the database would be too slow. In this case, you can create a stub method that always returns a hard-coded set of values.

    The interface in Listing 10 could be used to represent your data access layer.

    Listing 10 – IProductRepository.cs

       1:  using System;
       2:  using System.Collections.Generic;
       3:   
       4:  public interface IProductRepository
       5:  {
       6:      IProduct Get(int ProductId); 
       7:      
       8:      IEnumerable<IProduct> Select();
       9:   
      10:      bool Save(IProduct product);
      11:  }

    The interface in Listing 10 includes a method for retrieving a set of product records, a method for retrieving a particular product record, and a method for saving a product record.

    The unit test in Listing 11 illustrates how you can create a stub for the IProductRepository interface and setup the stub’s Select() method so that it always returns a fake set of products.

    Listing 11 – RhinoMocksTest.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using RhinoMockProject;
       8:  using Rhino.Mocks;
       9:   
      10:  namespace RhinoMockProjectTests
      11:  {
      12:      [TestClass]
      13:      public class RhinoMocksTest
      14:      {
      15:          private IEnumerable<IProduct> _fakeProducts = new List<IProduct>
      16:              {
      17:                  new Product {Name = "Steak", Price = 9.85m},
      18:                  new Product {Name = "Milk", Price = 2.02m},
      19:                  new Product {Name = "Diapers", Price = 33.07m}
      20:              };
      21:   
      22:   
      23:          [TestMethod]
      24:          public void TestStubInterfaceMethod()
      25:          {
      26:              MockRepository mocks = new MockRepository();
      27:              IProductRepository products = mocks.Stub<IProductRepository>();
      28:   
      29:              using (mocks.Record())
      30:              {
      31:                  SetupResult.For(products.Select()).Return(_fakeProducts);
      32:              }
      33:   
      34:              var results = products.Select();
      35:              
      36:              Assert.AreEqual(3, results.Count());
      37:          }
      38:   
      39:      }
      40:  }

    There are three important differences that you should notice between the code in Listing 11 and the code in the previous samples. First, notice that the sub for the IProductRepository interface is not created by using the GenerateStub<T>() method like in previous code samples. When setting up method return values, you must create an instance of the Rhino Mocks MockRepository class and call the MockRepository instance’s Stub<T>() method.

    Second, notice that the SetupResult class is used to setup the return value for the IProductRepository.Select() method. When the Select() method is called, the contents of the _fakeProducts field is returned.

    Finally, notice that the call to SetupResult is wrapped in a using statement that references the MockRespository.Record() method. The using statement in conjunction with the Record() method are used to record how the stub should behave when a particular stub method is called. You can setup multiple stub methods within the single using statement.

    You can even return different values from a stub method when different parameters are passed to the stub method. For example, the test in Listing 12 returns different products depending on the ProductId passed to the ProductRepository.Get() method.

    Listing 12 – RhinoMocksTest.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using RhinoMockProject;
       8:  using Rhino.Mocks;
       9:   
      10:  namespace RhinoMockProjectTests
      11:  {
      12:      [TestClass]
      13:      public class RhinoMocksTest
      14:      {
      15:   
      16:          [TestMethod]
      17:          public void TestStubMultipleReturn()
      18:          {
      19:              MockRepository mocks = new MockRepository();
      20:              IProductRepository products = mocks.Stub<IProductRepository>();
      21:   
      22:              using (mocks.Record())
      23:              {
      24:                  SetupResult
      25:                      .For(products.Get(2))
      26:                      .Return(new Product {Name="Beer", Price=12.99m });
      27:   
      28:                  SetupResult
      29:                      .For(products.Get(12))
      30:                      .Return(new Product { Name = "Steak", Price = 8.02m });
      31:              }
      32:   
      33:              // Test
      34:              IProduct product1 = products.Get(2);
      35:              Assert.AreEqual("Beer", product1.Name);
      36:   
      37:              IProduct product2 = products.Get(12);
      38:              Assert.AreEqual("Steak", product2.Name);
      39:   
      40:              IProduct product3 = products.Get(13);
      41:              Assert.IsNull(product3);
      42:          }
      43:   
      44:      }
      45:  }

    In Listing 12, two different products are returned when calling the Get() method depending on the value of the ProductId. In the Record() section of the test, the two different return values for the Get() method are setup.

    Notice the very last assert statement. If you call the Get() method with a ProductId that has not been setup, then the value Null is returned.

    If you want any call to the Get() method to always return a particular fake product, then you can call IgnoreArguments() when setting up the return value. This approach is illustrated by the test in Listing 13. As the assert statements at the end of the test method demonstrate, regardless of the ProductId passed to the Get() method, the very same product is returned.

    Listing 13 – RhinoMocksTest.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using RhinoMockProject;
       8:  using Rhino.Mocks;
       9:   
      10:  namespace RhinoMockProjectTests
      11:  {
      12:      /// <summary>
      13:      /// Summary description for TestRhino
      14:      /// </summary>
      15:      [TestClass]
      16:      public class RhinoMocksTest
      17:      {
      18:   
      19:          [TestMethod]
      20:          public void TestStubIgnoreArguments()
      21:          {
      22:              MockRepository mocks = new MockRepository();
      23:              IProductRepository products = mocks.Stub<IProductRepository>();
      24:   
      25:              using (mocks.Record())
      26:              {
      27:                  SetupResult
      28:                      .For(products.Get(1))
      29:                      .IgnoreArguments()
      30:                      .Return(new Product { Name = "Beer", Price = 12.99m });
      31:              }
      32:   
      33:              // Test
      34:              IProduct product1 = products.Get(2);
      35:              Assert.AreEqual("Beer", product1.Name);
      36:   
      37:              IProduct product2 = products.Get(12);
      38:              Assert.AreEqual("Beer", product2.Name);
      39:          }
      40:   
      41:      }
      42:  }

    Behavior Verification with Rhino Mocks

    You can use Rhino Mocks to verify that a particular set of objects interact in an expected way. For example, you can verify that a particular object method was called the expected number of times with the expected set of parameters. This type of testing is also called interaction-based testing.

    This type of test is useful when you cannot verify the state of an object after you interact with the object. For example, an object might not have a public property that you can perform an assert against. Therefore, there is no direct way to validate the state of the object after executing the unit test.

    For example, imagine that you need to create a logging component. Every time you perform a significant action in your application, you want to log the action to a log file on disk. (This example of behavior verification is taken from Gerard Meszaros’s xUnit Test Patterns book, see http://xunitpatterns.com/Behavior%20Verification.html). If the logger component does not have a property that exposes all of its log entries then there will be no easy way to verify whether the logger is behaving as expected.

    However, if you can intercept requests to the logger component, then you can verify that other components are interacting with the logger component when you expect. The point of behavior verification is to perform this type of test of the interaction between different components.

    Expectations versus Reality

    When performing behavior verification tests with Rhino Mocks, your test code is divided into two sections. First, you have a section of code where you record your expectations. Second, you have a section of code where your expectations are tested against reality.

    For example, Listing 14 contains a unit test for a logger component. In the first section of the test, a particular set of expectations is recorded. When the Customer.Save() method is called, the Logger.Log() method should be called with the ProductId of the product being saved.

    Listing 14 – LoggerTest.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using Rhino.Mocks;
       8:  using RhinoMockProject;
       9:   
      10:  namespace RhinoMockProjectTests
      11:  {
      12:      [TestClass]
      13:      public class LoggerTest
      14:      {
      15:   
      16:          [TestMethod]
      17:          public void LogTest()
      18:          {
      19:              MockRepository mocks = new MockRepository();
      20:              Logger logger = mocks.CreateMock<Logger>();
      21:              using (mocks.Record())
      22:              {
      23:                  logger.Log(27);
      24:              }
      25:              using (mocks.Playback())
      26:              {
      27:                  Customer newCustomer = new Customer(27, logger);
      28:                  newCustomer.Name = "Stephen Walther";
      29:                  newCustomer.Save();
      30:              }
      31:          }
      32:      }
      33:  }

    If you run the test in Listing 14, and the Logger.Log() method is not called with the expected value for CustomerId, then the unit test fails. Notice that the unit test does not contain an assert statement. If expectations do not match reality, Rhino Mocks causes the unit test to fail by raising an ExpectationViolationException exception.

    The Customer class is contained in Listing 15. Notice that the Logger component is passed to the Customer class in the Customer class constructor. Passing a class in this manner is a type of dependency injection called constructor injection (see Martin Fowler, http://martinfowler.com/articles/injection.html).

    Listing 15 – Customer.cs

       1:  using System;
       2:   
       3:  namespace RhinoMockProject
       4:  {
       5:      public class Customer
       6:      {
       7:          public int Id { get; private set; }
       8:          public string Name { get; set; }
       9:          private Logger _logger;
      10:   
      11:          public Customer(int Id, Logger logger)
      12:          {
      13:              this.Id = Id;
      14:              _logger = logger;
      15:          }
      16:   
      17:          public void Save()
      18:          {
      19:              _logger.Log(this.Id);
      20:          }
      21:   
      22:      }
      23:  }

    The Logger class is contained in Listing 16. This class isn’t really implemented since the Log() method is never really called. The Log() method raises an exception. Since we are mocking the Log() method, this exception is never raised.

    Listing 16 – Logger.cs

       1:  using System;
       2:   
       3:  public class Logger
       4:  {
       5:      public virtual void Log(int ProductId)
       6:      {
       7:          throw new Exception("eeeks!");
       8:      }
       9:   
      10:  }

    Strict, Non-Strict, and Partial Mocking

    Rhino Mocks supports three different ways to create mock objects. You can mock an object by calling any of the following three methods:

    1. CreateMock<T>() – This method of creating a mock object enforces a strict replay of expectations. If a method is called unexpectedly, then the mock object will fail verification and throw an exception.

    2. DynamicMock<T>() – This method of creating a mock object permits a looser replay of expectations. If a method is called unexpectedly, then the mock object will not fail verification and no exception is thrown.

    3. PartialMock<T>() – This method of creating a mock object can only be performed on classes. Only certain methods are mocked. Other methods of the class can be called normally.

    Listing 17 contains a class named Rover. Rover has two methods named Bark() and Fetch(). The unit tests in Listings 18 contrast the three methods of mocking Rover.

    Listing 17 – Rover.cs

       1:  using System;
       2:   
       3:  namespace RhinoMockProject
       4:  {
       5:      public class Rover
       6:      {
       7:   
       8:          public virtual void Bark(int loudness)
       9:          {
      10:              // Make loud noise
      11:          }
      12:   
      13:          public virtual void Fetch(int speed)
      14:          {
      15:              // Fetch something
      16:              throw new Exception("Yikes!");
      17:          }
      18:      
      19:      }
      20:  }

    Notice that both of Rover’s methods are marked as virtual methods. This is a requirement when using Rhino Mocks. When mocking a class, only virtual (and not sealed or static) methods can be mocked.

    Notice, furthermore, that the Fetch() method throws an exception. When this method is mocked, this exception won’t be thrown because the actual method won’t ever be called.

    Listing 18 – RoverTest.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using RhinoMockProject;
       8:  using Rhino.Mocks;
       9:   
      10:  namespace RhinoMockProjectTests
      11:  {
      12:      [TestClass]
      13:      public class RoverTest
      14:      {
      15:          [TestMethod]
      16:          public void BarkTestStrictReplay()
      17:          {
      18:              MockRepository mocks = new MockRepository();
      19:              Rover rover = mocks.CreateMock<Rover>();
      20:              using (mocks.Record())
      21:              {
      22:                  rover.Bark(17);
      23:                  LastCall
      24:                      .IgnoreArguments()
      25:                      .Repeat.Times(2);
      26:              }
      27:              using (mocks.Playback())
      28:              {
      29:                  rover.Bark(17);
      30:                  rover.Bark(23);
      31:                  // rover.Bark(2); // fail
      32:                  // rover.Fetch(2); // fail
      33:              }
      34:          }
      35:   
      36:          [TestMethod]
      37:          public void BarkTestNonStrictReplay()
      38:          {
      39:              MockRepository mocks = new MockRepository();
      40:              Rover rover = mocks.DynamicMock<Rover>();
      41:              using (mocks.Record())
      42:              {
      43:                  rover.Bark(17);
      44:                  LastCall
      45:                      .IgnoreArguments()
      46:                      .Repeat.Times(2);
      47:              }
      48:              using (mocks.Playback())
      49:              {
      50:                  rover.Bark(17);
      51:                  rover.Bark(23);
      52:                  rover.Bark(2); // pass
      53:                  rover.Fetch(2); // pass
      54:              }
      55:          }
      56:   
      57:          [TestMethod]
      58:          public void BarkTestPartialReplay()
      59:          {
      60:              MockRepository mocks = new MockRepository();
      61:              Rover rover = mocks.PartialMock<Rover>();
      62:              using (mocks.Record())
      63:              {
      64:                  rover.Bark(17);
      65:                  LastCall
      66:                      .IgnoreArguments()
      67:                      .Repeat.Times(2);
      68:              }
      69:              using (mocks.Playback())
      70:              {
      71:                  rover.Bark(17);
      72:                  rover.Bark(23);
      73:                  rover.Bark(2); // pass
      74:                  // rover.Fetch(2); // throws exception
      75:              }
      76:          }
      77:   
      78:      }
      79:  }

    Listing 18 contains three tests that test the same Rover class. The tests differ in how Rover is mocked.

    The first test -- named BarkTestStrictReplay() -- uses CreateMock<T>() to create an instance of Rover. The CreateMock<T>() method enforces strict expectations. If you don’t make the exact method calls setup in the expectations section, then the test fails when the expectations are played back against reality.

    For example, in this test, you can’t cause Rover to bark a third time since the expectation was setup that Rover would only bark twice. Also, you can’t call the Fetch() method since no expectations were setup concerning this method.

    The next test is named BarkTestNonStrictReplay(). In this test, Rover is created with the DynamicMock<T>() method. This method of creating a mock object allows for looser expectations. Calling the Bark() method a third time, or calling an unexpected method like Fetch(), does not cause the test to fail.

    Finally, the third test illustrates how you can mock Rover using the PartialMock<T>() method. The PartialMock<T>() method does not mock all of Rover’s methods and properties. In the test in Listing 18, Rover’s Bark() method is mocked but not his Fetch() method. When Fetch() is called, an exception is thrown since the actual Fetch() method throws an exception (see Listing 17).

    Creating Testable Web Applications

    In this last section, I want to draw your attention to a controversial topic. If you want to use Rhino Mocks to test an application, then you are forced to write your application in a particular way. Some people think this requirement is a virtue since it forces your application to have a testable design. Other people believe that the design of your application should not be dictated by the limitations of a particular tool.

    Rhino Mocks places two important constraints on the design of your application. First, since Rhino Mocks cannot be used to mock static or sealed methods, you are encouraged to avoid both static and sealed methods.

    Second, because you cannot mock what you cannot see, you are encouraged to follow a particular pattern called Dependency Injection when building an application with Rhino Mocks (see Martin Fowler, http://martinfowler.com/articles/injection.html). There are several variations of the Dependency Injection pattern, but the basic idea is that you should avoid instantiating classes within other classes. Instead, if one class is dependent on other classes, then you should pass these dependencies to the class when the class is initialized. Following this pattern makes it easier to mock the dependencies of a class.

    Let’s consider a particular code sample in which both of these limitations of Rhino Mocks is important. Imagine that you decide to create a Logger component for your application. When any method of your application is called, you want to log the action to a file on disk. If I didn’t care about Rhino Mocks, I would use the code in Listing 19 to create the Logger component.

    Listing 19 – Logger.cs (First iteration)

       1:  using System;
       2:   
       3:  namespace RhinoMockProject
       4:  {
       5:      public class Logger
       6:      {
       7:          public static void Write(string message)
       8:          {
       9:              // Log message to file system
      10:          }
      11:      }
      12:  }

    Notice that the Logger in Listing 19 uses a static method to write to the log file. The advantage of using a static method is that it saves a line of code when calling the method since you don’t need to instantiate the class before using it. For example, the DataProvider class in Listing 20 calls Logger.Write() in both of its methods.

    Listing 20 – DataProvider.cs (First Iteration)

       1:  using System;
       2:  using System.Collections.Generic;
       3:   
       4:  namespace RhinoMockProject
       5:  {
       6:   
       7:      public class DataProvider
       8:      {
       9:          public static IEnumerable<Product> GetProducts()
      10:          {
      11:              Logger.Write("Getting products");
      12:   
      13:              // Get products from database
      14:              return null;
      15:          }
      16:   
      17:   
      18:          public static bool SaveProduct(Product product)
      19:          {
      20:              Logger.Write("Saving new product");
      21:   
      22:              // Save product to database
      23:              return true;
      24:          }
      25:   
      26:   
      27:      }
      28:  }

    The problem with this approach to building a Logger component is that it is not compatible with Rhino Mocks. The Logger class is not Rhino Mocks mockable for two reasons. First, you cannot mock the Logger.Write() method since it is a static method. Second, you cannot mock the Logger class when it is used within the DataProvider class since the Logger class is not exposed outside of the DataProvider class (you cannot mock what you cannot see).

    Listing 21 contains a mockable version of the Logger class. In this revised version, the Write() method is a virtual instance method rather than a static method.

    Listing 21 – Logger.cs (Second Iteration)

       1:  using System;
       2:   
       3:  namespace RhinoMockProject
       4:  {
       5:      public class Logger
       6:      {
       7:          public virtual void Write(string message)
       8:          {
       9:              // Log message to file system
      10:          }
      11:      }
      12:  }

    The DataProvider class in Listing 22 has been revised to support Dependency Injection. The new DataProvider class accepts an instance of the Logger class in its constructor.

    Listing 22 – DataProvider.cs (Second Iteration)

       1:  using System;
       2:  using System.Collections.Generic;
       3:   
       4:  namespace RhinoMockProject
       5:  {
       6:      public class DataProvider
       7:      {
       8:          private Logger _logger;
       9:   
      10:          public DataProvider(Logger logger)
      11:          {
      12:              _logger = logger;
      13:          }
      14:   
      15:          public virtual IEnumerable<Product> GetProducts()
      16:          {
      17:              _logger.Write("Getting products");
      18:   
      19:              // Get products from database
      20:              return null;
      21:          }
      22:   
      23:          public virtual bool SaveProduct(Product product)
      24:          {
      25:              _logger.Write("Saving new product");
      26:   
      27:              // Save product to database
      28:              return true;
      29:          }
      30:      }
      31:  }

    Finally, the test in Listing 23 illustrates how you can use Rhino Mocks to perform a behavior verification of the Logger and DataProvider class. Notice that a mock version of the Logger class is created and passed to an actual instance of the DataProvider class.

    Listing 23 – LoggerTest.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using Rhino.Mocks;
       8:  using RhinoMockProject;
       9:   
      10:  namespace RhinoMockProjectTests
      11:  {
      12:      [TestClass]
      13:      public class LoggerTest
      14:      {
      15:          [TestMethod]
      16:          public void WriteTest()
      17:          {
      18:              MockRepository mocks = new MockRepository();
      19:              Logger logger = mocks.CreateMock<Logger>();
      20:              DataProvider dp = new DataProvider(logger);
      21:              using (mocks.Record())
      22:              {
      23:                  logger.Write("Saving new product");
      24:                  logger.Write("Getting products");
      25:              }
      26:              using (mocks.Playback())
      27:              {
      28:                  dp.SaveProduct(null);
      29:                  dp.GetProducts();
      30:              }
      31:          }
      32:   
      33:      }
      34:  }

    The test in Listing 23 mocks the Logger class and injects the mock into the DataProvider’s constructor. The test sets up the expectations that the Logger.Write() method will be called twice with particular messages. In the Playback section, the DataProvider.SaveProduct() and DataProvider.GetProducts() methods are called, the expectations are matched, and the test passes.

    If you are really interested in testable design, then you would most likely not stop here. The next step is to create an interface for the Logger class and pass the interface to the DataProvider constructor instead of the Logger class itself. You should be injecting ILogger instead of a particular logger. Out of laziness, I’ll stop here.

    Before ending this section, it is worth mentioning that Typemock Isolator, another Mock Object Framework for .NET, does not have the limitations discussed in this section. You can use Typemock Isolator to mock static methods. Furthermore, you can mock objects without following the Dependency Injection pattern. Some people think this is a virtue of Typemock Isolator and some people think that this is a vice.

    Summary

    The purpose of this blog entry was to provide you with an introduction to Rhino Mocks. This entry was certainly not intended as a comprehensive discussion of all of the features of Rhino Mocks. The goal was to explain how you can use Rhino mocks to perform both state verification and behavioral verification unit tests. I also discussed some of the important limitations of Rhino Mocks and how these limitations affect how you build applications.

  • TDD: Test-Driven Development with Visual Studio 2008 Unit Tests

    The purpose of this blog entry is to explain how you can create unit tests by using Visual Studio 2008. I’m not interested in unit tests in general -- I’m interested in building a particular type of unit test. I want to build unit tests that can be used when following good Test-Driven Development (TDD) practices when building ASP.NET MVC Web Application projects.

    Not all unit tests are good TDD tests. In order for a unit test to be useful for Test-Driven Development, you must be able to execute the unit test very quickly. Not all unit tests meet this requirement.

    For example, Visual Studio supports a special type of unit test for ASP.NET websites. You must execute this type of unit test in the context of either IIS or the development web server. This is not an appropriate type of unit test to use when practicing Test-Driven Development because this type of unit test is just too slow.

    In this blog entry, I’m going to provide you with a walk-through of the process of building unit tests that can be used for Test-Driven Development. I’m going to dive into the details of the Visual Studio 2008 unit testing framework. I’m also going to discuss several advanced topics such as how you can test private methods and how you can execute tests from the command line.

    Note: Most of the features described in this blog entry are supported by the Professional Edition of Visual Studio 2008. Unfortunately, these features are not supported by Visual Web Developer. For a comparison of the unit testing features that each edition of Visual Studio 2008 supports, see http://msdn2.microsoft.com/en-us/library/bb385902.aspx.

    A Quick Walk-through

    Let’s start by creating a new ASP.NET MVC Web Application project and creating a Test Project. This part is easy. When you create a new ASP.NET MVC Web Application project, you are prompted to create a new Visual Studio Test Project. Just as long as you leave the top radio button selected -- the default option -- you get a new Test Project added to your solution automatically (see Figure 1).

    clip_image002

    Figure 1 – Creating a New ASP.NET MVC Web Application Project

    The question is: now that you have a Test Project, what do you do with it?

    When you create a new ASP.NET MVC application, the project includes one controller which is named HomeController. This default controller has two methods named Index() and About(). Corresponding to the HomeController, the Test Project includes a file named HomeControlleterTest. This file contains two test methods named Index() and About().

    The two test methods, Index() and About(), are empty by default (see Figure 2). You can add your test logic into the body of these methods.

    clip_image004

    Figure 2 – Empty About() test method ready to be written.

    Let’s imagine that you want to build an online store. Imagine that you want to create a Details page for your store that displays details for a particular product. You pass a query string that contains a product Id to the Details page, and the product details are retrieved from the database and displayed.

    Following good Test-Driven Development practice, before you do anything else, you first write a test. You don’t write any application code until you have a test for the code. The tests for the Details page act as a criterion for success. To create a successful Details page, the following tests must be satisfied:

    1. If a ProductId is not passed to the page, an exception should be thrown

    2. The ProductId should be used to retrieve a Product from the database

    3. If a matching Product cannot be retrieved from the database, an exception should be thrown

    4. The Details View should be rendered

    5. The Product should be assigned to the Details View’s ViewData

    So let’s implement the first test. According to the first test, if a ProductId is not passed to the Details page, an exception should be thrown. We need to add a new unit test to our Test Project. Right-click the Controllers folder in your Test Project and select Add, New Test. Select the Unit Test Template (see Figure 2). Name the new unit test ProductControllerTest.

    clip_image006

    Figure 2 – Adding a new unit test

    Be careful about how you create a new unit test since there are multiple ways to add a unit test in the wrong way. For example, if you right-click the Controllers folder and select Add, Unit Test, then you get the Unit Test Wizard. This wizard will generate a unit test that runs in the context of a web server. That’s not what we want. If you see the dialog box in Figure 3, then you know that you have attempted to add an MVC unit test in the wrong way.

    clip_image008

    Figure 3 – Whenever you see this dialog box click the Cancel button!

    The ProductControllerTest, by default, contains the single test method in Listing 1.

    Listing 1 – ProductControllerTest.cs (original)

       1:  [TestMethod]
       2:  public void TestMethod1()
       3:  {
       4:    //
       5:    // TODO: Add test logic here
       6:    //
       7:  }

    We want to modify this test method so that it tests whether an exception is thrown when the Details page is requested without a ProductId. The correct test is contained in Listing 2.

    Listing 2 – ProductControllerTest.cs (modified)

       1:  [TestMethod]
       2:  [ExpectedException(typeof(ArgumentNullException), "Exception no ProductId")]
       3:  public void Details_NoProductId_ThrowException()
       4:  {
       5:      ProductController controller = new ProductController();
       6:      controller.Details(null);
       7:  }

    Let me explain what is going on with the test in Listing 2. The method is decorated with two attributes. The first attribute [TestMethod] identifies the method as a test method. The second attribute [ExpectedException] sets up an expectation for the test. If executing the test method does not throw an ArgumentNullException, then the test fails. We want the test to throw an exception because we want an exception to be thrown when the Details page is requested without a ProductId.

    The body of the test method contains two statements. The first statement creates an instance of the ProductController class. The second statement calls the controller’s Details() method.

    Now, at this point, we have not created the ProductController class in our MVC application. So there is no way that this test will execute successfully. But that is okay. This is the correct path to walk when practicing Test-Driven Development. First, you write a test that fails, and then you write code to fix it.

    So let’s run the test so we can enjoy some failure. There should be a toolbar at the top of the code editor window that contains two buttons for running tests. The first button runs the tests in the current context and the second button runs all the tests in the solution (see Figure 4).

    clip_image010

    Figure 4 – Executing Visual Studio 2008 Tests

    What’s the difference between clicking the two buttons? Running tests in the current context executes different tests depending on the location of your cursor in the code editor window. If your cursor is located on a particular test method, only that method is executed. If your cursor is located on the test class, all tests in the test class are executed. If the Test Results window has focus, all of your tests are executed (for details, see http://blogs.msdn.com/nnaderi/archive/2007/05/11/new-unit-testing-features-in-orcas-part-1.aspx).

    Actually, you should always strive to avoid clicking buttons with your mouse. Clicking buttons is slow and Test-Driven Development is all about executing tests quickly. You can execute tests by using these keyboard combinations:

    · Ctrl-R, A – Run all tests in solution

    · Ctrl-R, T – Run all tests in current context

    · Ctrl-R, N – Run all tests in current namespace

    · Ctrl-R, C – Run all tests in current class

    · Ctrl-R, Ctrl-A – Debug all tests in solution

    · Ctrl-R, Ctrl-T – Debug all tests in current context

    · Ctrl-R, Ctrl-N – Debug all tests in current namespace

    · Ctrl-R, Ctrl-C – Debug all tests in current class

    If you run the test method that we just created -- by hitting Ctrl-R, A -- it will fail miserably. The test won’t even compile since we have not created the ProductController class or a Details() method. This is what we need to do next.

    Switching back to the ASP.NET MVC project, right-click the Controllers folder and select Add, New Item. Select the Web category and select MVC Controller class. Name the new controller ProductController and click the Add button (or just hit the Enter key). A new controller is created that includes one Index() method.

    We want to write the bare minimum amount of code necessary to cause our unit test to pass. The ProductController class in Listing 3 will pass our unit test.

    Listing 3 – ProductController.cs

       1:  using System;
       2:  using System.Collections.Generic;
       3:  using System.Linq;
       4:  using System.Web;
       5:  using System.Web.Mvc;
       6:   
       7:  namespace MvcApplication3.Controllers
       8:  {
       9:      public class ProductController : Controller
      10:      {
      11:          public void Details(int? ProductId)
      12:          {
      13:              throw new ArgumentNullException("ProductId");
      14:          }
      15:      }
      16:  }

    The class in Listing 3 contains one method named Details(). I erased the Index() method that you get by default when you create a new controller. The Details() method always throws an ArgumentNullException.

    After entering the code in Listing 3, hit the keyboard combination Ctrl-R, A (You don’t need to switch back to the Test Project to run the test). The Test Results window shows that our test was successfully passed (see Figure 5).

    clip_image012

    Figure 5 – The happy green of a test successfully passed

    You might be thinking that this is crazy. Currently, our Details() method always throws an exception. And, yes, the Details() method would be a crazy method to use in a production application. However, the whole point of Test-Driven Development is that you focus on satisfying the test that is sitting in front of you right now. Later tests will force you to triangulate and build a more respectable looking controller method.

    Visual Studio Test Attributes

    When we built our test in the previous section, we were required to use the following two attributes:

    · [TestMethod] – Used to mark a method as a test method. Only methods marked with this attribute will run when you run your tests.

    · [TestClass] – Used to mark a class as a test class. Only classes marked with this attribute will run when you run your tests.

    When building tests, you always use the [TestMethod] and [TestClass] attributes. However, there are several other useful, but optional, test attributes. For example, you can use the following attribute pairs to setup and tear down tests:

    · [AssemblyInitialize] and [AssemblyCleanup] – Used to mark methods that execute before and after all of the tests in an assembly are executed

    · [ClassInitialize] and [ClassCleanup] – Used to mark methods that execute before and after all of the tests in a class are executed

    · [TestInitialize] and [TestCleanup] – Used to mark methods that execute before and after each test method is executed

    For example, you might want to create a fake HttpContext that you can use with all of your test methods. You can setup the fake HttpContext in a method marked with the [ClassInitialize] attribute and dispose of the fake HttpContext in a method marked with the [ClassCleanup] attribute.

    There are several attributes that you can use to provide additional information about test methods. These attributes are useful when you are working with hundreds of unit tests and you need to manage the tests by sorting and filtering the tests:

    · [Owner] – Enables you to specify the author of a test method

    · [Description] – Enables you to provide a description of a test method

    · [Priority] – Enables you to specify an integer priority for a test

    · [TestProperty] – Enables you to specify an arbitrary test property

    You can use these attributes when sorting and filtering tests in either the Test View window or the Test List Editor.

    Finally, there is an attribute that you can use to cause a particular test method to be ignored when running a test. This attribute is useful when one of your tests has a problem and you just don’t want to deal with the problem at the moment:

    · [Ignore] – Enables you to temporarily disable a test. You can use this attribute on either a test method or an entire test class

    Creating Test Assertions

    Most of the time, when you are writing the code for your test methods, you use the methods of the Assert class. The last line of code contained in most test methods uses the Assert class to assert a condition that a test must satisfy in order for the test to pass.

    The Assert class supports the following static methods:

    · AreEqual – Asserts that two values are equal

    · AreNotEqual – Asserts that two values are not equal

    · AreNotSame – Asserts that two objects are different objects

    · AreSame – Asserts that two objects are the same object

    · Fail – Asserts that the test fails

    · Inconclusive – Asserts that a test result is inconclusive. Visual Studio includes this assertion for methods that it generates automatically and that you need to implement

    · IsFalse – Asserts that a given condition expression returns the value False

    · IsInstanceOfType – Asserts that a given object is an instance of a specified type

    · IsNotInstanceOfType – Asserts that a given object is not an instance of a specified type

    · IsNotNull – Asserts that an object does not represent the Null value

    · IsNull – Asserts that an object represents the Null value

    · IsTrue – Asserts that a given condition expression returns the value True

    · ReplaceNullChars – Replaces Null characters in a string \0 with \\0

    When an Assert method fails, the Assert class throws an AssertFailedException.

    For example, imagine that you are writing a unit test to test a method that adds two numbers. The test method in Listing 4 uses an Assert method to check whether the method being tested returns the correct result for 2 + 2.

    Listing 4 – CalculateTest.cs

       1:  [TestMethod]
       2:  public void AddNumbersTest()
       3:  {
       4:      int result = Calculate.Add(2, 2);
       5:      Assert.AreEqual(result, 2 + 2);
       6:  }

    There is a special class for testing assertions about collections named the CollectionAssert class. The CollectionAssert class supports the following static methods:

    · AllItemsAreInstancesOfType – Asserts that each item in a collection is of a specified type

    · AllItemsAreNotNull – Asserts that each item in a collection is not null

    · AllItemsAreUnique – Asserts that each item in a collection is unique

    · AreEqual – Asserts that the value of each item in two collections are equal

    · AreEquivalent – Asserts that the values of each item in two collections are equal (but the order of the items in the first collection might not match the order of the items in the second collection).

    · AreNotEqual – Asserts that two collections are not equal

    · AreNotEquivalent – Asserts that two collections are not equivalent

    · Contains – Asserts that a collection contains an item

    · DoesNotContain – Asserts that a collection does not contain an item

    · IsNotSubsetOf – Asserts that one collection is not a subset of another collection

    · IsSubsetOf – Asserts that one collection is a subset of another collection

    This also is a special class, named StringAssert, for performing assertions about strings. The StringAssert class supports the following static methods:

    · Contains -- Asserts that a string contains a specified substring

    · DoesNotMatch – Asserts that a string does not match a specified regular expression

    · EndsWith – Asserts that a string ends with a specified substring

    · Matches – Asserts that a string matches a specified regular expression

    · StartsWith – Asserts that a string starts with a specified substring

    Finally, you can use the [ExpectedException] attribute to assert that a test method should throw a particular type of exception. We used the ExpectedException attribute in the walkthrough above to test whether or not a Null ProductId caused a controller to throw an ArgumentNullException.

    Generating Tests from Existing Code

    Visual Studio 2008 enables you to generate unit tests from existing code automatically. You can right-click any method in a class and select the option Create Unit Tests.

    clip_image014

    Figure 6 – Generating a unit test from existing code

    Even practitioners of Test-Driven Development must work with legacy code. If you need to add unit tests to existing code, you can take advantage of this option to quickly create the necessary test method stubs.

    One big warning about this approach to adding unit tests. If you use this option on a class located in an ASP.NET MVC Web Application Project, then the Unit Test Wizard opens. Unfortunately, this wizard generates a unit test that executes within the context of a web server. This type of unit test is not appropriate for Test-Driven Development because it just takes too long to execute. Therefore, I recommend that you take the approach to generating unit tests described in this section only when working with Class Library projects.

    Testing Private Methods, Properties, and Fields

    When following good Test-Driven Development practices, you test all of your code, including the private methods in your application. How do you test private methods from your test project? The problem, it might seem, is that you cannot call the private methods from within a unit test.

    There are two ways around this problem. First, Visual Studio 2008 can generate a façade class that exposes all the private members of the class being tested. Within Visual Studio 2008, you can right-click any class within the Code Editor and select the menu option Create Private Accessor. Selecting this menu option generates a new class that exposes all of the private methods, private properties, and private fields of the class as public methods, public properties, and public fields.

    For example, imagine that you want to test a class named Calculate that contains a private method named Subtract(). You can right click this class and generate an Accessor (see Figure 7).

    clip_image016

    Figure 7 – Creating a Private Accessor

    After you create the Accessor, you can use it in your unit test code to test the Subtract method. For example, the unit test in Listing 5 tests whether the subtract method returns the right result for 7 – 5.

    Listing 5 – CalculateTest.cs (Accessor)

       1:  [TestMethod]
       2:  public void SubtractTest()
       3:  {
       4:      int result = Calculate_Accessor.Subtract(7, 5); 
       5:      Assert.AreEqual(result, 7 - 5);
       6:  }

    Notice that in Listing 5, the Subtract() method is called on the Calculate_Accessor class and not the Calculate class. Because the Subtract() method is private, you can’t call it on the Calculate class. However, the generated Calculate_Accessor class exposes the method just fine.

    If you prefer, you can generate the Accessor class from the command line. Visual Studio includes a command line tool named Publicize.exe that generates a public façade for a class with private members.

    The second method for testing private class methods is to use reflection. By taking advantage of reflection, you can bypass access restrictions and invoke any class method and access any class property. The test in Listing 6 uses reflection to call the private Calculate.Subtract() method.

    Listing 6 – CalculateTest.cs (reflection)

       1:  [TestMethod]
       2:  public void SubtractTest()
       3:  {
       4:      MethodInfo method = typeof(Calculate).GetMethod("Subtract", 
    BindingFlags.NonPublic | BindingFlags.Static);
       5:      int result = (int)method.Invoke(null, new object[] { 7, 5 });
       6:      Assert.AreEqual(result, 7 - 5);
       7:  }

    The code in Listing 6 calls the private static Subtract() method by calling the Invoke() method on a MethodInfo object that represents the Subtract method (this is the kind of code that you would want to package into a utility class so that it would be easy to reuse for other tests).

    All of Those Confusing Test Windows

    I confess that one of my main motivations for writing this blog entry was that I was confused by all of the various test windows and I wanted to sort them out. Visual Studio 2008 has 3 windows related to unit tests.

    First, there is the Test Results window (see Figure 8). This window is displayed after you run your tests. You also can display this window by selecting the menu option Test, Windows, Test Results. The Test Window displays each test that was run and displays whether the test failed or passed.

    clip_image018

    Figure 8 – The Test Results window

    If you click on the link labeled Test run completed or Test run failed you get a page that provides more detailed information about the test run.

    Second, there is the Test View window (see Figure 9). You can open the Test View window by selecting the menu option Test, Windows, Test View. The Test View window lists all of your tests. You can select an individual test and run the test. You can also filter the tests in the Test View using particular test properties (for example, show only the tests written by Stephen).

    clip_image020

    Figure 9 – The Test View window

    Third, there is the Test List Editor window (see Figure 10). Open this window by selecting the menu option Test, Windows, Test List Editor. This window enables you to organize your tests into different lists. You can create new lists of tests and add the same test to multiple lists. Creating multiple test lists is useful when you need to manage hundreds of tests.

    clip_image022

    Figure 10 – The Test List Editor window

    Managing Test Runs

    After you execute your unit tests more than 25 times, you get the dialog box in Figure 11. Until I received this warning, I didn’t realize that Visual Studio creates a separate copy of all of the assemblies in a solution each time you do a test run (each time you run your unit tests).

    clip_image024

    Figure 11 – A mysterious message about test runs

    If you use Windows Explorer and take a look inside your application’s solution folder on disk, then you can see a folder named TestResults that Visual Studio 2008 creates for you automatically. This folder contains an XML file and a subfolder for each test run.

    You can prevent Visual Studio 2008 from creating copies of your assemblies for each test run by disabling test deployment. In order to do this, you modify your test run configuration file. Select the menu option Test, Edit Test Run Configurations. Select the Deployment tab and uncheck the checkbox labeled Enable deployment.

    clip_image026

    Figure 12 – Disabling Test Deployment

    Sometimes, when you go to the Test, Edit Test Run Configurations menu item, you see the message that there are no test run configurations available. In that case, you need to right-click your solution in the Solution Explorer window, select Add, New Item, and add a new Test Run Configuration. After you add a new Test Run Configuration file, you can open the dialog box in Figure12.

    Be warned that if you disable test deployment, you can no longer take advantage of the code coverage feature. If you aren’t using this feature, then don’t worry about it.

    Running Tests from the Command Line

    You might want to run your unit tests from the command line. For example, you might just have a perverse dislike for Integrated Development Environments like Visual Studio and want to write all of your code using Notepad. Or, more likely, you might want to run your tests automatically as part of a custom code check-in policy.

    You run your tests from the command line by opening up a Visual Studio 2008 Command Prompt (All Programs, Microsoft Visual Studio 2008, Visual Studio Tools, Visual Studio 2008 Command Prompt). After you open the command prompt, navigate to the assembly generated by your test project. For example:

    Documents\Visual Studio 2008\Projects\MyMvcApp\MyMvcAppTests\Bin\Debug

    Run your tests by executing the following command:

    mstest /testcontainer:MyMvcAppTests.dll

    Issuing this command will run all of your tests (see Figure 13).

    clip_image028

    Figure 13 – Running your unit tests from the command line

    Summary

    The goal of this blog entry was to get a better understanding of how you can use Visual Studio 2008 to write unit tests that can be used for Test-Driven Development. Visual Studio was designed to support many different types of tests and many different testing audiences. The sheer number of testing options (and test related windows) can be overwhelming. However, I hope that I have convinced you that Visual Studio 2008 can be a very effective environment for performing Test-Driven Development.

    Okay, so if you ignored everything else in this blog entry, at least remember that using the keyboard combination Ctrl-R, A runs all of the tests in your solution. Enough said.

  • ASP.NET MVC In-Depth: The Life of an ASP.NET MVC Request

    The purpose of this blog entry is to describe, in painful detail, each step in the life of an ASP.NET MVC request from birth to death. I want to understand everything that happens when you type a URL in a browser and hit the enter key when requesting a page from an ASP.NET MVC website.

    Why do I care? There are two reasons. First, one of the promises of ASP.NET MVC is that it will be a very extensible framework. For example, you’ll be able to plug in different view engines to control how your website content is rendered. You also will be able to manipulate how controllers get generated and assigned to particular requests. I want to walk through the steps involved in an ASP.NET MVC page request because I want to discover any and all of these extensibility points.

    Second, I’m interested in Test-Driven Development. In order to write unit tests for controllers, I need to understand all of the controller dependencies. When writing my tests, I need to mock certain objects using a mocking framework such as Typemock Isolator or Rhino Mocks. If I don’t understand the page request lifecycle, I won’t be able to effectively mock it.

    Two Warnings

    But first, two warnings.

    Here's the first warning: I’m writing this blog entry a week after the ASP.NET MVC Preview 2 was publicly released. The ASP.NET MVC framework is still very much in Beta. Therefore, anything that I describe in this blog entry might be outdated and, therefore, wrong in a couple of months. So, if you are reading this blog entry after May 2008, don’t believe everything you read.

    Second, this blog entry is not meant as an overview of ASP.NET MVC. I describe the lifecycle of an ASP.NET MVC request in excruciating and difficult to read detail. Okay, you have been warned.

    Overview of the Lifecycle Steps

    There are five main steps that happen when you make a request from an ASP.NET MVC website:

    1. Step 1 – The RouteTable is Created

    This first step happens only once when an ASP.NET application first starts. The RouteTable maps URLs to handlers.

    2. Step 2 – The UrlRoutingModule Intercepts the Request

    This second step happens whenever you make a request. The UrlRoutingModule intercepts every request and creates and executes the right handler.

    3. Step 3 – The MvcHandler Executes

    The MvcHandler creates a controller, passes the controller a ControllerContext, and executes the controller.

    4. Step 4 – The Controller Executes

    The controller determines which controller method to execute, builds a list of parameters, and executes the method.

    5. Step 5 – The RenderView Method is Called

    Typically, a controller method calls RenderView() to render content back to the browser. The Controller.RenderView() method delegates its work to a particular ViewEngine.

    Let’s examine each of these steps in detail.

    Step 1 : The RouteTable is Created

    When you request a page from a normal ASP.NET application, there is a page on disk that corresponds to each page request. For example, if you request a page named SomePage.aspx then there better be a page named SomePage.aspx sitting on your web server. If not, you receive an error.

    Technically, an ASP.NET page represents a class. And, not just any class. An ASP.NET page is a handler. In other words, an ASP.NET page implements the IHttpHandler interface and has a ProcessRequest() method that gets called when you request the page. The ProcessRequest() method is responsible for generating the content that gets sent back to the browser.

    So, the way that a normal ASP.NET application works is simple and intuitive. You request a page, the page request corresponds to a page on disk, the page executes its ProcessRequest() method and content gets sent back to the browser.

    An ASP.NET MVC application does not work like this. When you request a page from an ASP.NET MVC application, there is no page on disk that corresponds to the request. Instead, the request is routed to a special class called a controller. The controller is responsible for generating the content that gets sent back to the browser.

    When you write a normal ASP.NET application, you build a bunch of pages. There is always a one-to-one mapping between URLs and pages. Corresponding to each page request, there better be a page.

    When you build an ASP.NET MVC application, in contrast, you build a bunch of controllers. The advantage of using controllers is that you can have a many-to-one mapping between URLs and pages. For example, all of the following URLs can be mapped to the same controller:

    http://MySite/Products/1

    http://MySite/Products/2

    http://MySite/Products/3

    The single controller mapped to these URLs can display product information for the right product by extracting the product Id from the URL. The controller approach is more flexible than the classic ASP.NET approach. The controller approach also results in more readable and intuitive URLs.

    So, how does a particular page request get routed to a particular controller? An ASP.NET MVC application has something called a Route Table. The Route Table maps particular URLs to particular controllers.

    An application has one and only one Route Table. This Route Table is setup in the Global.asax file. Listing 1 contains the default Global.asax file that you get when you create a new ASP.NET MVC Web Application project by using Visual Studio.

    Listing 1 – Global.asax

       1:  using System;
       2:  using System.Collections.Generic;
       3:  using System.Linq;
       4:  using System.Web;
       5:  using System.Web.Mvc;
       6:  using System.Web.Routing;
       7:   
       8:  namespace TestMVCArch
       9:  {
      10:      public class GlobalApplication : System.Web.HttpApplication
      11:      {
      12:          public static void RegisterRoutes(RouteCollection routes)
      13:          {
      14:              // Note: Change the URL to "{controller}.mvc/{action}/{id}" to enable
      15:              //       automatic support on IIS6 and IIS7 classic mode
      16:   
      17:              routes.Add(new Route("{controller}/{action}/{id}", new MvcRouteHandler())
      18:              {
      19:                  Defaults = new RouteValueDictionary(new { action = "Index", id = "" }),
      20:              });
      21:   
      22:              routes.Add(new Route("Default.aspx", new MvcRouteHandler())
      23:              {
      24:                  Defaults = new RouteValueDictionary(new { controller = "Home", action = "Index", id = "" }),
      25:              });
      26:          }
      27:   
      28:          protected void Application_Start(object sender, EventArgs e)
      29:          {
      30:              RegisterRoutes(RouteTable.Routes);
      31:          }
      32:      }
      33:  }

    An application’s Route Table is represented by the static RouteTable.Routes property. This property represents a collection of Route objects. In the Global.asax file in Listing 1, two Route objects are added to the Route Table when the application first starts (The Application_Start() method is called only once when the very first page is requested from a website).

    A Route object is responsible for mapping URLs to handlers. In Listing 1, two Route objects are created. Both Route objects map URLs to the MvcRouteHandler. The first Route maps any URL that follows the pattern {controller}/{action}/{id} to the MvcRouteHandler. The second Route maps the particular URL Default.aspx to the MvcRouteHandler.

    By the way, this new routing infrastructure can be used independently of an ASP.NET MVC application. The Global.asax file maps URLs to the MvcRouteHandler. However, you have the option of routing URLs to a different type of handler. The routing infrastructure described in this section is contained in a distinct assembly named System.Web.Routing.dll. You can use the routing without using the MVC.

    Step 2 : The UrlRoutingModule Intercepts the Request

    Whenever you make a request against an ASP.NET MVC application, the request is intercepted by the UrlRoutingModule HTTP Module. An HTTP Module is a special type of class that participates in each and every page request. For example, classic ASP.NET includes a FormsAuthenticationModule HTTP Module that is used to implement page access security using Forms Authentication.

    When the UrlRoutingModule intercepts a request, the first thing the module does is to wrap up the current HttpContext in an HttpContextWrapper2 object. The HttpContextWrapper2 class, unlike the normal HttpContext class, derives from the HttpContextBase class. Creating a wrapper for HttpContext makes it easier to mock the class when you are using a Mock Object Framework such as Typemock Isolator or Rhino Mocks.

    Next, the module passes the wrapped HttpContext to the RouteTable that was setup in the previous step. The HttpContext includes the URL, form parameters, query string parameters, and cookies associated with the current request. If a match can be made between the current request and one of the Route objects in the Route Table, then a RouteData object is returned.

    If the UrlRoutingModule successfully retrieves a RouteData object then the module next creates a RouteContext object that represents the current HttpContext and RouteData. The module then instantiates a new HttpHandler based on the RouteTable and passes the RouteContext to the new handler’s constructor.

    In the case of an ASP.NET MVC application, the handler returned from the RouteTable will always be an MvcHandler (The MvcRouteHandler returns an MvcHandler). Whenever the UrlRoutingModule can match the current request against a Route in the Route Table, an MvcHandler is instantiated with the current RouteContext.

    The last step that the module performs is setting the MvcHandler as the current HTTP Handler. An ASP.NET application calls the ProcessRequest() method automatically on the current HTTP Handler which leads us to the next step.

    Step 3 : The MvcHandler Executes

    In the previous step, an MvcHandler that represents a particular RouteContext was set as the current HTTP Handler. An ASP.NET application always fires off a certain series of events including Start, BeginRequest, PostResolveRequestCache, PostMapRequestHandler, PreRequestHandlerExecute, and EndRequest events (there are a lot of application events – for a complete list, lookup the HttpApplication class in the Microsoft Visual Studio 2008 Documentation).

    Everything described in the previous section happens during the PostResolveRequestCache and PostMapRequestHandler events. The ProcessRequest() method is called on the current HTTP Handler right after the PreRequestHandlerExecute event.

    When ProcessRequest() is called on the MvcHandler object created in the previous section, a new controller is created. The controller is created from a ControllerFactory. This is an extensibility point since you can create your own ControllerFactory. The default ControllerFactory is named, appropriately enough, DefaultControllerFactory.

    The RequestContext and the name of the controller are passed to the ControllerFactory.CreateController() method to get a particular controller. Next, a ControllerContext object is constructed from the RequestContext and the controller. Finally, the Execute() method is called on the controller class. The ControllerContext is passed to the Execute() method when the Execute() method is called.

    Step 4 : The Controller Executes

    The Execute() method starts by creating the TempData object (called the Flash object in the Ruby on Rails world). The TempData can be used to store temporary data that must be used with the very next request (TempData is like Session State with no long-term memory).

    Next, the Execute() method builds a list of parameters from the request. These parameters, extracted from the request parameters, will act as method parameters. The parameters will be passed to whatever controller method gets executed.

    The Execute() method finds a method of the controller to execute by using reflection on the controller class (.NET reflection and not navel gazing reflection). The controller class is something that you wrote. So the Execute() method finds one of the methods that you wrote for your controller class and executes it. The Execute() method will not execute any controller methods that are decorated with the NonAction attribute.

    At this point in the lifecycle, we’ve entered your application code.

    Step 5 : The RenderView Method is Called

    Normally, your controller methods end with a call to either the RenderView() or RedirectToAction() method. The RenderView() method is responsible for rendering a view (a page) to the browser.

    When you call a controller’s RenderView() method, the call is delegated to the current ViewEngine’s RenderView() method. The ViewEngine is another extensibility point. The default ViewEngine is the WebFormViewEngine. However, you can use another ViewEngine such as the NHaml ViewEngine.

    The WebFormViewEngine.RenderView() method uses a class named the ViewLocator class to find the view. Next, it uses a BuildManager to create an instance of a ViewPage class from its path. Next, if the page has a master page, the location of the master page is set (again, using the ViewLocator class). If the page has ViewData, the ViewData is set. Finally, the RenderView() method is called on the ViewPage.

    The ViewPage class derives from the base System.Web.UI.Page class. This is the same class that is used for pages in classic ASP.NET. The final action that RenderView() method performs is to call ProcessRequest() on the page class. Calling ProcessRequest() generates content from the view in the same way that content is generated from a normal ASP.NET page.

    Extensibility Points

    The ASP.NET MVC lifecycle was designed to include a number of extensibility points. These are points where you can customize the behavior of the framework by plugging in a custom class or overriding an existing class. Here’s a summary of these extensibility points:

    1. Route objects – When you build the Route Table, you call the RouteCollection.Add() method to add new Route objects. The Add() method accepts a RouteBase object. You can implement your own Route objects that inherit from the base RouteBase class.

    2. MvcRouteHandler – When building an MVC application, you map URLs to MvcRouteHandler objects. However, you can map a URL to any class that implements the IRouteHandler interface. The constructor for the Route class accepts any object that implements the IRouteHandler interface.

    3. MvcRouteHandler.GetHttpHandler() – The GetHttpHandler() method of the MvcRouteHandler class is a virtual method. By default, an MvcRouteHandler returns an MvcHandler. If you prefer, you can return a different handler by overriding the GetHttpHandler() method.

    4. ControllerFactory – You can assign a custom class by calling the System.Web.MVC.ControllerBuilder.Current.SetControllerFactory() method to create a custom controller factory. The controller factory is responsible for returning controllers for a given controller name and RequestContext.

    5. Controller – You can implement a custom controller by implementing the IController interface. This interface has a single method: Execute(ControllerContext controllerContext).

    6. ViewEngine – You can assign a custom ViewEngine to a controller. You assign a ViewEngine to a controller by assigning a ViewEngine to the public Controller.ViewEngine property. A ViewEngine must implement the IViewEngine interface which has a single method: RenderView(ViewContext viewContext).

    7. ViewLocator – The ViewLocator maps view names to the actual view files. You can assign a custom ViewLocator to the default WebFormViewEngine.ViewLocator property.

    If you can think of any other extensibility points that I overlooked, please add a comment to this blog post and I will update this entry.

    Summary

    The goal of this blog entry was to describe the entire life of an ASP.NET MVC request from birth to death. I examined the five steps involved in processing an ASP.NET MVC request: Creating the RouteTable, Intercepting the request with the UrlRoutingModule, Generating a Controller, Executing an Action, and Rendering a View. Finally, I talked about the points at which the ASP.NET MVC Framework can be extended.

  • TDD: Introduction to Typemock Isolator

    Typemock Isolator is often referred to the most powerful Mock Object Framework for .NET. I’ve heard people talk about it as “The Big Guns”, “The Nuclear Weapon”, the “Cleanup Guy”. In this blog entry, I’m going to provide you with a brief introduction to Typemock Isolator.

    In the first section, I’m going to explain the purpose of Mock Object Frameworks and why you should care about them (ASP.NET MVC developers, pay attention). Next, I’m going to provide you with some toy-simple samples of using TypeMock Isolator so you get the idea of how to use the framework. One of the samples demonstrates how you can use Typemock to simulate LINQ to SQL queries (very, very cool stuff). Finally, I’m going to tackle a more realistic sample of using Typemock. In the final section of this blog entry, I’m going to show you how you can use Typemock to mock configuration and database dependencies so that you can write effective unit tests.

    The Importance of Mocking

    Typemock Isolator is a Mock Object Framework (also referred to simply as a Mocking Framework). A Mock Object Framework enables you to simulate objects when testing your code. For example, you can use Typemock to simulate instantiating objects, calling object methods, and reading and setting object properties.

    Why is this important? If you are practicing Test-Driven Development (TDD), then you write unit tests like a maniac. Practitioners of TDD follow a process called Red, Green, Refactor. When you sit down and start writing an application, the first thing you do is write a test. Then you run the test and it fails because you haven’t written any application code (this is the Red part). Next, you write the necessary code to pass the test (and only the necessary code to write the test). When you run the test again, you pass (this is the Green part). Next, you might cleanup your code. For example, you might consolidate common logic into a single method (this is the Refactor part). Repeat, repeat, repeat.

    If you are building ASP.NET MVC applications then, most likely, you’ll also be practicing TDD. One of the main motivations for building ASP.NET MVC is to support TDD. The MVC architecture enables a clean Separation of Concerns (SoC) which makes Test-Driven Development possible.

    When writing code using TDD, you constantly write and run unit tests. You run these tests over and over and over again. This means that a unit test must be fast. If your unit tests are not fast, then you’ll never get any work done because you’ll be sitting around all day waiting for your unit tests to complete.

    Furthermore, your unit tests should enable you to test a particular piece of code (a unit of code) in isolation. If one unit of code is dependent on another unit of code, then you end up not testing a single unit of code. If your code is riddled with dependencies, then your unit tests quickly turn into what are called integration or system tests. You end up testing an entire application with a unit test instead of particular unit of code.

    So, unit tests need to be fast and they need to enable you to test code in isolation. In practice, satisfying these requirements can be very difficult. The problem is that real-world code often has many dependencies. What is worse, often these dependencies are dependencies on external resources such as databases, web services, or the file system.

    The Problem

    Imagine, for example, that you are building a database-driven web application. You are building an online store. Imagine that the application currently has a method that retrieves all of the products from the database that looks like this:

            public static List<Product> GetProducts()
            {
                string conString = ConfigHelper.GetDBConnectionString();
                DataProvider dp = new DataProvider(conString);
                return dp.GetProducts();
            }

    The GetProducts() method gets a database connection string from a class named ConfigHelper, instantiates a data provider, and calls the data provider’s GetProducts() method to grab the products from the database.

    Imagine that you are asked to add a new feature to this application. When retrieving products, you are asked to calculate the sales tax. You are asked to modify the method that retrieves the products from the database in such a way that the method adds the sales tax to each product’s price. You are asked to make the new method look like this:

            public static List<Product> GetProducts(decimal tax)
            {
                ... modified code that adds sales tax ...
            }

    Following good TDD practice, you start implementing this feature by writing a unit test. But here is where you start encountering problems. The GetProducts() method has two external dependencies. First, the method uses a class called ConfigHelper to get the database connection string. The ConfigHelper class reads the connection string from the Web.config file.

    You don’t want to read the database connection string from the web.config file whenever you run the test. Reading information from a configuration file violates the requirement that a unit test should test code in isolation. You don’t want to test whether or not the configuration file is setup correctly. Instead, you want to test your tax calculation.

    Second, the GetProducts() method has a dependency on a DataProvider object. The DataProvider retrieves a set of records from the database. This dependency violates both the isolation and the speed requirements. If you call the GetProducts() method in your unit test, then you will access the database, and that can make the unit test slow (Imagine that you have 500 of these unit tests that you execute whenever you change the code in your application).

    At this point, you might conclude that there is no way to unit test the GetProducts() method. Units of code are an illusion since all real code is interdependent. No code is an island. Therefore, unit tests are impossible. Therefore, TDD is a foolish practice. Therefore, ASP.NET MVC is a stupid framework. Therefore, we should write all of our websites in Perl.

    The Solution

    Please don’t start using Perl. The solution to the problem discussed in the previous section is to use a Mock Object Framework. A Mock Object Framework enables you to simulate objects. You can use mock objects to trick your application into thinking that it is interacting with the normal objects when, in fact, it is actually interacting with sneaky imposters.

    In the case of the GetProducts() method, you can use a Mock Object Framework to simulate both the ConfigHelper and the DataProvider objects. You can create a mock ConfigHelper class that doesn’t really access the web.config file. You can create a mock DataProvider class that doesn’t really access the database. That way, you can test your tax calculation code in isolation.

    What makes Mock Object Frameworks, such as Typemock Isolator, truly powerful is that you can even return fake data from your mock object methods and properties. For example, you can cause the mock DataProvider.GetProducts() method to return a fake collection of products each time it is called. That way, you can test your tax calculation code against a set of products without actually accessing the database.

    In summary, Mock Object Frameworks are critical tools for Test-Driven Development. If you are interested in using ASP.NET MVC, and you want to pursue Test-Driven Development, then it is a good idea to get familiar with the Mock Object Frameworks (this is the rationale for this blog entry).

    Using Typemock Isolator

    Typemock Isolator is a commercial product. As far as I know, it is the only commercial Mock Object Framework for the .NET framework. Typemock Isolator comes in a (free) Community Edition, a Professional edition, and an Enterprise Edition. You can download Typemock Isolator from the following URL:

    http://www.typemock.com/Downloads.php

    There is only one download. You get the Professional and Enterprise features for 30 days and then, if you don’t pay for a license, Typemock downgrades to the hobbled Community Edition. I am using the full version of Typemock for the purposes of this blog entry.

    After you download and install Typemock, you can use it when building unit tests by adding a reference to Typemock Isolator for .NET 2.0 in your Visual Studio test project. Select the menu option Project, Add Reference and then select the .NET tab and type the letter ‘t’ (see Figure 1). You use the Typemock Isolator for .NET 2.0 reference for both .NET Framework 2.0 and .NET Framework 2.5 applications (Typemock has really good support for .NET Framework 3.5).

    clip_image002

    Figure 1 – Adding a reference to Typemock Isolator

    Mocking an Object

    Let’s start with a simple sample of using Typemock. Imagine that you have the class in Listing 1:

    Listing 1 – MyClass.cs

       1:  using System;
       2:   
       3:  namespace MyProject
       4:  {
       5:      public class MyClass
       6:      {
       7:          public MyClass()
       8:          {
       9:              throw new Exception("Hello from constructor!");
      10:          }
      11:      }
      12:  }

    The class in Listing 1 is a weird class. If you attempt to create an instance of the class, then an exception is thrown. I’m using this weird class because I want to demonstrate that when you use Typemock, you are working with a simulation of a class and not the class itself. We’ll be able to create an instance of the MyClass class in our code without throwing an exception by mocking the class.

    The test in Listing 2 uses Typemock to create an instance of the MyClass class.

    Listing 2 – MyClassTest.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using TypeMock;
       8:  using MyProject;
       9:   
      10:  namespace TestTypeMockTests
      11:  {
      12:   
      13:      [TestClass]
      14:      public class MyClassTest
      15:      {
      16:          [TestMethod]
      17:          public void Constructor_Call_Success()
      18:          {
      19:              // Expectations
      20:              using (RecordExpectations expect = RecorderManager.StartRecording())
      21:              {
      22:                  MyClass cls = new MyClass();
      23:              }
      24:   
      25:              // Reality
      26:              MyClass newClass = new MyClass(); // success
      27:              
      28:              //MyClass newClass2 = new MyClass(); // failure
      29:   
      30:              // Verify
      31:              MockManager.Verify();
      32:          }
      33:   
      34:      }
      35:  }

    Let me explain what is going on in Listing 2. First, notice that I have imported the Typemock namespace as the top of the file. I need this namespace to use the Typemock classes.

    The Constructor_Call_Success() method is used to test the MyClass class. This method tests whether an instance of MyClass can be created. The mock objects are used within this test method.

    When using Typemock, you typically have three sections of code. In the first section, you setup your expectations. In the second section, you test your expectations against reality. In the final section, you verify that expectations and reality match.

    Notice the using block. This block contains the expectations section. Anything that you do inside of this using block doesn’t actually happen. When the instance of MyClass is created, it is not actually created. The purpose of the expectation section is to setup the mock objects and record what you expect to happen to the mock objects. In Listing 2, we are recording our expectation that the MyClass class will be instantiated.

    The next section, the section after the using block, is the reality section. This section contains the actual unit test code. In Listing 2, an instance of MyClass is created. Again, the actual MyClass is not created. Instead, the mock MyClass imposter is created. You setup the mock MyClass in the expectations section.

    An exception is not thrown when you create an instance of MyClass. Since you are working with a mock object instead of the actual object, the normal MyClass constructor code is never executed.

    Finally, you call the MockManager.Verify() method to make sure that reality meets your expectations. In the expectations section, you setup the expectation that an instance of MyClass would be created. If an instance of MyClass was not, in fact, created, then the MockManager.Verify() method would fail and the unit test would fail.

    The reality section in Listing 2 includes one line of code that has been commented out. This line of code creates a second instance of MyClass. If you uncommented this line of code, then the MockManager.Verify() method would fail. It would fail because you setup the expectation, in the expectations section, that the MyClass class would only be instantiated once.

    Mocking a Method Call

    You can mock a method call – either static or instance methods – by following the same procedure described in the previous section. You setup the expectations, execute your test code, and verify that your expectations match the reality generated by your test code.

    For example, Listing 3 contains a slightly modified version of the MyClass class.

    Listing 3 – MyClass.cs (modified with new DoSomething() method)

       1:  using System;
       2:   
       3:  namespace MyProject
       4:  {
       5:      public class MyClass
       6:      {
       7:          public void DoSomething()
       8:          {
       9:              throw new Exception("Hello from DoSomething!");
      10:          }
      11:   
      12:          public MyClass()
      13:          {
      14:              throw new Exception("Hello from constructor!");
      15:          }
      16:      }
      17:  }

    The modified MyClass in Listing 3 includes a new method named DoSomething(). If you call DoSomething(), an exception is thrown. We can mock calling the DoSomething() method with the test in Listing 4.

    Listing 4 – MyClassTest.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using TypeMock;
       8:  using MyProject;
       9:   
      10:  namespace TestTypeMockTests
      11:  {
      12:   
      13:      [TestClass]
      14:      public class MyClassTest
      15:      {
      16:   
      17:          [TestMethod]
      18:          public void DoSomething_Call_Success()
      19:          {
      20:              // Expectations
      21:              using (RecordExpectations expect = RecorderManager.StartRecording())
      22:              {
      23:                  MyClass cls = new MyClass();
      24:                  cls.DoSomething();
      25:              }
      26:   
      27:              // Reality
      28:              MyClass newClass = new MyClass(); 
      29:              newClass.DoSomething(); // success
      30:              // newClass.DoSomething(); // failure
      31:   
      32:              // Verify
      33:              MockManager.Verify();
      34:          }
      35:      }
      36:  }

    When you execute the test in Listing 4, an exception is not thrown, and the test succeeds. The actual DoSomething() method is not called. Instead, the method call is mocked.

    In the expectations section, the expectation is setup that the DoSomething() method will be called once and only once. If the DoSomething() method is not called at all, then the MockManager.Verify() method will fail. Calling the DoSomething() method more than once, also will cause the MockManager.Verify() method to fail.

    Mocking Method Parameters

    You also can mock methods that accept parameters. You can even set expectations about the values that you expect for the parameters. Listing 5 contains a modified version of the MyClass class with a new version of the DoSomething() method that accepts a string and an integer parameter.

    Listing 5 – MyClass.cs (with new DoSomething() method that accepts parameters)

       1:  using System;
       2:   
       3:  namespace MyProject
       4:  {
       5:      public class MyClass
       6:      {
       7:          public void DoSomething(string param1, int param2)
       8:          {
       9:              throw new Exception("Hello from DoSomething!");
      10:          }
      11:   
      12:   
      13:          public MyClass()
      14:          {
      15:              throw new Exception("Hello from constructor!");
      16:          }
      17:      }
      18:  }

    The test in Listing 6 sets up some expectations concerning the parameters. In the expectations section, the DoSomething() method is called twice. After the DoSomething() method is called the second time, the CheckArguments() method is called.

    Listing 6 – MyClassTests.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using TypeMock;
       8:  using MyProject;
       9:   
      10:  namespace TestTypeMockTests
      11:  {
      12:   
      13:      [TestClass]
      14:      public class MyClassTest
      15:      {
      16:   
      17:          [TestMethod]
      18:          public void DoSomething_Call_Success()
      19:          {
      20:              // Expectations
      21:              using (RecordExpectations expect = RecorderManager.StartRecording())
      22:              {
      23:                  MyClass cls = new MyClass();
      24:                  cls.DoSomething("monday", 2);
      25:                  cls.DoSomething("tuesday", 42);
      26:                  expect.CheckArguments();
      27:              }
      28:   
      29:              // Reality
      30:              MyClass newClass = new MyClass();
      31:              newClass.DoSomething("saturday", 16); // any parameters
      32:              newClass.DoSomething("tuesday", 42); // matching parameters
      33:   
      34:              // Verify
      35:              MockManager.Verify();
      36:          }
      37:   
      38:   
      39:   
      40:      }
      41:  }

    Since the CheckArguments() method is not called after the first DoSomething() call, no expectations are setup concerning the parameters. The parameters just act as dummy parameters. Later in the test section, any values can be passed for the parameters.

    Since the CheckArguments() method is called after the second DoSomething() call, expectations are setup concerning these parameters. When the test is performed, the exact values “tuesday” and 42 must be passed to the DoSomething() method.

    In the reality section, the test is passed. The first time the DoSomething() method is called, you can call the method with any parameter values that you feel like. The second time the method is called, you must pass the two parameter values “tuesday” and 42.

    If you want to get really fancy, you can even setup parameter constraints. For example, you can require that a parameter contain a particular substring. Take a look at the documentation installed with Typemock to learn how to create richer parameter constraints.

    Mocking a Return Value

    You also can mock method return values. This is useful when you need to feed a value into the rest of your code to test. For example, the modified version of MyClass in Listing 7 contains a method named GetDBConnectionString(). This method reads the connection string from the web.config file.

    Listing 7 – MyClass.cs (modified with GetDBConnectionString() method)

       1:  using System;
       2:  using System.Configuration;
       3:  using System.Web.Configuration;
       4:   
       5:  namespace MyProject
       6:  {
       7:      public class MyClass
       8:      {
       9:          public string GetDBConnectionString()
      10:          {
      11:              ConnectionStringSettings settings = WebConfigurationManager.ConnectionStrings["con"];
      12:              if (settings == null)
      13:                  throw new ConfigurationErrorsException("Missing connection string con");
      14:              return settings.ConnectionString;
      15:          }
      16:   
      17:      }
      18:  }

    When performing a unit test, you don’t want to read from the configuration file. Reading from a configuration file adds external dependencies to your unit tests. Instead, you should mock the GetDBConnectionString() method and just return a hard-coded value. Listing 8 illustrates how you can do this.

    Listing 8 – MyClassTest.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using TypeMock;
       8:  using MyProject;
       9:   
      10:  namespace TestTypeMockTests
      11:  {
      12:   
      13:      [TestClass]
      14:      public class MyClassTest
      15:      {
      16:   
      17:          [TestMethod]
      18:          public void GetDBConnectionString_Call_ReturnsDSN()
      19:          {
      20:              // Expectations
      21:              using (RecordExpectations expect = RecorderManager.StartRecording())
      22:              {
      23:                  MyClass cls = new MyClass();
      24:                  cls.GetDBConnectionString();
      25:                  expect.Return("DSN=myData");
      26:              }
      27:   
      28:              // Reality
      29:              MyClass newClass = new MyClass();
      30:              string conString = newClass.GetDBConnectionString();
      31:   
      32:              Assert.AreEqual("DSN=myData", conString);
      33:          }
      34:      }
      35:  }

    Notice that the expectations section in Listing 8 includes the following statement:

    expect.Return(“DSN=myData”)

    This statement causes the GetDBConnectionString(), when it is later called in the test section, to return the value “DSN=myData”.

    If you don’t know how many times the GetDBConnectionString() method will be called in your test code, and you want a certain value to be returned whenever the method is called, then you can call the RepeatAlways() method in the expectations section like this:

        
                    MyClass cls = new MyClass();
                    cls.GetDBConnectionString();
                    expect.Return("DSN=myData");
                    expect.RepeatAlways();

    There is one other thing that you should notice about Listing 8. You should notice that MockManager.Verify() is never called. We aren’t interested in verifying that a certain method was called in Listing 8. Instead, we just want to mock a return value so we can carry out some unit test.

    Mocking Interfaces and Abstract Classes

    You also can use Typemock to mock interfaces and abstract classes without actually implementing the interface or abstract class. This feature is important for Test-Driven Development because it allows you to develop your code in a piecemeal fashion. For example, imagine that your code depends on a data access layer that you have not written. If you create an interface for the yet to be created data access layer, you can use Typemock to mock a class that implements the interface. This allows you to delay writing the interface until the future.

    For example, imagine that you have created the following interface:

       1:  using System;
       2:  using System.Collections;
       3:   
       4:  public interface IData
       5:  {
       6:      IEnumerable GetCustomers();
       7:   
       8:  }

    The IData interface has one method named GetCustomers() that, when implemented, should return a list of customers. Here’s a quick sample of how you can mock this interface with Typemock Isolator:

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:  using TypeMock;
       7:   
       8:  namespace TestTypeMockTests
       9:  {
      10:      [TestClass]
      11:      public class InterfaceTest
      12:      {
      13:   
      14:          private ArrayList _fakeCustomers = new ArrayList
      15:              {
      16:                  new {Id=1, Name="Stephen Walther"},
      17:                  new {Id=3, Name="Sue Jones"},
      18:                  new {Id=8, Name="Ruth Walther"}
      19:              };
      20:   
      21:          [TestMethod]
      22:          public void GetCustomers()
      23:          {
      24:              // Create interface stub
      25:              IData data = RecorderManager.CreateMockedObject<IData>();
      26:   
      27:              // Expectations
      28:              using (RecordExpectations expect = RecorderManager.StartRecording())
      29:              {
      30:                  data.GetCustomers();
      31:                  expect.Return(_fakeCustomers);
      32:              }
      33:   
      34:              // Reality
      35:              ArrayList results = (ArrayList)data.GetCustomers();
      36:              Assert.AreEqual(3, results.Count);
      37:          }
      38:   
      39:      }
      40:  }

    The first statement in the GetCustomers() test method is the most important one to notice. The CreateMockedObject() method creates a stub class that implements the IData interface. In the expectations section, this stub class is setup so that it returns a fake list of customers when its GetCustomers() method is called.

    After you create the mock implementation of the interface, you can pretend that you have already done the work of implementing it. Notice that the mock implementation can be used just fine in the reality section of the test.

    Mocking LINQ to SQL Queries

    One of the coolest features of Typemock is its support for mocking LINQ to SQL queries. You can hardcode a particular value that is returned whenever a LINQ to SQL query is performed. For example, the modified MyClassTest class in Listing 9 substitutes a fake static collection of products for the normal database results that would be returned from a LINQ to SQL query.

    Listing 9 – MyClass.cs (with GetProducts() method)

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:   
       7:  using TypeMock;
       8:  using MyProject;
       9:   
      10:  using System.Data.Linq;
      11:   
      12:  namespace TestTypeMockTests
      13:  {
      14:   
      15:      [TestClass]
      16:      public class MyClassTest
      17:      {
      18:   
      19:          private IQueryable _fakeProducts = new List<Product>
      20:              {
      21:                  new Product {Id=1, Name="Steak", Price=12.23m},
      22:                  new Product {Id=3, Name="Cheese", Price=2.00m},
      23:                  new Product {Id=8, Name="Milk", Price=5.39m}
      24:              }.AsQueryable();
      25:   
      26:   
      27:          [TestMethod]
      28:          public void GetProducts_Call_ReturnProducts()
      29:          {
      30:   
      31:              using (RecordExpectations recorder = RecorderManager.StartRecording())
      32:              {
      33:                  ProductsDataContext mockDB = new ProductsDataContext();
      34:                  var mockProducts = mockDB.Products;
      35:                  recorder.ReturnDefaultImplementation();
      36:                  var query = from p in mockProducts select p;
      37:                  recorder.Return(_fakeProducts);
      38:              } 
      39:   
      40:   
      41:              // Test
      42:              ProductsDataContext db = new ProductsDataContext();
      43:              var products = from p in db.Products select p;
      44:   
      45:              // 3 products in all
      46:              Assert.IsTrue(products.Count() == 3); 
      47:              // First product is steak
      48:              var lstProducts = products.ToList();
      49:              Assert.AreEqual(lstProducts[0].Name, "Steak");
      50:          }
      51:   
      52:   
      53:      }
      54:  }

    When you execute the test in Listing 9, the return value of a particular LINQ to SQL query is mocked. When you perform the query from p in mockProducts select p, the contents of the _fakeProducts collection are returned.

    The test section demonstrates that the fake set of products is returned. The count of products is always 3 regardless of the number of products in the database. The name of the first product is always “steak”.

    Mocking a More Realistic Code Sample

    In this final section, I tackle one last sample of mocking with Typemocks. I want to return to the original scenario discussed in the introduction of this blog entry.

    Imagine that you are building an online store. Imagine that the code in Listing 10 represents your business logic layer and the code in Listing 11 represents your data access layer.

    Listing 10 – BLL.cs

       1:  using DAL;
       2:  using System.Collections.Generic;
       3:  using System.Configuration;
       4:  using System.Web.Configuration;
       5:   
       6:   
       7:  namespace BLL
       8:  {
       9:      public class Product
      10:      {
      11:          public int Id { get; set; }
      12:   
      13:          public string Name { get; set; }
      14:   
      15:          public decimal Price { get; set; }
      16:   
      17:          public static List<Product> GetProducts()
      18:          {
      19:              string conString = ConfigHelper.GetDBConnectionString();
      20:              DataProvider dp = new DataProvider(conString);
      21:              return dp.GetProducts();
      22:          }
      23:      }
      24:   
      25:      public class ConfigHelper
      26:      {
      27:          public static string GetDBConnectionString()
      28:          {
      29:              ConnectionStringSettings settings = WebConfigurationManager.ConnectionStrings["con"];
      30:              if (settings == null)
      31:                  throw new ConfigurationErrorsException("Missing connection string con");
      32:              return settings.ConnectionString;
      33:          }
      34:      }
      35:   
      36:  }

    Listing 11 – DAL.cs

       1:  using System.Data;
       2:  using System.Data.SqlClient;
       3:  using System.Collections.Generic;
       4:  using BLL;
       5:   
       6:  namespace DAL
       7:  {
       8:      public class DataProvider
       9:      {
      10:          private string _connectionString;
      11:   
      12:          public DataProvider(string dbConnectionString)
      13:          {
      14:              _connectionString = dbConnectionString;
      15:          }
      16:   
      17:          public List<Product> GetProducts()
      18:          {
      19:              SqlConnection con = new SqlConnection(_connectionString);
      20:              string cmdText = "SELECT Id,Name,Price FROM Products";
      21:              SqlCommand cmd = new SqlCommand(cmdText, con);
      22:              List<Product> results = null;
      23:              using (con)
      24:              {
      25:                  con.Open();
      26:                  SqlDataReader reader = cmd.ExecuteReader();
      27:                  while (reader.Read())
      28:                  {
      29:                      Product product = new Product();
      30:                      product.Id = (int)reader["Id"];
      31:                      product.Name = (string)reader["Name"];
      32:                      product.Price = (decimal)reader["Price"];
      33:                      results.Add(product);
      34:                  }
      35:              }
      36:              return results;
      37:          }
      38:      }
      39:  }

    I’m not claiming that the code in Listing 10 and Listing 11 is well written code. Just imagine that this is legacy code that you are required to maintain.

    Now, one fine day, you are asked to modify the GetProducts() method in Listing 10 so that it includes a tax calculation. You are asked to modify the signature of the method so that it looks like this:

            public static List<Product> GetProducts(decimal tax)
            {
                ... modified code that adds sales tax ...
            }

    Following good Test-Driven Development methodology, before you do anything else, you write a test. This is where you need a Mock Object Framework like Typemock. In order to test the GetProducts() method, you need to mock both the ConfigHelper and DataProvider classes. If you don’t mock these objects, you’ll access your application’s configuration file and the database every time you run your tests.

    The test in Listing 12 contains a test that checks whether the right tax calculation is being performed.

    Listing 12 – ProductTest.cs

       1:  using System;
       2:  using System.Text;
       3:  using System.Collections.Generic;
       4:  using System.Linq;
       5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
       6:  using TypeMock;
       7:   
       8:  using BLL;
       9:  using DAL;
      10:   
      11:  namespace TestTypeMockTests
      12:  {
      13:      [TestClass]
      14:      public class ProductTest
      15:      {
      16:   
      17:   
      18:          private List<Product> _fakeProducts = new List<Product>
      19:              {
      20:                  new Product {Id=1, Name="Steak", Price=12.23m},
      21:                  new Product {Id=3, Name="Cheese", Price=2.00m},
      22:                  new Product {Id=8, Name="Milk", Price=5.39m}
      23:              };
      24:   
      25:          [TestMethod]
      26:          public void GetProducts_Tax_Match()
      27:          {
      28:              // Expectations
      29:              using (RecordExpectations expect = RecorderManager.StartRecording())
      30:              {
      31:                  // Mock ConfigHelper
      32:                  ConfigHelper.GetDBConnectionString();
      33:                  expect.Return("dummy");
      34:                  
      35:                  // Mock DataProvider
      36:                  DataProvider mockDP = new DataProvider("dummy");
      37:                  mockDP.GetProducts();
      38:                  expect.Return(_fakeProducts);
      39:              }
      40:   
      41:              // Reality
      42:              decimal tax = 0.10m;
      43:              decimal price0 = _fakeProducts[0].Price + 
      44:                 (_fakeProducts[0].Price * tax);
      45:              decimal price2 = _fakeProducts[2].Price + 
      46:                 (_fakeProducts[2].Price * tax);
      47:              List<Product> results = Product.GetProducts(tax);
      48:              Assert.AreEqual(price0, results[0].Price);
      49:              Assert.AreEqual(price2, results[2].Price);
      50:          }
      51:   
      52:      }
      53:  }

    In Listing 12, both the ConfigHelper and DataProvider classes are mocked within the expectation section. When the DataProvider.GetProducts() method is called, the static collection of products contained in the _fakeProducts variable are returned.

    In the test section, the GetProducts() method is tested to determine if the correct tax calculation is performed on each product price. First, the correct value for the Price property, taking into account the tax, is calculated for two of the products. Next, the value of these Price properties are compared against the value of the Price properties returned by calling the GetProducts() method. If the property values match, then the test passes.

    The important thing to understand about this test is that the configuration file is never touched and the database is never accessed. By taking advantage of the mock objects, all of the dependencies on external objects have been broken.

    Summary

    In this blog entry, I’ve provided you with a brief introduction to Mock Object Frameworks in general and Typemock Isolator in particular. The goal of this entry was to explain why you should care about Mock Object Frameworks.

    In the first section, I explained the importance of Mock Object Frameworks in the context of Test-Driven Development and ASP.NET MVC. Next, I explained how you could perform basic mocking operations with Typemock Isolator. I provided code samples that illustrate how you can mock instantiating objects, making method calls, and passing method parameters. I also discussed mocking LINQ to SQL queries with Typemock Isolator. Finally, I tackled a more realistic sample of when you would need to mock objects when performing unit tests. You learned how to mock access to external objects such as a configuration file and the database.

  • Book Review: The Art of Unit Testing

    I stumbled across The Art of Unit Testing by Roy Osherove while researching Mock Object frameworks that can be used with ASP.NET MVC. Even though the author is still in the process of writing the book, you can download an early draft of this book at http://www.manning.com/osherove/.

    This is a fantastic book for learning about Mock frameworks such as Rhino Mocks. One of the nicest features of the book is the author’s clearly worded definitions of many terms that you encounter when working with Mock object frameworks. For example, the book contains a valuable section that distinguishes between Stubs and Mocks. He also provides clear explanations of different techniques for performing Dependency Injections and creating Seams.

    The book concentrates on Rhino Mocks. He delves into the gritty details of how and when to use Rhino Mocks to simulate objects. He provides walkthroughs that demonstrate how to use Rhino Mocks to test whether expected object methods have been called, expected object properties have been set, and expected object events have been raised.

    The book also has a useful section that compares the different Mock Object frameworks. He compares NUnit.Mocks, NMock, NMock2, Type Mock, and Rhino Mocks (This section convinced me that I need to check out Type Mock).

    Even though the book is not finished, I already found it to be extremely useful. As far as I know, it currently is the only book that compares different Mock Object frameworks available in the .NET universe.

  • Using ASP.NET AJAX with ASP.NET MVC

    Yes, you can use ASP.NET AJAX with ASP.NET MVC. Several people have asked me recently how you can use ASP.NET AJAX in an ASP.NET MVC view. In this blog entry, I’m going to explain the problem and the solution.

    The Problem

    Normally, if you want to use ASP.NET AJAX in an ASP.NET page, you add a ScriptManager control to the page. The ScriptManager control requires a server-side form control. Therefore, in order to use a ScriptManager control, you must include a server-side form control in a page.

    Here’s the problem. You should not include a server-side form control in an ASP.NET MVC view. Why not? Using a server-side form control violates the spirit of ASP.NET MVC since adding a form control forces you back into the Web Forms page model that forces you to use postbacks and view state.

    Therefore, many people have concluded, ASP.NET AJAX is not compatible with ASP.NET MVC.

    The Solution

    The solution is simple, don’t use the ScriptManager control. Instead, just include the Microsoft AJAX Library with a standard <script src=”MicrosoftAjax.js”></script> tag.

    You can download the standalone version of the Microsoft AJAX Library from the following location:

    http://www.asp.net/ajax/downloads/

    The download includes multiple versions of the ASP.NET AJAX Library. The two most important scripts are named MicrosoftAjax.js and MicrosoftAjax.debug.js (the download also includes localized versions of the Microsoft AJAX Library). The MicrosoftAjax.js script is the production version of the library and the MicrosoftAjax.debug.js script is the debug version of the library.

    You can copy both the MicrosoftAjax.js and MicrosoftAjax.debug.js scripts directly into an ASP.NET MVC Web Application Project. A good location to add these scripts within an ASP.NET MVC application is the Content folder. After you add the scripts to your project, you can reference either the production or the debug version of the scripts within your views (or a master page).

    For example, the view in Listing 1 uses the Microsoft AJAX Library to wire-up a button click handler.

    Listing 1 – TestAjax.aspx

       1:  <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestAjax.aspx.cs" Inherits="FirstMVCApp.Views.Test.TestAjax" %>
       2:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       3:  <html xmlns="http://www.w3.org/1999/xhtml" >
       4:  <head runat="server">
       5:      <title>Test Ajax</title>
       6:      <script type="text/javascript" src="../../Content/MicrosoftAjax.debug.js"></script>
       7:      <script type="text/javascript">
       8:      
       9:          function pageLoad()
      10:          {
      11:              $addHandler( $get("btn"), "click", doSomething);
      12:          }
      13:          
      14:          function doSomething()
      15:          {
      16:              alert("Button clicked!");
      17:          }
      18:      
      19:      </script>
      20:  </head>
      21:  <body>
      22:      <div>
      23:   
      24:      <input id="btn" type="button" value="Click Here!" />
      25:   
      26:      </div>
      27:  </body>
      28:  </html>

    The doSomething() JavaScript method is wired to the btn Click event within the pageLoad method. When you click the button, the alert “Button clicked!” is displayed (see Figure 1).

    clip_image002

    Figure 1 – Using the Microsoft AJAX Library in an MVC View

    The page in Listing 1 uses the debug version of the Microsoft AJAX Library. The debug version of the library contains extra code that checks, for example, whether you are passing the right parameters to a method. In production, you should switch from the MicrosoftAjax.debug.js file to the MicrosoftAjax.js file. The MicrosoftAjax.js file has been minimized and it has been stripped of any debug code.

    To make it easy to switch back and forth between the debug and production version of the Microsoft AJAX Library, you might want to add the script reference to a master page instead of each individual page.

    What about Service References?

    One of the nice things about using the ScriptManager control in a normal ASP.NET page is that you can use the control to easily add a reference to either a WCF or an ASMX Web Service. For example, if you want to call the MyService Web Service from your client-side JavaScript, then you can add a service reference like this:

        <asp:ScriptManager ID="sm1" runat="server">
        <Services>
            <asp:ServiceReference Path="/Services/MyService.asmx" />
        </Services>
        </asp:ScriptManager>

    Since you should not use a ScriptManager control in an MVC view, you can’t add a service reference to a view in the same way. So, how do you call a web service?

    The view in Listing 2 demonstrates how you can call the MyService.asmx service from an MVC view:

    Listing 2 – TestService.aspx

       1:  <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestService.aspx.cs" Inherits="FirstMVCApp.Views.Test.TestService" %>
       2:   
       3:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       4:   
       5:  <html xmlns="http://www.w3.org/1999/xhtml" >
       6:  <head runat="server">
       7:      <title>Test Service</title>
       8:      <script type="text/javascript" src="../../Content/MicrosoftAjax.debug.js"></script>
       9:      <script type="text/javascript">
      10:      
      11:          function pageLoad()
      12:          {
      13:              Sys.Net.WebServiceProxy.invoke
      14:              (
      15:                  "../../Services/MyService.asmx", 
      16:                  "Select", 
      17:                  false, 
      18:                  null, 
      19:                  success, 
      20:                  fail
      21:              );
      22:          }
      23:      
      24:      
      25:          function success(results)
      26:          {
      27:              alert(results)
      28:          }
      29:      
      30:          function fail(err)
      31:          {
      32:              alert( "ERROR: " + err.get_message() );
      33:          }
      34:      
      35:      </script>
      36:  </head>
      37:  <body>
      38:      <div>
      39:      
      40:      </div>
      41:  </body>
      42:  </html>

    Notice that the Sys.Net.WebServiceProxy.invoke() method is called in the pageLoad() function. This method invokes the Web Service. The invoke() method accepts the following parameters:

    · servicePath – The path to the WCF or ASMX Web Service

    · methodName – The name of the web method to call

    · useGet – Determines whether to use GET or POST (GET is disabled by default)

    · params – An object literal that represents a list of parameters to pass to the web method

    · onSuccess – The JavaScript function to call if the web service call is successful

    · onFailure – The JavaScript function to call if the web service call is not successful

    · userContext – Arbitrary data passed back to the client

    · timeout – The amount of time before the web service all times out

    You can use the page in Listing 2 with the ASMX Web Service in Listing 3.

    Listing 3 – MyService.asmx

       1:  using System;
       2:  using System.Collections;
       3:  using System.ComponentModel;
       4:  using System.Data;
       5:  using System.Linq;
       6:  using System.Web;
       7:  using System.Web.Services;
       8:  using System.Web.Services.Protocols;
       9:  using System.Xml.Linq;
      10:  using System.Collections.Generic;
      11:   
      12:  namespace FirstMVCApp.Services
      13:  {
      14:      [WebService(Namespace = "http://tempuri.org/")]
      15:      [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
      16:      [ToolboxItem(false)]
      17:      [System.Web.Script.Services.ScriptService]
      18:      public class MyService : System.Web.Services.WebService
      19:      {
      20:   
      21:          [WebMethod]
      22:          public string Select()
      23:          {
      24:              var quotes = new List<string>()
      25:              {
      26:                  "A stitch in time saves nine",
      27:                  "Man is the measure of all things",
      28:                  "Look before you leap"
      29:              };
      30:   
      31:              Random rnd = new Random();
      32:              return quotes[rnd.Next(quotes.Count)];
      33:          }
      34:      }
      35:  }

    The Web Service in Listing 3 returns a random quotation. Notice that the Web Service includes a [ScriptService] attribute. You must include this attribute when you want to be able to call a Web Service from client-side script.

    When you request the page in Listing 2, the random quotation is displayed in an alert box (see Figure 2).

    clip_image004

    Figure 2 – Calling a Web Service from an MVC View

    What about the UpdatePanel Control?

    The UpdatePanel, when used in a normal ASP.NET page, enables you to update the content of part of a page without updating the content of the entire page (it enables you to avoid a full postback by performing a sneaky postback). How do you use the UpdatePanel control in an MVC view?

    The UpdatePanel cannot be used in a page that does not contain a ScriptManager control. Therefore, since the ScriptManager control depends on the server-side form control and you should not use a server-side form control in an MVC view, the UpdatePanel cannot be used in an MVC view.

    But don’t worry, you have another option. You don’t need to use the UpdatePanel control to perform a partial view update using the Microsoft AJAX Library. Instead, you can use the Sys.Net.WebRequest object.

    For example, the view in Listing 4 contains two buttons. When you click the first button, the contents of the Content1.htm file are pasted into a DIV tag named up1. When you click the second button, the contents of the Content2.htm file are pasted into the DIV tag. The page performs a partial update using the Microsoft AJAX Library support for making AJAX calls.

    Listing 4 – TestUpdatePanel.aspx

       1:  <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestUpdatePanel.aspx.cs" Inherits="FirstMVCApp.Views.Test.TestUpdatePanel" %>
       2:   
       3:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       4:   
       5:  <html xmlns="http://www.w3.org/1999/xhtml" >
       6:  <head runat="server">
       7:      <title>Test UpdatePanel</title>
       8:      <script type="text/javascript" src="../../Content/MicrosoftAjax.debug.js"></script>
       9:      <script type="text/javascript">
      10:      
      11:          function pageLoad()
      12:          {
      13:              $addHandler($get("btn1"), "click", 
      14:                  function() {getContent("../../Content/Content1.htm"); } );
      15:              $addHandler($get("btn2"), "click", 
      16:                  function() {getContent("../../Content/Content2.htm"); } );        
      17:          }
      18:   
      19:          function getContent(url)
      20:          {
      21:              var request = new Sys.Net.WebRequest();
      22:              request.set_url(url);
      23:              request.set_httpVerb("GET");
      24:              request.add_completed(updatePage);
      25:              request.invoke();        
      26:          }
      27:          
      28:          function updatePage(executor, eventArgs)
      29:          {
      30:              if(executor.get_responseAvailable()) 
      31:              {
      32:                  $get("up1").innerHTML = executor.get_responseData();
      33:              }
      34:              else
      35:              {
      36:                  if (executor.get_timedOut())
      37:                      alert("Timed Out");
      38:                  else if (executor.get_aborted())
      39:                      alert("Aborted");
      40:              }
      41:          }
      42:          
      43:      </script>
      44:  </head>
      45:  <body>
      46:      <div>
      47:          
      48:          <input 
      49:              id="btn1" 
      50:              type="button" 
      51:              value="Content 1" />
      52:          
      53:          <input 
      54:              id="btn2" 
      55:              type="button" 
      56:              value="Content 2" />
      57:          
      58:          <div id="up1"></div>
      59:      
      60:      </div>
      61:  </body>
      62:  </html>

    In Listing 4, the pageLoad() method is used to wire-up the two buttons in the body of the page to the getContent() JavaScript function. When you click the first button, the URL "../../Content/Content1.htm" is passed to the getContent() method. When you click the second button, the URL "../../Content/Content2.htm" is passed to the getContent() method.

    The getContent() method performs all of the work. In this method, a WebRequest object is created. Two properties of this object are set: the URL and the HTTP Verb. A handler is setup for the WebRequest so that when the WebRequest object is invoked, the updatePage() method is called.

    The updatePage() method simply updates the innerHTML of a DIV tag named up1. Updating the innerHTML of an element updates the content of the page dynamically.

    The contents of Content1.htm are contained in Listing 5 and the contents of Content2.htm are contained in Listing 6.

    Listing 5 – Content1.htm

       1:  <b>Hello from Content1 !!!</b>

    Listing 6 – Content2.htm

       1:  <b>Hello from Content2 !!!</b>

    Neither Content1.htm nor Content2.htm can contain server-side controls. That’s okay in the MVC universe since we are trying to avoid (heavy weight) server-side controls anyway.

    Conclusion

    The purpose of this blog entry was to explain how to use the Microsoft AJAX Library in an MVC Web Application. I explained how to add script references, add service references, and perform partial page updates without using the ScriptManager or UpdatePanel controls. Microsoft ASP.NET AJAX works just fine with Microsoft ASP.NET MVC.

  • ASP.NET AJAX In-Depth: Application Events

    The goal of this blog entry is simple: I want to understand everything about ASP.NET AJAX Application events. I want to know how application events work under the covers by performing a close examination of the Microsoft AJAX Library source code for the Application object.

    The Application object (Sys.Application) supports three application lifecycle events:

    · init – You use this event to initialize client components, controls, and behaviors

    · load – You use this event to kick-off your application’s client-side code

    · unload – You use this event to free up resources used by your application

    There are two more lifecycle events that are not really events. If your application includes a pageLoad() function, then this function is called immediately after the Application.load event. If your application includes a pageUnload() function, then this function is called immediately before the Application.unload event.

    The page in Listing 1 illustrates when each of these events happen:

    Listing 1 – ApplicationEvents.aspx

       1:  <%@ Page Language="C#" %>
       2:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       3:  <html xmlns="http://www.w3.org/1999/xhtml">
       4:  <head runat="server">
       5:      <title>Application Events</title>
       6:  </head>
       7:  <body>
       8:      <form id="form1" runat="server">
       9:      <div>
      10:          <asp:ScriptManager ID="ScriptManager1" runat="server" />
      11:      </div>
      12:      </form>
      13:   
      14:      <script type="text/javascript">
      15:      
      16:        // handle Application init
      17:        Sys.Application.add_init( function() { alert("init!") } );
      18:        
      19:        // handle Application load
      20:        Sys.Application.add_load( function() { alert("load!") } );
      21:        
      22:        // show pageLoad()
      23:        function pageLoad() { alert("pageLoad!"); }
      24:   
      25:        // show pageLoad()
      26:        function pageUnload() { alert("pageUnload!"); }
      27:   
      28:        // handle Application unload
      29:        Sys.Application.add_unload( function() { alert("unload!") } );
      30:      
      31:      </script>
      32:   
      33:   
      34:   
      35:  </body>
      36:  </html>

    Notice that the JavaScript script in Listing 1 is placed right before the closing HTML BODY tag. If your JavaScript code refers to objects from the Microsoft AJAX Library, then you must place your script after the Microsoft AJAX Library has been loaded. In Listing 1, the Microsoft AJAX Library is loaded by the server-side ScriptManager control.

    When you request the page in Listing 1, alerts are displayed in sequence for the Application.init, Application.load events followed by the pageLoad method call. If you refresh/reload the page, you navigate to a new page, or you close your browser, the pageUnload function is called and the Application.unload event is raised.

    How Application Events are Raised

    So let’s look at the Application events in more detail by examining the Microsoft AJAX Library source code.

    The Microsoft AJAX Library defines a private class named Sys._Application. This class defines the nature of an application for the ASP.NET AJAX Framework. A single instance of this class is created for an application automatically with the following line of code:

    Sys.Application = new Sys._Application();

    The Application.load and Application.unload events are wired-up in the constructor function for the _Application object. The constructor function includes the following two lines of code:

    Sys.UI.DomEvent.addHandler(window, "load", this._loadHandlerDelegate);
    
    Sys.UI.DomEvent.addHandler(window, "unload", this._unloadHandlerDelegate);

    The first line of code wires-up the Application.load event to the browser window.load event and the second line of code wires-up the Application.unload event to the browser window.unload event. So browser events drive ASP.NET AJAX Application events.

    When the window.load event is raised, the ASP.NET AJAX _loadHandlerDelegate() method is called. This method calls the _Application.initialize() method contained in Listing 2.

    Listing 2 – MicrosoftAjax.debug.js _Application.initialize

        function Sys$_Application$initialize() {
            if(!this._initialized && !this._initializing) {
                this._initializing = true;
                window.setTimeout(Function.createDelegate(this, this._doInitialize), 0);
            }
        }

    The initialize() method in Listing 2 checks whether the Application has already been initialized, or is currently in the process of being initialized, by checking the private-by-convention _initialized and _initializing properties. Next, the _doInitialize() method is called. Why is the _doInitialize() method called using window.setTimeout? Presumably to work around a browser incompatibility issue (I don’t know anything about the nature of this incompatibility issue).

    The important thing to notice here is that an ASP.NET AJAX application can only be initialized once. If you call initialize() multiple times, any call but the first call is ignored.

    The _doInitialize() method is contained in Listing 3.

    Listing 3 – MicrosoftAjax.debug.js _Application._doInitialize

        function Sys$_Application$_doInitialize() {
            Sys._Application.callBaseMethod(this, 'initialize');
            var handler = this.get_events().getHandler("init");
            if (handler) {
                this.beginCreateComponents();
                handler(this, Sys.EventArgs.Empty);
                this.endCreateComponents();
            }
            this.raiseLoad();
            this._initializing = false;
        }

    In the context of this blog entry, the _doInitialize() method is the most important method. This method performs the following actions:

    1. Raises the Application init event

    2. Raises the Application load event

    3. Marks the Application as initialized

    Let’s look at step 2 in more detail. The Application load event is raised by calling the raiseLoad() method. The raiseLoad() method is contained in Listing 4.

    Listing 4 – MicrosoftAjax.debug.js _Application.raiseLoad

        function Sys$_Application$raiseLoad() {
            var h = this.get_events().getHandler("load");
            var args = new Sys.ApplicationLoadEventArgs(Array.clone(this._createdComponents), !this._initializing);
            if (h) {
                h(this, args);
            }
            if (window.pageLoad) {
                window.pageLoad(this, args);
            }
            this._createdComponents = [];
        }

    The raiseLoad() method in Listing 4 raises the Application.load event and calls the pageLoad() function (if it exists) contained in your page. This method creates a new ApplicationLoadEventArgs object and passes this object to any Application.load handlers and the pageLoad function. The ApplicationLoadEventArgs object has two properties:

    · Components – This property returns an array of all of the components (including all controls and behaviors) created during the Application.init event

    · isPartialLoad -- This property indicates whether the Application load event is happening during Application initialization or whether the Application load event was raised by calling Application.raiseLoad() after the Application was already initialized.

    The second parameter requires explanation. Typically, the Application.load event is raised only once. However, if you have an UpdatePanel in a page, then the Application.load event is raised whenever an UpdatePanel updates. For example, the page in Listing 5 contains an UpdatePanel that updates its content every 5 seconds:

    Listing 5 – ShowUpdatePanel.aspx

       1:  <%@ Page Language="C#" %>
       2:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       3:  <html xmlns="http://www.w3.org/1999/xhtml">
       4:  <head runat="server">
       5:      <title>Show UpdatePanel</title>
       6:      <script type="text/javascript">
       7:      
       8:        function pageLoad(source, args) 
       9:        {
      10:          alert( "isPartialLoad=" + args.get_isPartialLoad() );
      11:        }
      12:      
      13:      </script>
      14:  </head>
      15:  <body>
      16:      <form id="form1" runat="server">
      17:      <div>
      18:          <asp:ScriptManager ID="ScriptManager1" runat="server" />
      19:   
      20:          <asp:UpdatePanel ID="up1" runat="server">
      21:          <ContentTemplate>
      22:          
      23:              <asp:Timer Interval="5000" runat="server" />
      24:          
      25:              <%= DateTime.Now %>
      26:              
      27:          </ContentTemplate>
      28:          </asp:UpdatePanel>
      29:   
      30:      </div>
      31:      </form>
      32:  </body>
      33:  </html>

    The page in Listing 5 includes a pageLoad() method that displays the value of the isPartialLoad property in a browser alert box. When you first request the page, the pageLoad() method is called during Application initialization and the pageLoad() method displays the value false for the isPartialLoad property. However, the page contains an UpdatePanel that refreshes its content every 5 seconds (there is a Timer control in the UpdatePanel that causes the UpdatePanel to refresh). Every 5 seconds, the pageLoad() method is called again and displays the value true.

    So that’s it for the Application initialization process. Let’s turn now to an examination of what happens when an ASP.NET AJAX Application unloads.

    Remember that the Application constructor function includes the following line of code that wires-up the ASP.NET AJAX Application.unload event to the browser window.unload event:

    Sys.UI.DomEvent.addHandler(window, "unload", this._unloadHandlerDelegate);

    When the window.unload event is raised (when you navigate to a new page, close the browser, or hit refresh/reload), the _unloadhandlerDelegate() method is called. This method, in turn, calls the Application.dispose() method. The dispose() method is contained in Listing 6.

    Listing 6 – MicrosoftAjax.debug.js _Application.dispose

        function Sys$_Application$dispose() {
            if (!this._disposing) {
                this._disposing = true;
                if (window.pageUnload) {
                    window.pageUnload(this, Sys.EventArgs.Empty);
                }
                var unloadHandler = this.get_events().getHandler("unload");
                if (unloadHandler) {
                    unloadHandler(this, Sys.EventArgs.Empty);
                }
                var disposableObjects = Array.clone(this._disposableObjects);
                for (var i = 0, l = disposableObjects.length; i < l; i++) {
                    disposableObjects[i].dispose();
                }
                Array.clear(this._disposableObjects);
                Sys.UI.DomEvent.removeHandler(window, "unload", this._unloadHandlerDelegate);
                if(this._loadHandlerDelegate) {
                    Sys.UI.DomEvent.removeHandler(window, "load", this._loadHandlerDelegate);
                    this._loadHandlerDelegate = null;
                }
                var sl = Sys._ScriptLoader.getInstance();
                if(sl) {
                    sl.dispose();
                }
                Sys._Application.callBaseMethod(this, 'dispose');
            }
        }

    The dispose() method in Listing 6 does four important things:

    1. If you have created a pageUnload() function in your application, that function is called

    2. It calls dispose() on any object that have you have registered with the application.

    3. It raises the Application unload event.

    4. It disposes the ScriptLoader instance.

    The second step disposes any objects registered with your application. All ASP.NET AJAX components (including controls and behaviors) are registered automatically with the Application object when the component is created. The component is registered with the Application in the base Sys.Component constructor function. This step is very important to prevent browser memory leaks. Microsoft Internet Explorer (at least the 6.0 version) is very bad at cleaning up after itself.

    Why window.load is Bad

    The last subject that we need to examine in this blog entry concerns the window.load event. The ASP.NET AJAX Application initialization process is kicked off by this browser event. However, this is bad. The window.load event happens too slowly.

    The problem is that the window.load event is not raised until all images are loaded into a browser page. You typically don’t want to wait until all images are loaded before you start to execute your application logic. You want to initialize your application immediately after all of the DOM elements in your page have been parsed.

    This problem with the window.load event was brought to everyone’s attention by Dean Edwards (see http://dean.edwards.name/weblog/2006/06/again/). He proposes a complex solution.

    Both Firefox and Opera support a DOMContentLoaded event. This browser event is raised after all of the DOM elements in a page have been parsed and before the window.load event. Unfortunately, Microsoft Internet Explorer does not support the DOMContentLoaded event.

    Internet Explorer does support a special attribute that can be used with the HTML SCRIPT tag called the DEFER attribute. When DEFER=”true”, an external JavaScript script is not loaded until after all the DOM elements in a page have been parsed. Therefore, you can use the DEFER attribute (in a hacky way) to simulate the DOMContentLoaded event.

    Dean Edwards (and friends) recommend the script in Listing 7 for kicking off your application.

    Listing 7 – Cross-Browser DOMContentLoaded

       1:  // Dean Edwards/Matthias Miller/John Resig
       2:   
       3:  function init() {
       4:      // quit if this function has already been called
       5:      if (arguments.callee.done) return;
       6:   
       7:      // flag this function so we don't do the same thing twice
       8:      arguments.callee.done = true;
       9:   
      10:      // kill the timer
      11:      if (_timer) clearInterval(_timer);
      12:   
      13:      // do stuff
      14:  };
      15:   
      16:  /* for Mozilla/Opera9 */
      17:  if (document.addEventListener) {
      18:      document.addEventListener("DOMContentLoaded", init, false);
      19:  }
      20:   
      21:  /* for Internet Explorer */
      22:  /*@cc_on @*/
      23:  /*@if (@_win32)
      24:      document.write("&lt;script id=__ie_onload defer src=javascript:void(0)&gt;&lt;\/script&gt;");
      25:      var script = document.getElementById("__ie_onload");
      26:      script.onreadystatechange = function() {
      27:          if (this.readyState == "complete") {
      28:              init(); // call the onload handler
      29:          }
      30:      };
      31:  /*@end @*/
      32:   
      33:  /* for Safari */
      34:  if (/WebKit/i.test(navigator.userAgent)) { // sniff
      35:      var _timer = setInterval(function() {
      36:          if (/loaded|complete/.test(document.readyState)) {
      37:              init(); // call the onload handler
      38:          }
      39:      }, 10);
      40:  }
      41:   
      42:  /* for other browsers */
      43:  window.onload = init;

    Dean Edwards has a nice sample page that you can use to try out the script in Listing 7 at http://dean.edwards.name/my/busted3.html. The page loads an image really slowly so you can detect the difference between the DOMContentLoaded and window.load events.

    The ASP.NET AJAX framework takes a different approach to handling the window.load problem. If you use the ScriptManager control to load the Microsoft AJAX Library, then the ScriptManager control injects the following script right before the page’s closing </BODY> tag:

    <script type="text/javascript">
    //<![CDATA[
    Sys.Application.initialize();
    //]]>
    </script>

    Since this script appears after (almost) all of the HTML content contained in the page, you know that when this script executes the DOM is (almost) ready. This is a really simple solution to the window.load problem.

    This solution causes the Application.initialize() method to be called twice. The initialize() method is called in the page itself and it is called a second time when the window.load event is raised. That’s okay since the initialize() method ensures that the Application.init event is raised only once. After the initialize() method is first called, a field named _initialized is set to the value true. The second call to initialize() is ignored.

    If you are not using the ScriptManager control to add the Microsoft AJAX Library to your pages, then you must be careful to do something similar. Personally, I like using the standalone Microsoft AJAX Library because I am interested in building “pure” client-side applications (You can download the standalone Microsoft AJAX Library from http://msdn2.microsoft.com/en-us/asp.net/bb944808.aspx). The page in Listing 8 illustrates one approach to handling the window.load problem with the standalone library.

    Listing 8 – LoadStandAlone.aspx

       1:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       2:  <html xmlns="http://www.w3.org/1999/xhtml">
       3:  <head runat="server">
       4:      <title>Load Standalone</title>
       5:  </head>
       6:  <body>
       7:      <div>
       8:   
       9:      <strong>The DOM Content</strong>
      10:      
      11:      </div>
      12:      
      13:      <script type="text/javascript" src="Microsoft/MicrosoftAjax.debug.js"></script>
      14:      <script type="text/javascript" src="Application.js"></script>
      15:      
      16:  </body>
      17:  </html>

    The standalone Microsoft AJAX Library contains both a MicrosoftAjax.js and MicrosoftAjax.debug.js file. You should use the former file when an application is in production and the latter file when debugging an application (The ScriptManager control switches between these two files automatically depending on the value of the ScriptManager ScriptMode attribute and your application’s debug settings).

    In Listing 8, a <SCRIPT> tag is used to load the debug version of the Microsoft AJAX Library. I’ve copied the MicrosoftAjax.debug.js file into a folder contained in my website named Microsoft. Furthermore, I’ve added a second <SCRIPT> tag to load my custom JavaScript code for my application. My application code is contained in a file named Application.js. The contents of this file are contained in Listing 9.

    Listing 9 – Application.js

       1:  /// <reference name="MicrosoftAjax.js"/>
       2:  Sys.Application.initialize();
       3:   
       4:  Sys.Application.add_load( applicationLoad );
       5:   
       6:  function applicationLoad()
       7:  {
       8:      alert("Ready before the images!");
       9:  }

    Notice that the first line of code in Listing 9 is a call to the Application.initialize() method. This call causes the ASP.NET Application to initialize before the window.load event so your AJAX application can start executing before all of the images in your page are loaded.

    Summary

    In this blog entry, I’ve examined the ASP.NET AJAX Application events in detail. There are two main things that need to be emphasized from the discussion above.

    First, the Application load event is raised over and over again when using the UpdatePanel. You should be careful about the code that you add to a pageLoad() function or a Application.load event handler since the code might get executed multiple times.

    Second, make sure that you initialize your Application as quickly as possible. By default, an ASP.NET AJAX Application won’t initialize until window.load. If you are not using the ScriptManager control, make sure that you initialize your Application earlier.

  • ASP.NET AJAX In-Depth: Object Inheritance

    The goal of the blog entry is simple: I want to understand everything happening under the covers when you take advantage of ASP.NET AJAX inheritance. So, let’s start with a simple code sample:

    Listing 1 – AjaxInheritance.aspx

       1:  <script type="text/javascript">
       2:   
       3:  function BaseControl()
       4:  {
       5:      this._propA = "BaseControl propA";
       6:      this._propB = "BaseControl propB";
       7:  }
       8:   
       9:  BaseControl.prototype =
      10:  {
      11:      get_propA : function() {return this._propA;},
      12:      set_propA : function(value) {this._propA = value; },
      13:   
      14:      get_propB : function() {return this._propB; },
      15:      set_propB : function(value) {this._propB = value; }
      16:  }
      17:   
      18:  BaseControl.registerClass("BaseControl");
      19:   
      20:   
      21:  function TreeViewControl()
      22:  {
      23:      TreeViewControl.initializeBase(this);
      24:      this._propA = "TreeViewControl propA";
      25:  }
      26:   
      27:  TreeViewControl.prototype =
      28:  {
      29:      get_propA : function() {return this._propA;},
      30:      set_propA : function(value) {this._propA = value; }
      31:  }
      32:   
      33:  TreeViewControl.registerClass("TreeViewControl", BaseControl);
      34:   
      35:  var treeView1 = new TreeViewControl();
      36:   
      37:  alert( treeView1.get_propA() ); // displays "TreeViewControl propA"
      38:  alert( treeView1.get_propB() ); // displays "BaseControl propB"
      39:   
      40:      
      41:  </script>

    The JavaScript code in Listing 1 defines two objects named BaseControl and TreeViewControl. These objects might represent user interface controls that are displayed in a web page. The TreeViewControl inherits from the BaseControl object.

    First, the BaseControl object is defined with a constructor function named BaseControl. The constructor function initializes two fields named _propA and _propB. Next, get and set accessor methods are added to the BaseControl object’s prototype. These methods expose the private _propA and _propB fields as public properties. Finally, the BaseControl object is registered as a class by calling the ASP.NET AJAX registerClass() method. We’ll be discussing what this method call does in detail in a moment.

    Second, a new object named TreeViewControl is defined. Notice that the TreeViewControl constructor function includes a call to an ASP.NET AJAX method named initializeBase(). We also need to discuss what is going on with this method in a moment.

    Like the BaseControl, the TreeViewControl is registered as a class by calling the registerClass() method. However, the TreeViewControl class is registered as inheriting from the BaseControl class. The second parameter passed to the registerClass() method enables you to specify a base class.

    Finally, an instance of the TreeViewControl is created named treeView1. The get_propA() and get_propB() methods of the object are called and the results of these method calls are displayed with alert boxes in the browser.

    Understanding the registerClass() Method

    The first ASP.NET AJAX method that we need to examine in detail is the registerClass() method. This method accepts the following three parameters:

    · typeName – The name of the class being registered

    · baseType – (optional) The base class for the class being registered

    · interfaceTypes – (optional) The array of interfaces that the class being registered implements

    You can view the entire source code for the registerClass() method by examining the MicrosoftAjax.debug.js file included in the standalone Microsoft AJAX Library. You can download the standalone library from http://msdn2.microsoft.com/en-us/asp.net/bb944808.aspx.

    I’ve stripped the validation code and the code related to working with interfaces from the registerClass() method and I’ve included the remaining source code in Listing 2.

    Listing 2 – MicrosoftAjax.debug.js registerClass() method

       1:  Type.prototype.registerClass = function(typeName, baseType, interfaceTypes) {
       2:   
       3:      var parsedName;
       4:      try {
       5:          parsedName = eval(typeName);
       6:      }
       7:      catch(e) {
       8:          throw Error.argument('typeName', Sys.Res.argumentTypeName);
       9:      }
      10:      if (parsedName !== this) throw Error.argument('typeName', Sys.Res.badTypeName);
      11:      if (Sys.__registeredTypes[typeName]) throw Error.invalidOperation(String.format(Sys.Res.typeRegisteredTwice, typeName));
      12:      if (baseType && !baseType.__class) throw Error.argument('baseType', Sys.Res.baseNotAClass);
      13:      this.prototype.constructor = this;
      14:      this.__typeName = typeName;
      15:      this.__class = true;
      16:      if (baseType) {
      17:          this.__baseType = baseType;
      18:          this.__basePrototypePending = true;
      19:      }
      20:      Sys.__upperCaseTypes[typeName.toUpperCase()] = this;
      21:   
      22:      Sys.__registeredTypes[typeName] = true;
      23:      return this;
      24:  }

    The first thing that you should notice about the code in Listing 2 is that the registerClass() method is a method of the Type object (it is defined on the Type prototype). What is the Type object? The Type object is an alias for the JavaScript Function object. The Microsoft AJAX Library creates this alias with the following line of code:

    window.Type = Function;

    Therefore, you can call the registerClass() method on any function. Typically, you would call registerClass() method on a function that acts as an object constructor.

    Let’s go through the source code for the registerClass() method in Listing 2 step-by-step starting with the following code:

       1:  var parsedName;
       2:      try {
       3:          parsedName = eval(typeName);
       4:      }
       5:      catch(e) {
       6:          throw Error.argument('typeName', Sys.Res.argumentTypeName);
       7:      }
       8:      if (parsedName !== this) throw Error.argument('typeName', Sys.Res.badTypeName);

    When you call the registerClass() method, the first parameter is a string that corresponds to the current function’s name. You call the registerClass() method for a class named TreeViewControl like this:

    TreeViewControl.registerClass(“TreeViewControl”);

    This seems redundant. Why do you need to refer to TreeViewControl twice: once as an object and once as a string? I assume that the goal was to get a string representation of the function name. The code above checks whether evaluating the string name equals the actual function. One way to avoid this redundancy would be to extract the name of the function by calling toString() on the function and matching the function name like this:

    this.toString().match(/( \w+)/)[0] 

    This line of code returns the name of the object that the current method is being called upon. Presumably, this approach was not used for performance reasons.

    The next block of code for the registerClass() method looks like this:

       1: if (Sys.__registeredTypes[typeName]) throw Error.invalidOperation(String.format(Sys.Res.typeRegisteredTwice, typeName));
       2: if (baseType && !baseType.__class) throw Error.argument('baseType', Sys.Res.baseNotAClass);

    The first line prevents you from registering two classes with the same class name. The second line validates whether or not the baseType parameter represents a class.

    The next line of code looks like this:

        this.prototype.constructor = this;

    This line of code is interesting. It fixes a problem with the constructor property in JavaScript illustrated with the code in Listing 3:

    Listing 3 – BadConstructor.js

       1:      <script type="text/javascript">
       2:   
       3:      // Bad Constructor
       4:      function A() {}
       5:      function B() {}
       6:      
       7:      B.prototype = new A();
       8:      
       9:      var x = new B();
      10:      alert( x.constructor ); // Returns A
      11:   
      12:   
      13:      // Good Constructor
      14:      function A() {}
      15:      function B() {}
      16:      
      17:      B.prototype = new A();
      18:      B.prototype.constructor = B; // fix constructor
      19:      
      20:      var x = new B();
      21:      alert( x.constructor ); // Returns B
      22:   
      23:      
      24:      </script>

    The constructor function should return the name of the function used to construct the current object. Unfortunately, when there is a prototype chain, the constructor property returns the wrong constructor function. It returns the name of the function used to construct the top object in the prototype chain.

    When x.constructor is first called in Listing 3, the property returns the wrong value. When the x.constructor method is called later in the code (after fixing the constructor property), the x.constructor property returns the correct value.

    Here’s the next block of code from the registerClass() method:

       1:      this.__typeName = typeName;
       2:      this.__class = true;
       3:      if (baseType) {
       4:          this.__baseType = baseType;
       5:          this.__basePrototypePending = true;
       6:      }
       7:      Sys.__upperCaseTypes[typeName.toUpperCase()] = this;
       8:   
       9:      Sys.__registeredTypes[typeName] = true;

    This code adds several properties to the current constructor function: __typeName, __class, __baseType, and __basePrototypePending. These properties are used by the reflection methods and by the initializeBase() method that we discuss in the next section.

    Finally, notice that the name of the constructor function (the class) is registered in two arrays kept in the Sys namespace: __upperCaseTypes and __registeredTypes. The __upperCaseTypes array is used by the Type.parse() method which takes a type name and returns an instance of the type. The __registeredTypes array is used by the registerClass() method to make sure that a class is not registered more than once.

    One thing that you should notice about the registerClass() method is that it does not modify the prototype property. The constructor function’s prototype property is not modified until the initializeBase() method is called. We discuss initializeBase() in the next section.

    Understanding the initializeBase() Method

    You call the initializeBase() method in the constructor of a derived class. For example, in Listing 1, we called the initializeBase() method in the constructor function for the TreeViewControl class. If you don’t call this method, the derived class does not inherit anything from its super class.

    I’ve included a stripped down version of the initializeBase() method in Listing 4.

    Listing 4 – MicrosoftAjax.debug.js initializeBase()

       1:  Type.prototype.initializeBase = function(instance, baseArguments) {
       2:      if (!this.isInstanceOfType(instance)) throw Error.argumentType('instance', Object.getType(instance), this);
       3:      this.resolveInheritance();
       4:      if (this.__baseType) {
       5:          if (!baseArguments) {
       6:              this.__baseType.apply(instance);
       7:          }
       8:          else {
       9:              this.__baseType.apply(instance, baseArguments);
      10:          }
      11:      }
      12:      return instance;
      13:  }

    Like the registerClass() method, the initializeBase() method is created as a method of the Function object (The Function object is aliased with the name Type). So you can call initializeBase() on any function. The intention is that you will call this method within a constructor function on the current function (or a super class of the current function).

    Let’s go through the code in Listing 4 line-by-line starting with the following code:

    if (!this.isInstanceOfType(instance)) throw Error.argumentType('instance', Object.getType(instance), this);

    This code validates whether the instance parameter passed to the initializeBase() method corresponds to the current function (or a super class of the current function). For example, the following code will throw an exception since the initializeBase() method is being called on the A function within the C function (You’ll only get these exceptions when in debug mode):

    Listing 5 – BadInitializeBase.js

       1:  <script type="text/javascript">
       2:   
       3:  function A() {}
       4:  A.registerClass("A");
       5:  function B() {}
       6:  B.registerClass("B");
       7:  function C()
       8:  {
       9:      A.initializeBase(this); // throws exception
      10:      B.initializeBase(this); // ok
      11:      C.initializeBase(this); // ok
      12:  }    
      13:  C.registerClass("C", B);
      14:   
      15:  var x = new C();
      16:   
      17:   
      18:  </script>

    The next statement in the initializeBase() method is the most important statement:

        this.resolveInheritance();

    This statement modifies the current function's prototype by calling the resolveInheritance() method. The resolveInheritance() method (slightly edited) is contained in Listing 6.

    Listing 6 – MicrosoftAjax.debug.js resolveInheritance()

       1:  Type.prototype.resolveInheritance = function() {
       2:      if (this.__basePrototypePending) {
       3:          var baseType = this.__baseType;
       4:          baseType.resolveInheritance();
       5:          for (var memberName in baseType.prototype) {
       6:              var memberValue = baseType.prototype[memberName];
       7:              if (!this.prototype[memberName]) {
       8:                  this.prototype[memberName] = memberValue;
       9:              }
      10:          }
      11:          delete this.__basePrototypePending;
      12:      }
      13:  }

    The resolveInheritance() method checks whether or not the constructor function’s __basePrototypePending property has the value true. The registerClass() method sets __basePrototypePending to the value true when you register a new class.

    Next, the resolveInheritance() method is called recursively for each constructor function in the inheritance chain. When the top of the chain is hit, all of the properties of the prototype of a constructor function higher in the chain are copied down.

    Consider the code in Listing 7 (the same code as Listing 1).

    Listing 7 – AjaxInheritance.js

       1: <script type="text/javascript">

       2:   
       3:  function BaseControl()
       4:  {
       5:      this._propA = "BaseControl propA";
       6:      this._propB = "BaseControl propB";
       7:  }
       8:   
       9:  BaseControl.prototype =
      10:  {
      11:      get_propA : function() {return this._propA;},
      12:      set_propA : function(value) {this._propA = value; },
      13:   
      14:      get_propB : function() {return this._propB; },
      15:      set_propB : function(value) {this._propB = value; }
      16:  }
      17:   
      18:  BaseControl.registerClass("BaseControl");
      19:   
      20:   
      21:  function TreeViewControl()
      22:  {
      23:      TreeViewControl.initializeBase(this);
      24:      this._propA = "TreeViewControl propA";
      25:  }
      26:   
      27:  TreeViewControl.prototype =
      28:  {
      29:      get_propA : function() {return this._propA;},
      30:      set_propA : function(value) {this._propA = value; }
      31:  }
      32:   
      33:  TreeViewControl.registerClass("TreeViewControl", BaseControl);
      34:   
      35:  var treeView1 = new TreeViewControl();
      36:   
      37:  alert( treeView1.get_propA() ); // displays "TreeViewControl propA"
      38:  alert( treeView1.get_propB() ); // displays "BaseControl propB"
      39:   
      40:      
      41:  </script>

    When initializeBase() is called in the constructor for the TreeView control, the resolveInheritance() method is called. The resolveInheritance() method looks up the base type for the TreeViewControl constructor function. In this case, the base type is BaseControl. Each property from the base type’s prototype is copied to the TreeViewControl constructor’s prototype. In particular, the get_propA, set_propA, get_propB, set_propB, and constructor properties are copied from the prototype for BaseControl to the prototype for TreeViewControl.

    Why are the properties copied from the parent constructor function’s prototype to the current prototype? In other words, why are the prototypes flattened? Presumably, for reasons of performance. If all of the properties are copied to the lowest prototype in the prototype chain, then the prototype chain never needs to be climbed to resolve the value of any property.

    In Firefox, the following statement returns the value true:

    alert( treeView1.__proto__.hasOwnProperty("get_propB") ); // displays true

    The __proto__ property is a Firefox only property that represents the current object’s prototype. The hasOwnProperty() JavaScript method returns true only when a property is a local property of an object and not when a property is read from the prototype chain. This statement shows that the prototype has been flattened and the prototype chain can be ignored when reading a property.

    The final code executed by the initializeBase() method appears below:

       1:      if (this.__baseType) {
       2:          if (!baseArguments) {
       3:              this.__baseType.apply(instance);
       4:          }
       5:          else {
       6:              this.__baseType.apply(instance, baseArguments);
       7:          }
       8:      }

    This code checks whether the current constructor function has been assigned a base type in the registerClass() method. If there is a base type, the JavaScript apply() method is called to pass the object being created to the constructor function for the base type. This last bit of code is necessary to initialize any private fields from the base class for the current object. The apply() method explains how the treeView1 object gets its _propA and _propB fields.

    Conclusion

    While writing this blog entry and working through the registerClass() and initializeBase() methods, I was surprised to discover that the ASP.NET AJAX Framework flattened the prototype chain. I was under the impression that ASP.NET AJAX used strict JavaScript prototype inheritance. Presumably, as mentioned previously, the prototype chain is flattened for performance reasons.

    There is a lot of interesting code in the Microsoft AJAX Library. There’s a lot that can be learned from a close study of the source code.

  • Two Methods of Creating JavaScript Objects: Prototype Inheritance and the Xerox Method

    In this blog entry, I examine different methods of building new JavaScript objects from existing JavaScript objects. For lack of better names, I’m calling the first method the Prototype Inheritance method and the second method the Xerox method. The goal of this blog entry is discuss the relative strengths and weaknesses of the two methods. At the very end of this entry, I briefly examine the approach taken by the ASP.NET AJAX framework.

    Prototype Inheritance

    Prototype Inheritance is the standard method of building JavaScript objects described in most JavaScript books and the Mozilla JavaScript documentation. Here’s how Prototype Inheritance works. Every JavaScript object has an associated prototype object. If you attempt to read a property from a JavaScript object, and the object does not have the property, then an attempt is made to read the property from the object’s prototype.

    Since the prototype object for an object can also have a prototype object, every object has something called a prototype chain. Whenever you attempt to read a property, each link in the chain is checked for the property. If the property is not found in the object’s prototype chain, then the property value undefined is returned.

    Prototype Inheritance is illustrated by Figure 1.

    clip_image002

    Figure 1 – Prototype Inheritance

    In Figure 1, there is an object with two prototype objects in its prototype chain (a prototype chain is terminated with a Null value). The object itself (located at the bottom of the figure) has two properties named PropA and PropB. This object’s first prototype object, Prototype 1, has one property named PropC. Finally, Prototype 1 also has a prototype object named Prototype 2. Prototype 2 has two properties named PropD and PropA.

    When reading the value of a property from the object, the entire prototype chain is used to retrieve the value of the property. For example, if you attempt to read the value of PropC, the value of the property is retrieved from Prototype 1.

    Notice that a prototype chain can contain duplicate properties. In Figure 1, PropA is included twice: as a property of the original object and as a property of the Prototype 2 object. Prototype chains use a first match algorithm. Therefore, when reading the value of PropA, the Prototype 2 object is ignored (lower objects in a chain can mask properties of higher objects in the chain).

    Here’s what is a little confusing about the way that Prototype Inheritance works. You don’t specify the prototype object for an object itself. Instead, you specify the prototype object with an object’s constructor function. This point is clearer with a sample of Prototype Inheritance in hand. Listing 1 contains two objects: BaseControl and TreeViewControl. These classes represent visual controls (widgets) that might be used in a web page. The TreeViewControl object inherits from the BaseControl object.

    Listing 1 – PrototypeInheritance.js

       1:  <script type="text/javascript">
       2:   
       3:  function BaseControl()
       4:  {
       5:      this.PropA = "BaseControl PropA";
       6:      this.PropB = "BaseControl PropB";    
       7:  }
       8:   
       9:  function TreeViewControl()
      10:  {
      11:      this.PropA = "TreeViewControl PropA";
      12:  }
      13:   
      14:  // Assign prototype
      15:  TreeViewControl.prototype = new BaseControl();
      16:   
      17:  // Create object
      18:  var treeView = new TreeViewControl();
      19:   
      20:  alert(treeView.PropA); // displays "TreeViewControl PropA"
      21:  alert(treeView.PropB); // displays "BaseControl PropB"
      22:  alert(treeView.PropZ); // displays undefined
      23:      
      24:  </script>

    In Listing 1, two object constructor functions named BaseControl and TreeViewControl are created. Next, an instance of BaseControl is created and assigned to the TreeViewControl function’s prototype property. Assigning an object to the Prototype property creates the prototype relationship between the BaseControl and TreeViewControl functions/objects.

    When an instance of the TreeViewControl is created, the following sequence of events happen (for details, see section 13.2.2 of the ECMAScript 3.0 specification at http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf):

    1. A new object is created by the new operator

    2. The value of the constructor function’s Prototype property is copied to the new object’s internal [[Prototype]] property

    3. The new object is passed to the constructor function (within the constructor function, the keyword this refers to the new object)

    When these steps are completed, you have a new object named treeView that has one property named PropA. In addition, the treeView object has an internal [[Prototype]] property that points to an instance of the BaseControl object. When you read a property from an object, the internal [[Prototype]] property is read to find a particular object’s prototype. Therefore, when you read treeView.PropB, the value “BaseControl PropB” is returned from the treeView prototype chain.

     

    The Xerox Method

    The other common approach to building JavaScript objects from other objects I call the Xerox method. When you use the Xerox method, you copy a set of properties from an existing object into a new object.

    This is the approach taken by the very popular Prototype framework (download from http://www.prototypejs.org/download). The Prototype framework includes an Object.extend() method that looks like this:

    Listing 3 – Prototype.js Extend Method

       1:  Object.extend = function(destination, source) {
       2:    for (var property in source)
       3:      destination[property] = source[property];
       4:    return destination;
       5:  };

    This method does something really simple: it copies all of the properties from a source object into a destination object.

    Here’s how you can use the Object.extend() method with the BaseControl and TreeViewControl objects:

    Listing 4 – Extend.js

       1:  <script type="text/javascript">
       2:   
       3:  var BaseControl =
       4:  {
       5:      PropA: "BaseControl PropA",
       6:      PropB: "BaseControl PropB"    
       7:  }
       8:   
       9:  var TreeViewControl =
      10:  {
      11:      PropA: "TreeViewControl PropA"
      12:  }
      13:   
      14:  // Extend TreeViewControl with BaseControl
      15:  Object.extend(TreeViewControl, BaseControl);
      16:   
      17:  // Create object
      18:  var treeView = Object.extend( {}, TreeViewControl);
      19:   
      20:  alert(treeView.PropA); // displays "BaseControl PropA"
      21:  alert(treeView.PropB); // displays "BaseControl PropB"
      22:  alert(treeView.PropZ); // displays undefined
      23:      
      24:  </script>

    In Listing 4, the Object.extend() method is used to copy all of the properties of the BaseControl object into the TreeViewControl object. Next, the extend method is called a second time to create a new copy of the TreeView object.

    There are a couple of things that you must be careful about when using Object.extend(). First, notice that treeView.PropA now returns the value “BaseControl PropA” instead of TreeViewControl.PropA unlike previous listings. When we copied the properties from BaseControl into TreeViewControl, we overwrote existing TreeViewControl properties. If this behavior bothers you, you can modify the Object.extend() method to look like this:

    Listing 5 – Extend2.js

       1:  Object.extend2 = function(destination, source) {
       2:    for (var property in source)
       3:      if (destination[property] === undefined)
       4:          destination[property] = source[property];
       5:    return destination;
       6:  };

    This modified version of Object.extend() won’t overwrite existing properties in the “derived” object.

    You also should be warned that the Object.extend() method creates a shallow clone. When you create a new object with Object.extend(), value types are copied but not reference types. This behavior is clarified by the following code:

    Listing 6 – ShallowClone.js

       1:  <script type="text/javascript">
       2:   
       3:  var BaseControl =
       4:  {
       5:      MethodA: function() { alert("Hello"); },
       6:      PropB: []
       7:  }
       8:   
       9:  var TreeViewControl =
      10:  {
      11:      PropA: "TreeViewControl PropA"
      12:  }
      13:   
      14:  // Extend TreeViewControl with BaseControl
      15:  Object.extend(TreeViewControl, BaseControl);
      16:   
      17:  // Create objects
      18:  var treeView1 = Object.extend( {}, TreeViewControl);
      19:  var treeView2 = Object.extend( {}, TreeViewControl);
      20:   
      21:  treeView1.MethodA = function() { alert("Bye"); };    
      22:  treeView1.PropB.push( "some item" );    
      23:      
      24:  alert( treeView2.PropB.length ); // displays 1    
      25:  treeView2.MethodA(); // displays "Hello"
      26:      
      27:  </script>

    In Listing 6, BaseControl has two properties that represent Object types rather than value types. For example, PropB represents an Array. Since an Array is an Object type, every object extended with the BaseControl will share the same reference to the very same Array. Adding an item to treeView1.PropB also adds the item to treeView2.PropB.

    The fact that Object.extend creates a shallow rather than a deep clone is both a good and a bad thing. On the one hand, from the point of view of memory consumption, it is a good thing. On the other hand, if you don’t know what you are doing, then you might shoot yourself in the foot.

    There is a variation on the Xerox method included in the Mozilla JavaScript documentation (see More Flexible Constructors at http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Details_of_the_Object_Model). Instead of using the Object.extend() method, you call the base object from the derived object’s constructor. Here’s how you would use this variation with the BaseControl and TreeViewControl objects:

    Listing 7 – BaseCall.js

       1:  <script type="text/javascript">
       2:   
       3:  function BaseControl()
       4:  {
       5:      this.PropA = "BaseControl PropA";
       6:      this.PropB = "BaseControl PropB";    
       7:  }
       8:   
       9:  function TreeViewControl()
      10:  {
      11:      // call base constructor
      12:      this.base = BaseControl;
      13:      this.base();
      14:      
      15:      this.PropA = "TreeViewControl PropA";
      16:  }
      17:   
      18:  // Create object
      19:  var treeView = new TreeViewControl();
      20:   
      21:  alert(treeView.PropA); // displays "TreeViewControl PropA"
      22:  alert(treeView.PropB); // displays "BaseControl PropB"
      23:  alert(treeView.PropZ); // displays undefined
      24:      
      25:  </script>

    Of all of the methods of constructing objects described in this blog entry, I find this method the most intuitive and easy to use.

    Notice that the relationship between BaseControl and TreeViewControl is specified within the TreeViewControl constructor function with the following two lines of code:

    // call base constructor

    this.base = BaseControl;

    this.base();

    The BaseControl function is assigned to a property of the TreeViewControl constructor function. Next, the base constructor function is called. That’s it.

    It is important to understand that base is not a JavaScript keyword. You can use any property name here and the code would work the same way. For example, this code works just fine:

    // call base constructor

    this.steve = BaseControl;

    this.steve();

    The point of this code is to call the BaseControl constructor with the right value for the this keyword. When the BaseControl() function is called, you want the keyword this to refer to the current object being built by the TreeViewControl constructor function.

    If you want to make the code in Listing 7 even shorter, then you can use the JavaScript apply() method. The apply() method enables you to modify the value of the this keyword when calling a function. This approach is illustrated in Listing 8:

    Listing 8 – Apply.js

       1:  <script type="text/javascript">
       2:   
       3:  function BaseControl()
       4:  {
       5:      this.PropA = "BaseControl PropA";
       6:      this.PropB = "BaseControl PropB";    
       7:  }
       8:   
       9:  function TreeViewControl()
      10:  {
      11:      // call base constructor
      12:      BaseControl.apply(this);
      13:    
      14:      this.PropA = "TreeViewControl PropA";
      15:  }
      16:   
      17:  // Create object
      18:  var treeView = new TreeViewControl();
      19:   
      20:  alert(treeView.PropA); // displays "TreeViewControl PropA"
      21:  alert(treeView.PropB); // displays "BaseControl PropB"
      22:  alert(treeView.PropZ); // displays undefined
      23:      
      24:  </script>

    The method used in this last code sample is the shortest way of building objects from existing objects that I know. When BaseControl.apply(this) is called, the BaseControl function is called with the current object as the value for the BaseControl function’s this keyword. Therefore, the BaseControl function ends up decorating the current object with the PropA and PropB properties.

    Prototype Inheritance versus the Xerox Method

    In this blog entry, I’ve compared two general methods for building new JavaScript objects from existing JavaScript objects: Prototype Inheritance and the Xerox method. So which method is better?

    The chief advantage of Prototype Inheritance is saving memory. When you use Prototype Inheritance, you are not creating copies of object properties. Instead, Prototype Inheritance enables you to specify relationships between distinct objects with distinct sets of properties. If you are working with thousands of objects, then saving memory might really matter to you.

    The advantage of the Xerox method is performance. Following a prototype chain to resolve a property takes time. When using the Xerox method, on the other hand, every property of an object is a local property. An object’s prototype chain is never used.

    One other advantage of the Xerox method is flexibility. The Xerox method supports multiple inheritance. If you want to derive a TreeViewControl from both a BaseControl and a BaseDataBoundControl, then you can do this with the Xerox method but not with the Prototype Inheritance method.

    Building Objects with ASP.NET AJAX

    When building new objects out of existing objects using ASP.NET AJAX, you use some of the features of Prototype Inheritance and some of the features of the Xerox method. Let's look at a code sample.

    Listing 2 – ASPNETAjaxInheritance.aspx

       1:  <script type="text/javascript">
       2:   
       3:   
       4:  function BaseControl()
       5:  {
       6:  }
       7:  BaseControl.prototype.PropA = "BaseControl PropA";
       8:  BaseControl.prototype.PropB = "BaseControl PropB";
       9:   
      10:   
      11:  // Register BaseControl class
      12:  BaseControl.registerClass("BaseControl");
      13:   
      14:  function TreeViewControl()
      15:  {
      16:      TreeViewControl.initializeBase(this);
      17:  }
      18:  TreeViewControl.prototype.PropA = "TreeViewControl PropA";
      19:   
      20:  // Register TreeViewControl class
      21:  TreeViewControl.registerClass("TreeViewControl", BaseControl);
      22:   
      23:  // Create object
      24:  var treeView = new TreeViewControl();
      25:   
      26:  alert(treeView.PropA); // displays "TreeViewControl PropA"
      27:  alert(treeView.PropB); // displays "BaseControl PropB"
      28:  alert(treeView.PropZ); // displays undefined
      29:    
      30:  </script>

    In Listing 2, a method named registerClass() is called for both the BaseControl and the TreeViewControl functions. The registerClass() method accepts the following parameters:

    · typeName – The class being registered

    · baseType – (optional) the base class for the class being registered

    · interfaceTypes – (optional) an array of interfaces implemented by the class being registered

    First, the registerClass() method is called for the BaseControl constructor function. Next, the method is called for the TreeViewControl constructor function. When the method is called for the TreeViewContructor function, a second parameter is passed that represents the TreeViewControl’s base class.

    There is one other important line of code that you need to notice in Listing 2. Notice that TreeViewControl.initializeBase() is called in the TreeViewControl constructor function. If you don’t call this method, then the prototype relationship between BaseControl and TreeViewControl will never be created.

    One last thing that you should notice about Listing 2. Notice that the object properties are not defined within the constructor functions. For example, PropA is not defined in the BaseControl constructor function. Instead, PropA is defined with the BaseControl.prototype object. This is a requirement when using prototype inheritance with ASP.NET AJAX. If you define the properties within an object’s constructor function, then the prototype chain never comes into play.

    As I mentioned before, the ASP.NET AJAX Framework uses both Prototype Inheritance and Xerox Inheritance. On the one hand, ASP.NET AJAX uses Prototype Inheritance. Every instance of a particular class (such as the TreeViewControl class) shares the same prototype. The prototype and not the object instances have the PropA and PropB method. Memory is saved since these properties do not need to be copied to each and every instance of a TreeViewControl.

    On the other hand, ASP.NET AJAX uses Xerox Inheritance. When the ASP.NET AJAX initializeBase() method is called, the prototype chain is collapsed. All of the properties of each prototype object higher in the chain are copied lower in the chain. Presumably, the ASP.NET AJAX framework collapses the prototype chain to improve performance so that the chain does not need to be climbed when reading the value of object properties.

  • ASP.NET 3.5 Unleashed Errata: Listing 31.6 and Listing 31.24

     

    There are two mistakes in Chapter 31, Using Server-Side ASP.NET AJAX, both related to a last minute change to the ListView control. Microsoft changed the ListView control to require an itemPlaceholder instead of an itemContainer element in its LayoutTemplate. I managed to update the other code samples related to the ListView control in the book, but I neglected to update Chapter 31 (I forgot that I used the ListView control in this chapter).

    The correct code for Listing 31.6 is:

       1:  <%@ Page Language="C#" %>
       2:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       3:  <html xmlns="http://www.w3.org/1999/xhtml">
       4:  <head runat="server">
       5:      <title>Nested UpdatePanels</title>
       6:      <style type="text/css">
       7:          fieldset
       8:          {
       9:              padding: 10px;
      10:          }
      11:          .comment
      12:          {
      13:              padding: 10px;
      14:              border: dotted 2px black;
      15:              margin: 10px;
      16:          }
      17:      </style>
      18:  </head>
      19:  <body>
      20:      <form id="form1" runat="server">
      21:      <div>
      22:      <asp:ScriptManager
      23:          id="sm1"
      24:          Runat="server" />
      25:      Page Time: <%= DateTime.Now.ToString("T") %>
      26:      <br />
      27:      <asp:DropDownList
      28:          id="ddlMovie"
      29:          DataSourceID="srcMovies"
      30:          DataValueField="Id"
      31:          DataTextField="Title"
      32:          AutoPostBack="true"
      33:          Runat="server" />
      34:      <asp:SqlDataSource
      35:          id="srcMovies"
      36:          ConnectionString='<%$ ConnectionStrings:con %>'
      37:          SelectCommand="SELECT Id, Title FROM Movie"
      38:          Runat="server" />
      39:      <br /><br />
      40:      <asp:UpdatePanel ID="upOuter" UpdateMode="Conditional" runat="server">
      41:      <Triggers>
      42:          <asp:AsyncPostBackTrigger ControlID="ddlMovie" />
      43:      </Triggers>
      44:      <ContentTemplate>
      45:      Outer UpdatePanel Time: <%= DateTime.Now.ToString("T") %>
      46:      <br />
      47:      <asp:FormView
      48:          id="frmMovie"
      49:          DataSourceID="srcMovie"
      50:          Runat="server">
      51:          <ItemTemplate>
      52:          <fieldset>
      53:          <legend>Movie</legend>
      54:          Title: <%# Eval("Title") %>
      55:          <br />
      56:          Director: <%# Eval("Director") %> 
      57:   
      58:          <asp:UpdatePanel ID="upInner" runat="server">
      59:          <ContentTemplate>        
      60:          <asp:ListView
      61:              id="lstMovieComments"
      62:              DataSourceID="srcMovieComments"
      63:              InsertItemPosition="FirstItem"
      64:              Runat="server">
      65:              <LayoutTemplate>
      66:                  <fieldset>
      67:                  <legend>Comments</legend>
      68:                  Inner UpdatePanel Time: <%# DateTime.Now.ToString("T") %>
      69:                  <asp:PlaceHolder id="itemPlaceHolder" runat="server" />
      70:              </fieldset>          
      71:              </LayoutTemplate>
      72:              <ItemTemplate>
      73:                  <div class="comment">
      74:                  <%# Eval("Comment") %>
      75:                  </div>
      76:              </ItemTemplate>
      77:              <InsertItemTemplate>
      78:              <asp:Label
      79:                  id="lblComment"
      80:                  Text="Comment:"
      81:                  AssociatedControlID="txtComment"
      82:                  Runat="server" />
      83:              <br />
      84:              <asp:TextBox
      85:                  id="txtComment"
      86:                  Text='<%# Bind("Comment") %>'
      87:                  TextMode="MultiLine"
      88:                  Columns="40"
      89:                  Rows="3"
      90:                  Runat="server" />
      91:              <br />
      92:              <asp:Button
      93:                  id="btnInsert"
      94:                  Text="Add Comment"
      95:                  CommandName="Insert"
      96:                  Runat="server" />    
      97:              </InsertItemTemplate>
      98:          </asp:ListView>
      99:          </ContentTemplate>
     100:          </asp:UpdatePanel>
     101:          <asp:SqlDataSource
     102:              id="srcMovieComments"
     103:              ConnectionString='<%$ ConnectionStrings:con %>'
     104:              SelectCommand="SELECT Id, Comment 
     105:                  FROM MovieComment
     106:                  WHERE MovieId=@MovieId"
     107:              InsertCommand="INSERT MovieComment (Comment,MovieId)
     108:                  VALUES (@Comment,@MovieId)"
     109:              Runat="server">
     110:              <SelectParameters>
     111:                  <asp:ControlParameter Name="MovieId" ControlID="ddlMovie" />
     112:              </SelectParameters>    
     113:              <InsertParameters>
     114:                  <asp:ControlParameter Name="MovieId" ControlID="ddlMovie" />
     115:              </InsertParameters>    
     116:          </asp:SqlDataSource>     
     117:          </fieldset>        
     118:          </ItemTemplate>
     119:      </asp:FormView>   
     120:      </ContentTemplate> 
     121:      </asp:UpdatePanel>
     122:      <asp:SqlDataSource
     123:          id="srcMovie"
     124:          ConnectionString='<%$ ConnectionStrings:con %>'
     125:          SelectCommand="SELECT Id, Title, Director 
     126:              FROM Movie
     127:              WHERE Id=@Id"
     128:          Runat="server">
     129:          <SelectParameters>
     130:              <asp:ControlParameter Name="Id" ControlID="ddlMovie" />
     131:          </SelectParameters>    
     132:      </asp:SqlDataSource>     
     133:      </div>
     134:      </form>
     135:  </body>
     136:  </html>

    Notice that I also updated the way that the current time is displayed for this code sample. I changed:

    Inner UpdatePanel Time: <%= DateTime.Now.ToString("T") %>

    To:

    Inner UpdatePanel Time: <%# DateTime.Now.ToString("T") %>

    The correct code for Listing 31.24 is:

       1:  <%@ Page Language="C#" %>
       2:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       3:  <html xmlns="http://www.w3.org/1999/xhtml">
       4:  <head runat="server">
       5:      <title>Timer Messages</title>
       6:      <style type="text/css">
       7:      .message
       8:      {
       9:          margin-left: 20px;
      10:          font-style:italic;
      11:      }
      12:      </style>
      13:  </head>
      14:  <body>
      15:      <form id="form1" runat="server">
      16:      <asp:ScriptManager ID="sm1" runat="server" />
      17:      <asp:Timer ID="Timer1" Interval="5000" runat="server" />
      18:      <asp:UpdatePanel ID="up1" runat="server">
      19:      <Triggers>
      20:          <asp:AsyncPostBackTrigger ControlID="Timer1" EventName="Tick" />
      21:      </Triggers>
      22:      <ContentTemplate>
      23:      Last Refresh <%= DateTime.Now.ToString("T") %>
      24:      <hr />
      25:      <asp:ListView
      26:          id="lstMessages"
      27:          DataSourceID="srcMessages"
      28:          Runat="server">
      29:          <LayoutTemplate>
      30:              <asp:Placeholder id="itemPlaceholder" runat="server" />
      31:          </LayoutTemplate>
      32:          <ItemTemplate>
      33:              <div>
      34:                  Posted by <%# Eval("PostedBy") %>
      35:                  <div class="message">
      36:                  <%# Eval("Post") %>
      37:                  </div>
      38:              </div>    
      39:          </ItemTemplate>
      40:      </asp:ListView>    
      41:      </ContentTemplate>      
      42:      </asp:UpdatePanel>
      43:      <asp:ObjectDataSource
      44:          id="srcMessages"
      45:          TypeName="Message"
      46:          SelectMethod="Select"
      47:          Runat="server" />
      48:      </form>
      49:  </body>
      50:  </html>

    Thank you Nikolay for pointing out these errors.

  • Declaring Client-Side ASP.NET AJAX Controls : Part I

    I want to build “pure” client-side ASP.NET AJAX web applications and I want to get the full benefits of a declarative framework. Currently, the ASP.NET AJAX framework does not support a good method of creating declarative client-side controls. In this blog entry, I examine different strategies for implementing declarative client-side controls that target the Microsoft ASP.NET AJAX framework.

    The Problem in Need of a Solution

    I like the ASP.NET framework. Declarative server-side controls are a good thing. I would much rather add a GridView control to a page than script out all the necessary logic for rendering the user interface for sorting and paging a set of items. Likewise for the TreeView, Menu, and all of the other controls in the toolbox. In general, I believe that it is better to declare than to code.

    I’ve been writing web applications for a long time. I used to build huge websites using classic Active Server Pages. Active Server Pages did not support declarative controls and the pages were not pretty. You had to swim in a sea of vbscript/jscript script when reading the page. The pages were hard to understand and maintain. The technical name for the code contained in this type of page is spaghetti code.

    I like building user interfaces with declarative controls. Unfortunately, the ASP.NET framework currently only supports declarative server-side controls. The ASP.NET framework does not support declarative client-side controls. Since I want to build rich interactive responsive Ajax web applications, I need client-side declarative controls.

    I’ve made a list of the features that I want in a declarative client-side Ajax framework:

    · Declarative Controls – I want to be able to add a client-side control to a page in exactly the same way as I currently can add a server-side control to a page. You should be able to declare a rich client-side control simply by adding a tag to a page.

    · Composite Controls – In some cases, a client-side control should get replaced by a rich set of HTML elements. Think of the ASP.NET Login control. This control renders TextBox, Validation, and Button controls. Some declarative client-side controls need to be composite controls.

    · DOM Accessible – You should be able to interact with a client-side control using standard DOM methods such as getElementById(). As we’ll see later in this blog entry, this requirement is more challenging than you might think.

    · Templates – Many of the server-side controls in the ASP.NET framework support templates. Templates are huge. Templates enable you to get rid of the majority of your spaghetti code. However, templates pose special issues for a declarative control framework. A template does not represent a set of controls. A template represents a pattern for a repeated set of controls. Templates introduce special issues about control IDs (you can’t repeat the same ID).

    · Libraries – Different client-side controls might live in different client-side script libraries. The framework needs to be able to load the right client-script library for the right control. It would be even better if the framework could determine library dependencies and load the right dependencies automatically and non-redundantly.

    · Scriptless – In the perfect world, a page would contain nothing but tags. It would be a valid XHTML document (both the source code and the rendered content). It should not contain scripts or even data-binding expressions. A person entirely ignorant of the ASP.NET framework should be able to load it up into an application like Dreamweaver and start modifying it without endangering any of the page logic (you know, the designer should be able to design without breaking your page’s functionality).

    · Notepad-able – I don’t trust any code that I can’t write in notepad. I get nervous whenever I hear anyone say that the Visual tools will make some code easy to write (for example, creating entity associations in LINQ to SQL is currently much too hard). One of the things that I really liked about the original ASP.NET framework was that I could do everything in Notepad. That gave me the feeling that I could understand the code.

    The list above is a lot to want, but it describes what I want. The rest of this blog entry will describe different strategies for implementing this type of declarative client-side framework.

    Creating a Client-Side ASP.NET AJAX Control

    Before we do anything else, let’s start by creating a really, really simple ASP.NET AJAX client-side control. The code in Listing 1 defines a simple client-side control named the MyControl control. The MyControl control renders the string “blah”.

    Listing 1 – MyControl.js

       1:  /// <reference name="MicrosoftAjax.js"/>
       2:   
       3:  Type.registerNamespace("Code");
       4:   
       5:  Code.MyControl = function(element) {
       6:   
       7:    Code.MyControl.initializeBase(this, [element]);
       8:   
       9:    element.innerHtml = "blah";
      10:   
      11:  }
      12:   
      13:  Code.MyControl.prototype = {
      14:   
      15:    initialize: function() {
      16:   
      17:      Code.MyControl.callBaseMethod(this, 'initialize');
      18:   
      19:      // Add custom initialization here
      20:   
      21:    },
      22:   
      23:    dispose: function() {
      24:   
      25:      //Add custom dispose actions here
      26:   
      27:      Code.MyControl.callBaseMethod(this, 'dispose');
      28:   
      29:    }
      30:   
      31:  }
      32:   
      33:  Code.MyControl.registerClass('Code.MyControl', Sys.UI.Control);
      34:   
      35:  if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

    If the code in Listing 1 does not make sense to you, don’t worry. The code defines a very minimal client-side control. So, let’s look at different ways that we can add this control to a page.

    Creating AJAX Controls: The Windows Forms Approach

    You create an ASP.NET AJAX control by calling the client-side $create() method. The $create() method can be used to convert a normal HTML element in a page into a client-side Ajax control.

    For example, the page in Listing 2 instantiates the MyControl control that we created in the previous section:

    Listing 2 – Way1.aspx

       1:  <%@ Page Language="C#" %>
       2:   
       3:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       4:   
       5:  <html xmlns="http://www.w3.org/1999/xhtml">
       6:   
       7:  <head id="Head1" runat="server">
       8:   
       9:    <title>Way 1</title>
      10:   
      11:    <script type="text/javascript">
      12:   
      13:    function pageLoad() 
      14:   
      15:    {
      16:   
      17:      $create(Code.MyControl, null, null, null, $get("ctl"));
      18:   
      19:    }
      20:   
      21:    </script>
      22:   
      23:  </head>
      24:   
      25:  <body>
      26:   
      27:  <form id="form1" runat="server">
      28:   
      29:  <div>
      30:   
      31:  <asp:ScriptManager ID="ScriptManager1" runat="server">
      32:   
      33:  <Scripts>
      34:   
      35:    <asp:ScriptReference Path="~/MyControl.js" />
      36:   
      37:  </Scripts>
      38:   
      39:  </asp:ScriptManager>
      40:   
      41:    <div id="ctl"></div>
      42:   
      43:  </div>
      44:   
      45:  </form>
      46:   
      47:  </body>
      48:   
      49:  </html>

    There are two things to notice about this page. First, notice that the MyControl.js JavaScript file is imported with the server-side ScriptManager control. The ScriptReference loads the MyControl.js file.

    Second, notice the page includes a JavaScript pageLoad() function. This function gets called by the ASP.NET AJAX framework automatically after all of the scripts are loaded and the DOM has been parsed. The call to the $create() method is contained in this pageLoad method.

    The $create() method converts a normal, unassuming HTML element into a client-side ASP.NET AJAX control. The script above converts a DIV tag declared in the body of the page into an ASP.NET AJAX control.

    The $create() method accepts the following set of parameters:

    · Type – Indicates the type of control to create. For example, Code.MyControl

    · Properties – Indicates a list of initial property values for the control. You pass this list as a JavaScript object literal.

    · Events – Indicates a list of initial event handlers for the control. You pass this list as a JavaScript object literal.

    · References – Indicates a list of references to other controls. You pass this list as a JavaScript object literal.

    · Element – Indicates the DOM element where the control will be initialized.

    I almost never use any of the parameters except for Type, Properties, and Element.

    I call this method of instantiating an AJAX control the Windows Forms approach. I call it the Windows Forms approach since it reminds me of the way that you must code the instantiation of all of the controls in a Windows Forms form.

    Nobody writes Windows Forms applications in notepad because this method of instantiating controls is just too awkward and time consuming. Obviously, this is not a good way to create AJAX controls. This approach is a non-declarative approach. It does not work well in the case of pages with a lot of controls.

    Creating AJAX Controls: The ASP.NET Controls Approach

    The ASP.NET framework currently supports one method of creating declarative client-side controls. You can create a declarative client-side control by launching it from a declarative server-side ASP.NET control.

    To make this easy, the ASP.NET 3.5 framework includes a base control class for this very purpose: the ScriptControl. The code in Listing 3 defines a server-side control named MyControl that launches the client-side control also named MyControl.

    Listing 3 – MyControl.cs

       1:  using System;
       2:   
       3:  using System.Web;
       4:   
       5:  using System.Web.UI;
       6:   
       7:  using System.Collections.Generic;
       8:   
       9:  namespace Code
      10:   
      11:  {
      12:   
      13:    public class MyControl : ScriptControl
      14:   
      15:    {
      16:   
      17:      protected override HtmlTextWriterTag TagKey
      18:   
      19:      {
      20:   
      21:        get
      22:   
      23:        {
      24:   
      25:          return HtmlTextWriterTag.Div;
      26:   
      27:        }
      28:   
      29:      }
      30:   
      31:      protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
      32:   
      33:      {
      34:   
      35:        ScriptDescriptor descriptor = new ScriptControlDescriptor("Code.MyControl", this.ClientID);
      36:   
      37:        return new List<ScriptDescriptor>() { descriptor };
      38:   
      39:      }
      40:   
      41:      protected override IEnumerable<ScriptReference> GetScriptReferences()
      42:   
      43:      {
      44:   
      45:        ScriptReference refer = new ScriptReference("~/MyControl.js");
      46:   
      47:        return new List<ScriptReference>() { refer };
      48:   
      49:      }
      50:   
      51:    }
      52:   
      53:  }

    The server-side control defined in Listing 3 has one property named TagKey and two methods named GetScriptDescriptors() and GetScriptReferences. The TagKey property determines the tag that the server-side control renders to the browser. In the code above, the control renders a DIV tag.

    The GetScriptDescriptors() method is responsible for generating the $create() method call that creates the client-side control. The control in Listing 3 creates a client-side control named MyControl. The control generates the following $create statement which is executed on the client:

    $create(Code.MyControl, null, null, null, $get("ctl"));

    Finally, the GetScriptReferences() method enables you to add the JavaScript library that contains the definition for the client-side control to the page. In Listing 3, the GetScriptReferences() method is used to add a reference to the MyControl.js JavaScript library that contains the definition of the client-side MyControl control.

    After you create the server-side script control, you can use the control in a page just like any other ASP.NET control. The page in Listing 4 takes advantage of the server-side MyControl control to launch the client-side MyControl control.

    Listing 4 – Way2.aspx

       1:  <%@ Page Language="C#" %>
       2:   
       3:  <%@ Register TagPrefix="ajax" Namespace="Code" %>
       4:   
       5:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       6:   
       7:  <html xmlns="http://www.w3.org/1999/xhtml">
       8:   
       9:  <head runat="server">
      10:   
      11:    <title>Way 2</title>
      12:   
      13:  </head>
      14:   
      15:  <body>
      16:   
      17:  <form id="form1" runat="server">
      18:   
      19:  <div>
      20:   
      21:    <asp:ScriptManager ID="ScriptManager1" runat="server" />
      22:   
      23:    <ajax:MyControl ID="ctl" runat="server" />
      24:   
      25:  </div>
      26:   
      27:  </form>
      28:   
      29:  </body>
      30:   
      31:  </html>

    The advantage of this approach to creating client-side controls is that it integrates very well with the existing ASP.NET framework. For example, the very popular AJAX Control Toolkit uses this approach (more or less) for all of the toolkit controls such as the DragPanel and AutoComplete controls (see http://www.asp.net/ajax/ajaxcontroltoolkit/samples/). This is a very good approach to take when you want to incrementally add Ajax functionality to an existing server-side ASP.NET application.

    However, I’m interested in building “pure” Ajax applications with the Microsoft ASP.NET framework. If you want to abandon all of the baggage of server-side ASP.NET -- such as view state, the postback model, and the page and control event model -- then you won’t want to use heavy weight server-side controls as a launch mechanism for your client-side controls.

    In particular, the ScriptControl base control requires you to add a ScriptManager control to a page. The ScriptManager control, in turn, requires you to add a server-side form control to a page. Therefore, as soon as you start using a ScriptControl to launch your client-side controls, you’ve already committed yourself to the web form model.

    Furthermore, it is important to realize that a ScriptControl derives from the base WebControl class. The base WebControl class has a rich set of events, methods, and properties tied to the server-side Web Forms page execution model. A ScriptControl participates in the normal page execution lifecycle.

    When building a “pure” Ajax application, this is the very stuff that I want to go away:

    · Postbacks – The whole point of an Ajax application is to avoid submitting entire pages back to the server. From the perspective of an Ajax developer, posting a page back to the server is just an opportunity to create a bad user experience. Imagine, for the moment, freezing a desktop application and making the screen shake whenever a user performed any action; that would be crazy. The holy grail of a “pure” Ajax application is the single page application.

    · View State – View state is great for a server-side ASP.NET web application. However, view state is a nightmare when you are building a client-side application. Keeping view state synchronized between the client and server is a huge pain. In any case, there is no point in maintaining view state when you are not performing postbacks (see previous bullet point). Since view state must be pushed back and forth across the wire in a hidden form field, view state just hurts performance.

    · Page and Control Execution Lifecycle – ASP.NET provides developers with a rich server-side page execution lifecycle which is completely useless in the case of a "pure" client-side application. Who cares about Init, Load, PreRender, and Unload events when these events happen on the server-side? Just render my client-side code please.

    Now, I want to emphasize that the features listed in the bullet points above are what makes ASP.NET such a fantastic framework for building server-side web applications. Be that as it may, I want my fast Ajax fighter jet of a client-side application.

    The .NET and ASP.NET frameworks provide many useful features that can be used in a pure Ajax web application. For example, I want to take advantage of ASP.NET services such as the authentication, role, and profile services. I also want to take advantage of .NET framework features such as LINQ to SQL. I just don’t want to be forced to adopt a heavy-weight server-side page model just to take advantage of these useful framework features.

    Creating AJAX Controls: The Lightweight ASP.NET Page Approach

    If server-side ASP.NET controls are too heavy to launch client-side Ajax controls, then why not build lightweight server-side controls? Why not create server-side controls that don’t assume view state, the postback model, or a server-side page execution lifecycle? This is the approach to creating declarative client-side controls that we will consider in this section.

    When I started to investigate this approach, I quickly realized that heavyweight web controls are baked very deeply into the ASP.NET framework. Every control used in an ASP.NET page must derive from the base Control class (System.Web.UI.Control class). The base Control class already assumes a heavy-weight server-side page model. Therefore, if you want to create lightweight controls, you must also abandon ASP.NET pages.

    One of the nice features of the ASP.NET framework is that it was designed to be very flexible. If you want to abandon ASP.NET pages as they currently exist, then you can do this. You simply need to remap ASP.NET pages to a new HTTP Handler.

    I want my handler to do something really simple. I want it to parse a page and generate $create() method calls for any page elements that do not inhabit the XHTML namespace. My HTTP Handler is contained in Listing 5:

    Listing 5 – AjaxPageHandler.cs

       1:  using System;
       2:   
       3:  using System.Web;
       4:   
       5:  using System.Xml;
       6:   
       7:  using System.Text;
       8:   
       9:  public class AjaxPageHandler : IHttpHandler
      10:   
      11:  {
      12:   
      13:    public void ProcessRequest(HttpContext context)
      14:   
      15:    {
      16:   
      17:      // load page
      18:   
      19:      string pagePath = context.Request.PhysicalPath;
      20:   
      21:      XmlDocument doc = new XmlDocument();
      22:   
      23:      try
      24:   
      25:      {
      26:   
      27:        doc.Load(pagePath);
      28:   
      29:      }
      30:   
      31:      catch
      32:   
      33:      {
      34:   
      35:        throw new Exception("Could not load " + context.Request.Path);
      36:   
      37:      }
      38:   
      39:      // find Ajax elements
      40:   
      41:      XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
      42:   
      43:      nsManager.AddNamespace("default", "http://www.w3.org/1999/xhtml");
      44:   
      45:      XmlNodeList controls = doc.SelectNodes(@"//*[namespace-uri(.) != 'http://www.w3.org/1999/xhtml']", nsManager);
      46:   
      47:     if (controls.Count > 0)
      48:   
      49:     {
      50:   
      51:      // Add Microsoft AJAX Library Script reference
      52:   
      53:      AddScriptTag(context, doc, "/Microsoft/MicrosoftAjax.js");
      54:   
      55:      // Add libraries
      56:   
      57:      AddLibraries(context, doc);
      58:   
      59:      // build $create method calls
      60:   
      61:      AddCreates(doc, controls);
      62:   
      63:    }
      64:   
      65:    // Render XML doc
      66:   
      67:    doc.Save(context.Response.Output);
      68:   
      69:  }
      70:   
      71:  private void AddLibraries(HttpContext context, XmlDocument doc)
      72:   
      73:  {
      74:   
      75:    foreach (XmlAttribute att in doc.DocumentElement.Attributes)
      76:   
      77:    {
      78:   
      79:      if (att.Name.StartsWith("xmlns:"))
      80:   
      81:      {
      82:   
      83:        AddScriptTag(context, doc, att.Value);
      84:   
      85:      }
      86:   
      87:    }
      88:   
      89:  }
      90:   
      91:  private void AddScriptTag(HttpContext context, XmlDocument doc, string path)
      92:   
      93:  {
      94:   
      95:    XmlElement script = doc.CreateElement("script", "http://www.w3.org/1999/xhtml");
      96:   
      97:    script.SetAttribute("type", "text/javascript");
      98:   
      99:    script.SetAttribute("src", context.Request.ApplicationPath + path);
     100:   
     101:    script.InnerText = ""; // don't create minimal element
     102:   
     103:    doc.DocumentElement.AppendChild(script);
     104:   
     105:  }
     106:   
     107:  private void AddCreates(XmlDocument doc, XmlNodeList controls)
     108:   
     109:  {
     110:   
     111:    // Build $create method calls
     112:   
     113:    StringBuilder sb = new StringBuilder();
     114:   
     115:    sb.AppendLine();
     116:   
     117:    sb.AppendLine(@"//<![CDATA[");
     118:   
     119:    sb.AppendLine("Sys.Application.initialize();");
     120:   
     121:    sb.AppendLine("Sys.Application.add_init(function() {");
     122:   
     123:    foreach (XmlElement el in controls)
     124:   
     125:    {
     126:   
     127:      if (!el.HasAttribute("id"))
     128:   
     129:        throw new Exception("Element " + el.Name + " missing id");
     130:   
     131:      sb.AppendFormat("$create({0}.{1},null,null,null,$get('{2}'));\n", el.Prefix, el.LocalName, el.GetAttribute("id"));
     132:   
     133:    }
     134:   
     135:    sb.AppendLine("});");
     136:   
     137:    sb.AppendLine("//]]>");
     138:   
     139:    // Add script element
     140:   
     141:    XmlElement script = doc.CreateElement("script", "http://www.w3.org/1999/xhtml");
     142:   
     143:    script.SetAttribute("type", "text/javascript");
     144:   
     145:    script.InnerXml = sb.ToString();
     146:   
     147:    doc.DocumentElement.AppendChild(script);
     148:   
     149:  }
     150:   
     151:  public bool IsReusable
     152:   
     153:  {
     154:   
     155:    get { return true; }
     156:   
     157:  }
     158:   
     159:  }

    The HTTP handler in listing 5 actually does 3 things:

    · It adds a reference to the Microsoft AJAX Library. The assumption is that this library is located at the path /Microsoft/MicrosoftAjax.js. You can download the standalone Microsoft AJAX Library from http://msdn2.microsoft.com/en-us/asp.net/bb944808.aspx

    · It adds a reference to each library needed by the client-side controls.

    · It calls the $create() method for each client-side control.

    You can apply the HTTP Handler to any aspx page in a folder named AjaxPages with the web configuration file in Listing 6 by adding this configuration file to the AjaxPages folder.

    Listing 6 – /AjaxPages/Web.config

       1:  <?xml version="1.0"?>
       2:   
       3:  <configuration>
       4:   
       5:  <system.web>
       6:   
       7:    <httpHandlers>
       8:   
       9:      <remove verb="*" path="*.aspx"/>
      10:   
      11:      <add verb="*" path="*.aspx" type="AjaxPageHandler"/>
      12:   
      13:    </httpHandlers>
      14:   
      15:  </system.web>
      16:   
      17:  </configuration>

    Finally, Listing 7 contains a page that contains two declarations for client-side controls. The page contains the declaration for a control named MyControl and a control named Boom.

    Listing 7 – /AjaxPages/Page.aspx

       1:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       2:   
       3:  <html xmlns="http://www.w3.org/1999/xhtml" xmlns:Code="/MyControl.js" xmlns:Ajax="/Boom.js">
       4:   
       5:  <head runat="server">
       6:   
       7:    <title>Ajax Page</title>
       8:   
       9:  </head>
      10:   
      11:  <body>
      12:   
      13:  <div>
      14:   
      15:    <Code:MyControl id="ctl" text="Hello World!"></Code:MyControl>
      16:   
      17:    <Ajax:Boom id="boo1"></Ajax:Boom>
      18:   
      19:  </div>
      20:   
      21:  </body>
      22:   
      23:  </html>

    The page in Listing 7 is a valid XHTML page. Notice that the page’s document element contains three xmlns attributes. It has xmlns attributes for the following namespaces: http://www.w3.org/1999/xhtml, MyControl.js, and Boom.js. The last two namespaces do double duty as paths to client control libraries.

    Notice, furthermore, that the page contains the declarations for two client-side controls named MyControl and Boom. The declarations use the namespace prefixes from the xmlns attributes.

    When you request the page, the AjaxPageHandler HTTP Handler executes and parses the page. The rendered page in Listing 8 gets sent to the browser.

    Listing 8 – Page.aspx (rendered content)

       1:  <?xml version="1.0" encoding="utf-8"?>
       2:   
       3:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"[]>
       4:   
       5:  <html xmlns="http://www.w3.org/1999/xhtml" xmlns:Code="/MyControl.js" xmlns:Ajax="/Boom.js">
       6:   
       7:  <head runat="server">
       8:   
       9:  <title>Ajax Page</title>
      10:   
      11:  </head>
      12:   
      13:  <body>
      14:   
      15:  <div>
      16:   
      17:  <Code:MyControl id="ctl" text="Hello World!">
      18:   
      19:  </Code:MyControl>
      20:   
      21:  <Ajax:Boom id="boo1">
      22:   
      23:  </Ajax:Boom>
      24:   
      25:  </div>
      26:   
      27:  </body>
      28:   
      29:  <script type="text/javascript" src="/Code/Microsoft/MicrosoftAjax.js">
      30:   
      31:  </script>
      32:   
      33:  <script type="text/javascript" src="/Code/MyControl.js">
      34:   
      35:  </script>
      36:   
      37:  <script type="text/javascript" src="/Code/Boom.js">
      38:   
      39:  </script>
      40:   
      41:  <script type="text/javascript">
      42:   
      43:  //<![CDATA[
      44:   
      45:  Sys.Application.initialize();
      46:   
      47:  Sys.Application.add_init(function() {
      48:   
      49:  $create(Code.MyControl,null,null,null,$get('ctl'));
      50:   
      51:  $create(Ajax.Boom,null,null,null,$get('boo1'));
      52:   
      53:  });
      54:   
      55:  //]]>
      56:   
      57:  </script>
      58:   
      59:  </html>

    This seems like a great approach to solving the problem of declaring client-side controls. This solution appears to enable us to build “pure” client-side Ajax applications. Our lightweight pages do not shackle us to view state, the postback model, or the server-side page execution lifecycle.

    In fact, when I first started writing this blog entry (days ago), I thought that this solution would be the best solution. However, the devil is in the details. There are some real problems with this solution that you encounter as soon as your declarative controls get more complicated.

    You quickly encounter problems with the solution when working with Firefox. The problem is that Firefox interprets all of the custom control declarations using its tag soup processor. This processor mangles the tags in weird ways. You might have noticed that I declared the two tags in Listing 7 using explicit opening and closing tags:

    <Code:MyControl id="ctl" text="Hello World!">

    </Code:MyControl>

    <Ajax:Boom id="boo1">

    </Ajax:Boom>

    If, instead, I had declared the tags using self-closing tags, then the page would not have been interpreted correctly by Firefox:

    <Code:MyControl id="ctl" text="Hello World!" />

    <Ajax:Boom id="boo1" />

    The Firefox tag soup processor interprets the above tag declarations like this:

    <Code:MyControl id="ctl" text="Hello World!">

    <Ajax:Boom id="boo1"></Ajax:Boom>

    </Code:MyControl>

    Notice that the second tag has gotten gobbled up by the first tag. When you have a series of custom client-side controls in a row, they all get swallowed up by the first custom tag in the series.

    This problem might seem minor, but it gets more acute when you start adding multiple client-side tags to a page. Eventually, I want to be able to declare client-side controls that contain templates that contain multiple client-side controls. This will never happen if Firefox always insists on re-arranging all of my tags.

    There is a way to fix this problem when working with Firefox. You need to serve your pages as XHTML pages (using the "application/xhtml+xml" MIME type) instead of the normal text/html MIME type. When a page is served to Firefox using the "application/xhtml+xml" MIME type, Firefox does not use its normal tag soup processor. Instead, it uses its stricter XML parser to parse the page. No more garbling the page.

    You can serve pages to Firefox using the "application/xhtml+xml" MIME type by using the Global.asax file in Listing 9:

    Listing 9 – Global.asax

       1:  <%@ Application Language="C#" %>
       2:   
       3:  <script runat="server">
       4:   
       5:  void Application_PreSendRequestHeaders(object sender, EventArgs e)
       6:   
       7:  {
       8:   
       9:    HttpContext context = ((HttpApplication)sender).Context;
      10:   
      11:    if (context.Request.Path.ToLower().EndsWith(".aspx"))
      12:   
      13:    {
      14:   
      15:      if (Array.IndexOf(context.Request.AcceptTypes, "application/xhtml+xml") != -1)
      16:   
      17:      {
      18:   
      19:        context.Response.ContentType = "application/xhtml+xml";
      20:   
      21:      }
      22:   
      23:    }
      24:   
      25:  }
      26:   
      27:  </script>
      28:   

    Notice that the Global.asax file in Listing 9 only serves a page as XHTML when the browser accepts it. Microsoft Internet Explorer cannot handle XHTML pages – so don’t attempt to serve an XHTML page to this browser.

    Unfortunately, this solution introduces yet another problem. When a page is served as "application/xhtml+xml", you can no longer use the DOM getElementById() method with custom tags. Because the Microsoft AJAX Library $get() method is a shorthand for the getElementById() method, and we use the $get()method with the last parameter of the $create() method call, this means that our $create() method calls will no longer work. Drats!

    So, what do we do now? If we want to be able to use getElementById() with our declarative client-side controls, then we must replace the custom tags with standard XHTML tags. For example, we can replace any custom client-side tags, such as the Code:MyControl tag, with a standard XHTML DIV tag. If we perform this replacement, then getElementById() works again.

    We could modify our AjaxPageHandler HTTP Handler to perform this replacement on the server-side for us. However, at this point, I’m going to abandon the server-side approach to parsing declarative controls and turn to a client-side approach.

    Creating AJAX Controls: The Client-Side Approach

    The final solution for parsing client-side declarative controls that I want to examine in this blog entry is the client-side approach. When following this strategy, you perform all of your control parsing within your client-side JavaScript code.

    The basic idea is that you perform a DOM walk. You walk through all of the elements in a page and you execute a call to the $create() method whenever you encounter any custom tags. You can use the JavaScript library in Listing 10 to perform a DOM walk.

    Listing 10 – DomWalk.js

       1:  /// <reference name="MicrosoftAjax.js"/>
       2:   
       3:  Sys.Application.add_init( appInit );
       4:   
       5:  function appInit()
       6:   
       7:  {
       8:   
       9:    // Find Ajax controls
      10:   
      11:    var controls = [];
      12:   
      13:    var els = document.getElementsByTagName("*");
      14:   
      15:    var el;
      16:   
      17:    for (var i=0;i < els.length;i++)
      18:   
      19:    {
      20:   
      21:      el = els[i];
      22:   
      23:      if (isControl(el))
      24:   
      25:        controls.push( el ) ;
      26:   
      27:    }
      28:   
      29:    // Create controls
      30:   
      31:    for (var k=0;k < controls.length;k++)
      32:   
      33:    {
      34:   
      35:      el = controls[k];
      36:   
      37:      $create(Type.parse( getControlType(el) ), null, null, null, el);
      38:   
      39:    }
      40:   
      41:  }
      42:   
      43:  function isControl(el)
      44:   
      45:  {
      46:   
      47:    if (el.tagUrn)
      48:   
      49:      return true;
      50:   
      51:    if (el.namespaceURI && el.namespaceURI != "http://www.w3.org/1999/xhtml")
      52:   
      53:      return true;
      54:   
      55:    return false;
      56:   
      57:  }
      58:   
      59:  function getControlType(el)
      60:   
      61:  {
      62:   
      63:    return (el.tagUrn || el.namespaceURI) + "." + (el.localName || el.tagName);
      64:   
      65:  }
      66:   
      67:  Sys.Application.notifyScriptLoaded();

    The code in Listing 10 marches through all of the elements in a page searching for elements that are not part of the default XHTML namespace. Next, the code calls the $create() method for each of non-XHTML elements in order to instantiate a client-side control. The page in Listing 11 uses the DomWalk.js JavaScript library.

    Listing 11 – Way3.aspx

       1:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       2:   
       3:  <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ajax="Code">
       4:   
       5:  <head runat="server">
       6:   
       7:    <title>Way 3</title>
       8:   
       9:    <script type="text/javascript" src="Microsoft/MicrosoftAjax.js"></script>
      10:   
      11:    <script type="text/javascript" src="SuperControl.js"></script>
      12:   
      13:    <script type="text/javascript" src="DomWalk.js"></script>
      14:   
      15:    </head>
      16:   
      17:  <body>
      18:   
      19:  <div>
      20:   
      21:    <ajax:SuperControl id="ctl" />
      22:   
      23:  </div>
      24:   
      25:  </body>
      26:   
      27:  </html>

    There are three things that you should notice about the page in Listing 11. First, notice that the HTML document element includes an xmlns attribute that has the name ajax and the value Code. Next, notice that each of the required script libraries -- MicrosoftAjax.js, SuperControl.js, and DomWalk.js-- are manually imported with <script> tags. Finally, notice that the body of the page contains the declaration for a single control named the SuperControl.

    In order for the page in Listing 11 to work correctly, it must be served as an XHTML document to Firefox. In other words, you need the Global.asax file contained in Listing 9. One consequence of this requirement is that the page must be an aspx page instead of an html page (otherwise, the Global.asax file won’t execute when you request the page).

    The SuperControl is contained in Listing 12.

    Listing 12 – SuperControl.js

       1:  /// <reference name="MicrosoftAjax.js"/>
       2:   
       3:  Type.registerNamespace("Code");
       4:   
       5:  Code.SuperControl = function(element) {
       6:   
       7:    // create replacement element
       8:   
       9:    this.originalElement = element;
      10:   
      11:    element = document.createElement("div");
      12:   
      13:    element.id = this.originalElement.getAttribute("id");
      14:   
      15:    this.originalElement.parentNode.replaceChild(element,this.originalElement);
      16:   
      17:    Code.SuperControl.initializeBase(this, [element]);
      18:   
      19:    // add inner HTML
      20:   
      21:    element.innerHTML = "Super!";
      22:   
      23:  }
      24:   
      25:  Code.SuperControl.prototype = {
      26:   
      27:    initialize: function() {
      28:   
      29:      Code.SuperControl.callBaseMethod(this, 'initialize');
      30:   
      31:      // Add custom initialization here
      32:   
      33:    },
      34:   
      35:    dispose: function() {
      36:   
      37:      //Add custom dispose actions here
      38:   
      39:      Code.SuperControl.callBaseMethod(this, 'dispose');
      40:   
      41:    }
      42:   
      43:  }
      44:   
      45:  Code.SuperControl.registerClass('Code.SuperControl', Sys.UI.Control);
      46:   
      47:  if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
      48:   

    Notice that the constructor for the SuperControl includes logic to replace the original element (the ajax:SuperControl element) with a new element (a DIV element). There are two reasons why you need to do this. First, you cannot use document.getElementById() with a custom element like the ajax:SuperControl element. Second, innerHTML does not work with custom elements. If you want your custom controls to work like normal XHTML elements, then you need to replace them with normal XHTML elements.

    Conclusion

    So which approach is the best approach for parsing client-side Ajax controls? I’m leaning on the side of the client-side approach described in the last section. I have two reasons for preferring the client-side approach over the lightweight server-side approach.

    First, I know that I need to replace the custom elements that represent Ajax controls in a page with standard XHTML elements. Otherwise, I can’t interact with the controls as normal elements (getElementById() and innerHTML don’t work). I could perform this replacement on the server-side. However, I might want to dynamically inject controls into a page from JavaScript code. In that case, it would make more sense to parse the elements on the client-side.

    Imagine, for example, a client-side Login control. This is an example of a composite control. I would want to replace the ajax:Login element with a set of normal XHTML elements like DIV and INPUT elements. I don’t want to do these replacements in server-side code since I might want to add a Login control to a page from JavaScript code dynamically.

    Second, I don’t want to perform a getElementById() call for each element that I want to instantiate with the $create() method since the getElementById() method is notoriously slow. However, if I build my $create() method calls on the server-side, I don’t know of any way of avoiding calling getElementById() for each control. When rendering from the server, I am forced to represent an element with its Id string and not with the element itself.

    If, on the other hand, I perform the parsing on the client-side, then there are many ways of avoiding getElementById(): I can use getElementsByTagName(), I can use XPATH, I can perform an XSLT transformation, and so on. I don't know a priori which method is faster, but it seems like I have much more flexibility.