Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Design Patterns for ASP.NET Developers, Part 1: Basic Patterns : Page 5

Most Design Pattern documentation targets desktop applications or discusses pattern theory, but in this series you'll find a discussion and examples of patterns specifically targeted at ASP.NET.


advertisement

Implementing the Repository Pattern
A data repository that implements the Repository pattern can provide dependency-free access to data of any type. For example, developers might create a class that reads user information from Active Directory, and exposes it as a series of User objects—each having properties such as Alias, EmailAddress, and PhoneNumber. The repository may also provide features to iterate over the contents, find individual users, and manipulate the contents.

Third-party tools are available to help developers build repositories, such as the CodeSmith tools library. Visual Studio includes the tools to generate a typed DataSet that can expose values as properties, rather than as data rows, and this can form the basis for building a repository.

As a simple example, the sample application uses a typed DataSet (CustomerRepository.xsd in the App_Code folder), which is populated from the Customers table in the Northwind database. The DataSet Designer in Visual Studio automatically implements the Fill and GetData methods within the class, and exposes objects for each customer (CustomersRow) and for the whole set of customers (CustomersDataTable).

The class CustomerRepositoryModel.cs in the App_Code folder exposes data from the typed DataSet, such as the GetCustomerList method that returns a populated CustomersDataTable instance, and the GetCustomerName method that takes a customer ID and returns that customer's name as a String:

   public class CustomerRepositoryModel
   {
   
      public CustomerRepository.CustomersDataTable GetCustomerList()
      {
         // get details from CustomerRepository typed DataSet
         try
         {
            CustomersTableAdapter adapter = new 
               CustomersTableAdapter();
            return adapter.GetData();
         }
         catch (Exception ex)
         {
            throw new Exception(
               "ERROR: Cannot access typed DataSet", ex);
         }
      }
   
      public String GetCustomerName(String custID)
      {
         // get details from CustomerRepository typed DataSet
         try
         {
            if (custID.Length < 5)
            {
               custID = String.Concat(custID, "*");
            }
            CustomerRepository.CustomersDataTable customers = 
               GetCustomerList();
            // select row(s) for this customer ID
            CustomerRepository.CustomersRow[] rows = 
               (CustomerRepository.CustomersRow[])customers.Select(
               "CustomerID LIKE '" + custID + "'");
            // return the value of the CompanyName property
            return rows[0].CompanyName;
         }
         catch (Exception ex)
         {
            throw new Exception(
               "ERROR: Cannot access typed DataSet", ex);
         }
      }
   }

Implementing the Singleton Pattern
The sample application uses the Front Controller pattern to allow users to specify the required View using a short and memorable name. The Front Controller, described in detail in a later section, relies on an XML file that maps the visible short and memorable names to the actual URLs for this view. To expose the XML document's content to the Front Controller code, the application uses a Singleton instance of the class named TransferUrlList.cs (in the App_Code folder).

This approach provides good performance, because the class is loaded at all times and the Front Controller has only to call a static method to get a reference to the single instance, then call the method that translates the memorable name into a URL.

To implement the Singleton pattern, the class contains a private default constructor (a constructor that takes no parameters), which prevents the compiler from adding a default public constructor. This also prevents any classes or code from calling the constructor to create an instance.

The TransferUrlList class also contains a static method that returns the single instance, creating and populating it from the XML file if there is no current instance. The class uses static local variables to store a reference to the instance, and—in this example—to hold a StringDictionary containing the list of URLs loaded from the XML file:



   // Singleton class to expose a list of URLs for
   // Front Controller to use to transfer to when 
   // special strings occur in requested URL
   public class TransferUrlList
   {
      private static TransferUrlList instance = null;
      private static StringDictionary urls;
   
      private TransferUrlList()
      // prevent code using the default constructor by 
      // making the construtor private
      { }
   
      public static TransferUrlList GetInstance()
      // public static method to return single instance of class
      {
         // see if instance already created
         if (instance == null)
         {
            // create the instance
            instance = new TransferUrlList();
            urls = new StringDictionary();
            String xmlFilePath = HttpContext.Current.Request.MapPath(
               @"~/xmldata/TransferURLs.xml");
            // read list of transfer URLs from XML file
            try
            {
               using (XmlReader reader = 
                  XmlReader.Create(xmlFilePath))
               {
                  while (reader.Read())
                  {
                     if (reader.LocalName == "item")
                     {
                        // populate StringDictionary
                        urls.Add(reader.GetAttribute("name"), 
                           reader.GetAttribute("url"));
                     }
                  }
               }
            }
            catch (Exception ex)
            {
              throw new Exception(
                 "Cannot load URL transfer list", ex);
            }
         }
         return instance;
      }
      ...
   }   

A StringDictionary provides good performance, as the method that searches for a matching name and URL in the list can use the ContainsKey method, and then access the matching value using an indexer. If there is no match, the code returns the original value without translating it. The following code shows the GetTransferUrl method that performs the URL translation:

   public String GetTransferUrl(String urlPathName)
   // public method to return URL for a specified name
   // returns original URL if not found
   {
      if (urls.ContainsKey(urlPathName))
      {
         return urls[urlPathName];
      }
      else
      {
         return urlPathName;
      }
   }

To use the TransferUrlList Singleton class, code in the Front Controller just has to get a reference to the instance, and then call the GetTransferUrl method with the URL to translate as the value of the single parameter:

   ...
   // get Singleton list of transfer URLs 
   TransferUrlList urlList = TransferUrlList.GetInstance();
   // see if target value matches a transfer URL
   // by querying the list of transfer URLs
   // method returns the original value if no match 
   String transferTo = urlList.GetTransferUrl(reqTarget);
   ...

That completes this installment. Part 2 will discuss Controller Patterns for ASP.NET.



Alex Homer is a director of Stonebroom, Ltd., a software development, consulting, and training organization. He was formerly lead technical author and reviewer for Wrox, specializing in Microsoft Web and database technologies. You can reach him through his Web site.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap