Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1271 Chapter 26: User and Server Controls DesignerActionTextItem is added to the collection (see Figure 26-18). The DesignerActionTextItem class allows you to add text menu items to the smart tag. Figure 26-18 As shown in Figure 26-18, when you add the control to a Web page, the control now has a smart tag with the DesignerActionTextItem class as content. UI Type Editors A UI type editor is a way to provide users of your controls with a custom interface for editing properties directly from the Property Browser. One type of UI type editor you might already be familiar with is the Color Picker you see when you want to change the ForeColor attribute that exists on most ASP.NET con- trols. ASP.NET provides a wide variety of in-box UI type editors that make it easy to edit more complex property types. The easiest way to find what UI type editors are available in the .NET Framework is to search for types derived from the UITypeEditor class in the MSDN Library help. After you find the type editor you want to use on your control property, you simply apply the UI Type Editor to the property using the Editor attribute. Listing 26-45 shows how to do this. 1271 Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1272 Chapter 26: User and Server Controls Figure 26-19 Listing 26-45: Adding a UI type editor to a control property VB <Bindable(True), Category("Appearance"), DefaultValue(""), _ Editor( _ GetType(System.Web.UI.Design.UrlEditor), _ GetType(System.Drawing.Design.UITypeEditor)) > _ Public Property Url() As String Get Return _url End Get Set(ByVal value As String) _url = value End Set End Property C# [Bindable(true)] [Category("Appearance")] [DefaultValue("")] [Editor(typeof(System.Web.UI.Design.UrlEditor), typeof(System.Drawing.Design.UITypeEditor))] public string Url { get { return url; } 1272 Evjen c26.tex V2 - 01/28/2008 3:48pm Page 1273 Chapter 26: User and Server Controls set { url = value; } } In this sample, you have created a Url property for a control. Because you know this property will be a URL, you want to give the control user a positive design-time experience. You can use the UrlEditor type editor to make it easier for users to select a URL. Figure 26-19 shows the Url Editor that appears when the user edits the control property. Summary In this chapter, you learned a number of ways you can create reusable, encapsulated chunks of code. You first looked at user controls, the simplest form of control creation. You learned how to create user controls and how you can make them interact with their host Web pages. Creating user controls is quite easy, but they lack the portability of other control-creation options. Then, you saw how you can create your own custom server controls. You looked at many of the tools you can create by writing custom server controls. These range from tools for emitting HTML and creating CSS styles and JavaScript to those applying themes. The chapter also discussed the type of server controls you can create, ranging from server controls that simply inherit from the WebControl class to templated controls that give users of the control the power to define the display of the server control. Finally, you looked at ways you can give the users of your server control a great design-time experience by providing them with TypeConvertors, design surface interactions, and custom property editors in your server control. 1273 Evjen c27.tex V2 - 01/28/2008 3:51pm Page 1275 Modules and Handlers Sometimes, just creating dynamic Web pages with the latest languages and databases does not give you, the developer, enough control over an application. At times, you need to be able to dig deeper and create applications that can interact with the Web server itself. You want to be able to interact with the low-level processes, such as how the Web server processes incoming and outgoing HTTP requests. Before ASP.NET, to get this level of control using IIS, you were forced to create ISAPI extensions or filters. This proved to be quite a daunting and painful task for many developers because creat- ing ISAPI extensions and filters required knowledge of C/C++ and knowledge of how to create native Win32 DLLs. Thankfully, in the .NET world, creating these types of low-level applications is really no more difficult than most other tasks you would normally perform. This chapter looks at two methods of manipulating how ASP.NET processes HTTP requests, the HttpModule, and the HttpHandler. Each method provides a unique level of access to the underlying processing of ASP.NET and can be a powerful tool for creating Web applications. Processing HTTP Requests Before starting to write Handlers or Modules, it’s helpful to know how IIS and ASP.NET normally process incoming HTTP requests and what options you have for plugging custom logic into those requests. IIS is the basic endpoint for incoming HTTP requests. At a very high level, its job is to listen for and validate incoming HTTP requests. Then it routes them to the appropriate module for processing and returns any results to the original requestor. ASP.NET is one of t he modules that IIS may pass requests to for processing. However, exactly how that processing happens and how you can integrate your own logic into the pipeline differs based on the version of IIS you are using. IIS 5/6 and ASP.NET If you are using IIS 5 or IIS 6, the HTTP request processing pipeline is fairly black box to a managed code developer. IIS basically treats ASP.NET as one of the modules that it can pass requests to for Evjen c27.tex V2 - 01/28/2008 3:51pm Page 1276 Chapter 27: Modules and Handlers processing rather than as an integrated part of the IIS request processing pipeline. Figure 27-1 shows the basic request processing pipeline of IIS 5/6 and ASP.NET. Figure 27-1 As you can see, the IIS and ASP.NET request pipelines are very similar and several tasks, such as authentication, are even duplicated between the two pipelines. Furthermore, while you can write Handlers and Modules using managed code, they are still processed in the isolated context of the ASP.NET process. If you wanted to integrate deeper into the IIS pipeline you are forced to create modules using native code. IIS 7 and ASP.NET Starting with IIS 7, the request processing pipeline in IIS has been completely re-architected using an open and highly extensible module based system. Now, instead of IIS seeing ASP.NET as a separate entity, ASP.NET has been deeply integrated into the IIS request processing pipeline. As shown in Figure 27-2, the request processing pipeline has been streamlined to eliminate duplicate processes and to allow you to integrate managed modules in the pipeline. Because ASP.NET modules are first-class citizens, you can place them at any point in the pipeline, or even completely replace existing modules with your own custom functionality. Features that previously required you to write custom ISAPI modules in unmanaged code can now simply be replaced by managed code modules containing your logic. If you are interested in learning more 1276 Evjen c27.tex V2 - 01/28/2008 3:51pm Page 1277 Chapter 27: Modules and Handlers about the integration of ASP.NET and IIS 7, check out the Wrox title Professional IIS 7 and ASP.NET Integrated Programming by Shahram Khosravi (Wiley Publishing, Inc., 2007). Figure 27-2 ASP.NET Request Processing Regardless of the IIS version, the basic HTTP request pipeline model has two core mechanisms for handling requests: HttpModules and HttpHandlers. ASP.NET uses those two mechanisms to process incoming ASP.NET requests, generate a response, and return that response to the client. In fact, you are probably already familiar with HttpModules and HttpHandlers — although you might not know it. If you have ever used the Inbox caching or the authentication features of ASP.NET, you have used several different HttpModules. Additionally, if you have ever served up an ASP.NET application, even something as simple as a Hello World Web page and viewed it in a browser, you have used an HttpHandler. ASP.NET uses handlers to process and render ASPX pages and other file extensions. Modules and handlers allow you to plug into the request-processing pipeline at different points and interact with the actual requests being processed by IIS. As you can see in both Figures 27-1 and 27-2, ASP.NET passes each incoming request through a layer of preprocessing HttpModules in the pipeline. ASP.NET allows multiple modules to exist in the pipeline for each request. After the incoming request has passed through each module, it is passed to the HttpHandler, which serves the request. Notice that although a single request may pass through many different modules, it can be processed by one handler only. The handler is generally responsible for creating a response to the incoming HTTP request. After the handler has completed execution and generated a response, the response is passed back thro ugh a series of post-processing modules, before it is returned to the client. 1277 Evjen c27.tex V2 - 01/28/2008 3:51pm Page 1278 Chapter 27: Modules and Handlers You should now have a basic understanding of the IIS and ASP.NET request pipeline — and how you can use HttpModules and HttpHandlers to interact with the pipeline. The following sections take an in-depth look at each of these. HttpModules HttpModules are simple classes that can plug themselves into the request-processing pipeline. They do this by hooking into a handful of events thrown by the application as it processes the HTTP request. To create an HttpModule, you simply create a class that derives from the System.Web.IHttpModule interface. This interface requires you to implement two methods: Init and Dispose . Listing 27-1 shows the class stub created after you implement the IHttpModule interface. Listing 27-1: Implementing the IHttpModule Interface VB Imports Microsoft.VisualBasic Imports System.Web Namespace Demo Public Class SimpleModule Implements IHttpModule Public Overridable Sub Init(ByVal context As HttpApplication) _ Implements IHttpModule.Init End Sub Public Overridable Sub Dispose() Implements IHttpModule.Dispose End Sub End Class End Namespace C# using System; using System.Collections.Generic; using System.Text; using System.Web; namespace Demo { class SimpleModule : IHttpModule { #region IHttpModule Members public void Dispose() { throw new Exception("The method or operation is not implemented."); } 1278 Evjen c27.tex V2 - 01/28/2008 3:51pm Page 1279 Chapter 27: Modules and Handlers public void Init(HttpApplication context) { throw new Exception("The method or operation is not implemented."); } #endregion } } The Init method is the primary method you use to implement functionality. Notice that it has a single method parameter, an HttpApplication object named context . This parameter gives you access to the current HttpApplication context, and it is what you use to wire up the different events that fire during the request processing. The following table shows the events that you can register in the Init method. Event Name Description AcquireRequestState Raised when ASP.NET runtime is ready to a cquire the Session State of the current HTTP request. AuthenticateRequest Raised when ASP.NET runtime is ready to authenticate the identity of the user. AuthorizeRequest Raised when ASP.NET runtime is ready to authorize the user for the resources user is t rying to access. BeginRequest Raised when ASP.NET runtime receives a new HTTP request. Disposed Raised when ASP.NET completes the processing of HTTP request. EndRequest Raised just before sending the response content to the client. Error Raised when an unhandled exception occurs during the processing of HTTP request. PostRequestHandlerExecute Raised just after HTTP handler finishes execution. PreRequestHandlerExecute Raised just before ASP.NET begins executing a handler for the HTTP request. After this event, ASP.NET forwards the request to the appropriate HTTP handler. PreSendRequestContent Raised just before ASP.NET sends the response contents to the client. This event allows you to change the contents before it gets delivered to the client. You can use this event to add the contents, which are common in all pages, to the page output. For example, a common menu, header, or footer. PreSendRequestHeaders Raised just before ASP.NET sends the HTTP response headers to the client. This event allows you to change the headers before they get delivered to the client. You can use this event to add cookies and custom data into headers. 1279 Evjen c27.tex V2 - 01/28/2008 3:51pm Page 1280 Chapter 27: Modules and Handlers Modifying HTTP Output Take a look at some examples of using HttpModules. The first example shows a useful way of modifying the HTTP output stream before it is sent to the client. This can be a simple and useful tool if you want to add text to each page served from your Web site, but you do not want to modify each page. For the first example, create a Web project in Visual Studio and add a class to the App_Code directory. The code for this first module is shown in Listing 27-2. Listing 27-2: Altering the output of an ASP.NET Web page VB Imports Microsoft.VisualBasic Imports System.Web Namespace Demo Public Class AppendMessage Implements IHttpModule Dim WithEvents _application As HttpApplication = Nothing Public Overridable Sub Init(ByVal context As HttpApplication) _ Implements IHttpModule.Init _application = context End Sub Public Overridable Sub Dispose() Implements IHttpModule.Dispose End Sub Public Sub context_PreSendRequestContent(ByVal sender As Object, _ ByVal e As EventArgs) Handles _application.PreSendRequestContent ’alter the outgoing content by adding a HTML comment. Dim message As String = " < ! This page has been post processed at"&_ System.DateTime.Now.ToString() & _ " by a custom HttpModule > " _application.Context.Response.Output.Write(message) End Sub End Class End Namespace C# using System; using System.Collections.Generic; using System.Text; using System.Web; namespace Demo { public class AppendMessage : IHttpModule 1280 Evjen c27.tex V2 - 01/28/2008 3:51pm Page 1281 Chapter 27: Modules and Handlers { private HttpContext _current = null; #region IHttpModule Members public void Dispose() { throw new Exception("The method or operation is not implemented."); } public void Init(System.Web.HttpApplication context) { _current = context.Context; context.PreSendRequestContent += new EventHandler(context_PreSendRequestContent); } void context_PreSendRequestContent(object sender, EventArgs e) { //alter the outgoing content by adding a HTML comment. string message = " < ! This page has been post processed at " + System.DateTime.Now.ToString() + " by a custom HttpModule > "; _current.Response.Output.Write(message); } #endregion } } You can see that the class stub from Listing 27-2 is expanded here. In the Init method, you register the PreSendRequestContent event. This event fires right before the content is sent to the client, and you have one last opportunity to modify it. In the PreSendRequestContent handler method, you simply create a string containing an HTML com- ment that contains the current time. You take this string and write it to the current HTTP requests output stream. The HTTP request is then sent back to the client. In order to use this module, you must let ASP.NET know that you want to include the module in the request-processing pipeline. You do this is by modifying the web.config to contain a reference to the module. Listing 27-3 shows how you can add an httpModules section to your web.config . Listing 27-3: Adding the httpModule configuration to web.config < configuration > < system.web > < httpModules > < add name="AppendMessage" type="Demo.AppendMessage, App_code" / > < /httpModules > < /system.web > < /configuration > 1281 . 01/28/2008 3: 51 pm Page 1278 Chapter 27: Modules and Handlers You should now have a basic understanding of the IIS and ASP. NET request pipeline — and how you can use HttpModules and HttpHandlers to interact. Modules and Handlers about the integration of ASP. NET and IIS 7, check out the Wrox title Professional IIS 7 and ASP. NET Integrated Programming by Shahram Khosravi (Wiley Publishing, Inc., 2007). Figure. integrated part of the IIS request processing pipeline. Figure 27-1 shows the basic request processing pipeline of IIS 5/ 6 and ASP. NET. Figure 27-1 As you can see, the IIS and ASP. NET request pipelines