Enhancing the Sample Application


Now that you know how to define interfaces and how to implement the interfaces in a class, it's time to enhance the sample application. More specifically , you're going to add the class that serves as the custom module. To turn a class into a module the class has to implement the System.Web.IHttpModule interface. It's not very difficult to implement the interfaceit only has two methods : Init and Dispose. ASP.NET calls the Init method the very first time the module gets loaded into memory. It calls Dispose when the module is unloaded. The only hard part is that you'll have to use an event, and events are not discussed until Chapter 10, "Delegates and Events."

We're not going to spend too much time discussing what an event is in this chapter but for now it's enough to know that an event is a method that gets triggered as a result of an action. In many ways implementing an event is like implementing an interface except that an interface can have many methods where an event has only one method. An example of an event is the click event of a button. Your class can request to get a click event notification from a button on a form. When the user clicks the button the server lets your class know that the event has occurred. Modules can request to listen to the BeginRequest event, among others. ASP.NET triggers this event in your module whenever the client's browser requests a page.

To add a custom module class:

  1. Select Project > Add class from the menu bar. Type custommodule.cs for the class name and press Enter ( Figure 8.12 ).

    Figure 8.12. All the functionality for the custom module will go in the custommodule class. Use this dialog to have the wizard generate a skeleton for the class.

    graphics/08fig12.gif

  2. At the top of the code module below the line that reads using System; type using System.Web; .

  3. On the line that reads public class custommodule add : IHttpModule at the end so that it reads:

     public class custommodule : IHttpModule. 
  4. Now it's time to cheat a little. In Visual Studio .NET there's a wizard that lets you implement an interface easily. Select View > Class View from the menu bar.

  5. On the Class View window expand interfacesproject > interfacesproject > custommodule > Bases and Interfaces. Then right-click on IHttpModule and select Add > Implement Interface from the popup menu ( Figure 8.13 ).

    Figure 8.13. The implement interface wizard uses the implicit implementation mechanism; it adds public members for each of the members in the interface.

    graphics/08fig13.gif

  6. The wizard adds the method stubs for the Init and Dispose methods. Your code should look like the code in Figure 8.14 .

    Figure 8.14 The IHttpModule interface serves two purposes. One, it tells the ASP.NET framework that the class is in fact a custom module. Two, it gives the framework a way to tell the class when it is first loaded (Init method) and when it's no longer needed (Dispose method).
     using System; using System.Web; namespace interfacesproject {    /// <summary>    /// Summary description for custommodule.    /// </summary>    public class custommodule : IHttpModule    {      public custommodule()      {         //         // TODO: Add constructor logic here         //      }  #region Implementation of IHttpModule   public void Init(System.Web. HttpApplication context)   {   }   public void Dispose()   {   }   #endregion  } } 
  7. Add a method to the class called BeginRequest ( Figure 8.15 ).

    Figure 8.15 BeginRequest isn't part of the IHttpModule interface. It's an event in the HttpApplication class that tells you any time there's a request to any of the pages in your application.
     using System; using System.Web; namespace interfacesproject {    /// <summary>    /// Summary description for custommodule.    /// </summary>    public class custommodule : IHttpModule    {      public custommodule()      {         //         // TODO: Add constructor logic here         //      }      #region Implementation of IHttpModule      public void Init(System.Web.HttpApplication context)      {      }      public void Dispose()      {      }      #endregion  voie BeginRequest(object sender, EventArgs args)   {   }  } } 
  8. In the Init method add the code to connect the BeginRequest event to the BeginRequest method in your class ( Figure 8.16 ). Don't worry about understanding this code right now; it will be explained in Chapter 10, "Delegates and Events."

    Figure 8.16 Notice that to connect an event in a class to a method in your class you refer to the event as if it were a property of the object (object.eventname) then use the += operator and assign it a new object (a delegate) and pass your function as a parameter for the constructor of the object.
     using System; using System.Web; namespace interfacesproject {    //<summary>    //Summary description for custommodule.    //</summary>    public class custommodule :    HttpModule    {      public custommodule()      {      //      //TODO: Add constructor logic here      //      }      #region Implementation of IHttpModule      public void Init(System.Web.HttpApplication context)      {  context.BeginRequest +=   new EventHandler(BeginRequest);  }      public void Dispose()      {      }      #endregion      void BeginRequest(object sender,      EventArgs args)      {      }    } } 
  9. Add code to the Init method to build a string with the client-side script and save it in the Application object. Remember that the Application object is accessible to all the pages and to every client ( Figure 8.17 ).

    Figure 8.17 Ah, the beauty of literal strings. Notice that it's really easy to place carriage returns in a string using literal strings. You basically format the string as you want it, carriage returns and all.
     public void Init(System.Web.HttpApplication context) {    context.BeginRequest += new EventHandler(BeginRequest);  string html = @"   <html>   Loading...   <script language=vbscript>   Sub GetDimensions()   Dim clientWidth   Dim clientHeight   clientWidth = document.body.ClientWidth   clientHeight = document.body.ClientHeight   document.myform.txtDimensions.Value = clientWidth & "";"" & clientHeight &  "";""   document.myform.submit   End Sub   </script>   <body onLoad=""GetDimensions"">   <form name=""myform"" method=""POST"" action=""{0}"">   <p><input type=""hidden"" name=""txtDimensions""   size=""20""></p>   </form>   </body>   </html>";   context.Application["__DiscoverHTML"] = html;  } 
  10. Now add the code in Figure 8.18 to the BeginRequest method. The purpose of this code is to detect if dimension information is available. This information would be available through a hidden field. If the textbox doesn't exist, the module blocks the request to the page and sends back the client-side script. The script records the dimensions in a hidden field and immediately requests the page again. The module then sees that the textbox exists and adds the dimensions to the Item object (see sidebar on the next page for more information).

    Figure 8.18 There's a lot of code here that needs explanation. Refer to the "Walkthrough of BeginRequest Event" sidebar for details.
     void BeginRequest(object sender, EventArgs args) {  Global g = (Global)sender;   string dimensions =   g.Request.Form["txtDimensions"];   if (dimensions == null   dimensions == "" )   {   string html =   (string)g.Context.Application["__DiscoverHTML"];   string newUrl = string.Format(html,   g.Request.Url.AbsolutePath);   g.Response.Write(newUrl);   g.CompleteRequest();   }   else if (dimensions.IndexOf("ClientWidth")   == -1)   {   string[] sizes =   dimensions.Split(';');   int clientWidth =   System.Convert.ToInt32(sizes[0]);   int clientHeight =   System.Convert.ToInt32(sizes[1]);   g.Context.Items["__ClientWidth"] =   clientWidth;   g.Context.Items["__ClientHeight"] =   clientHeight;   }  } 

graphics/tick.gif Tips

  • The code in this section is all the code you need to have a custom module. However, the module does not take effect until you finish the example later in this chapter.

  • The wizard that implements interfaces adds #region Implementation of IHttpModule at the beginning of the implementation methods and #endregion at the end. These statements don't affect the compiler directly; they just provide a way for you to have a collapsible code region in the editor. If you notice in the editor you will see a minus sign to the left of the region declaration ( Figure 8.19 ); if you click the minus sign then the editor will hide the code within the region, and turn the minus to a plus ( Figure 8.20 ). Clicking the plus makes the code reappear.

    Figure 8.19. The #region statement adds a region of collapsible code. When the editor detects the #region directive it adds a minus sign on the left edge of the code window.

    graphics/08fig19.gif

    Figure 8.20. Clicking the minus collapses the code within the region and displays the description after the word #region so that you can identify the code. The #region doesn't add any functionality to the code, it's just for the editor, and you can delete it if you don't like it.

    graphics/08fig20.gif


Walkthrough of BeginRequest Event

If you look at the first line in the BeginRequest function there is a cast of the sender object (the function's first parameter) into a Global object. Global is a class that the wizard generates when you create an ASP.NET project. It's derived from HttpApplication. This class gets created the first time any client accesses any page in your application. From the Global object you can access other objects like the Response and Request object.

If you look at the second line of code, you'll see that we use the Global object to get the Request object. As you may remember, Request lets you access information about the client's request. If you use the Form property, you can access the hidden field that gets created in the client-side script. The name of the hidden field is txtDimensions.

The line g.Request.Form["txtDimensions"] retrieves the text of the hidden field. If the field doesn't exist then the result will be null. If it does then the result will be the coordinates of the client area. The client-side script saves the coordinates as width;height; (800;600; for example). If the result is null then the code uses Response.Write to send the client-side script to the client. Then the code calls CompleteRequest which stops the client's request from going all the way to the page that was requested . If we didn't do this, our client-side script would be combined with the output from the page. If the dimensions are available, we split the string in the format width;height; into two values and convert to integers. Then we place the values in the Items object.

We haven't used the Items object before, but it's a lot like the Session object and the Application object. Basically it's another way to persist information; the difference is that the information is only available for the duration of one client request. With the Application object information is saved for as long as the Web server is running your application and it's accessible to any client using the application. Session information is persisted also for the duration of the program, but the information in Session is specific to each client. The Items object only lasts for one request. So if the client navigates from one page to another, the information is lost. However, within the same request, our module can put information in Items and then our page can retrieve it. You reach the Items object through g.Context.Items.



C#
C# & VB.NET Conversion Pocket Reference
ISBN: 0596003196
EAN: 2147483647
Year: 2003
Pages: 198
Authors: Jose Mojica

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net