Finally, you create a new module that parses the request path and rewrites the URL to the page you want to execute.. _application.Context.Request.Path.LastIndexOf"//" ; //Here is where w
Trang 1The generic format of the httpModules section is
<httpModules>
<add name="modulename" type="namespace.classname, assemblyname" />
</httpModules>
If you are deploying your application to an IIS 7 server, you must also add the module configuration to
the <system.webServer> configuration section.
<modules>
<add name="AppendMessage" type="Demo.AppendMessage, App_code"/>
</modules>
If you have created your HttpModule in theApp_Codedirectory of an ASP.NET web site, you might
wonder how you know what theassemblynamevalue should be, considering ASP.NET now dynamically
compiles this code at runtime The solution is to use the textApp_Codeas the assembly name This tells
ASP.NET that your module is located in the dynamically created assembly
You can also create HttpModules as a separate class library in which case you simply use the assembly
name of the library
After you have added this section to yourweb.configfile, simply view one of the Web pages from your
project in the browser When you view the page in the browser, you should not notice any difference
But if you view the source of the page, notice the comment you added at the bottom of the HTML
Figure 27-3 shows what you should see when you view the page source
Figure 27-3
1282
Trang 2URL Rewriting
Another interesting use of an HttpModule is to perform URL rewriting URL rewriting is a technique that
allows you to intercept the HTTP request and change the path that was requested to an alternative one This can be very useful for creating pseudo Web addresses that simplify a URL for the user For example, the MSDN Library is well known for its extremely long and cryptic URL paths, such as
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/
frlrfSystemWebIHttpModuleClassTopic.asp
The problem with this URL is that it is not easy to remember; and even if you do somehow remember it,
it is very difficult to type into the browser’s Address field URL rewriting allows you to create friendly
URLs that you can parse and redirect to the appropriate resource The MSDN Library now uses URL
rewriting to create friendly URLs Instead of the cryptic URL you saw previously, you can now use the following URL to access the same resource:
http://msdn2.microsoft.com/library/system.web.ihttpmodule.aspx
This URL is much shorter, easier to remember, and easier to type into a browser’s Address field You can create your own URL rewriter module to learn how this is done
To demonstrate this, you create three new Web pages in your project The first Web page is used to con-struct a URL using two text boxes The second serves as the page that accepts the unfriendly querystring, like the MSDN URL shown previously The third page is used to trick IIS into helping you serve the
request Shortly, we talk about this trick and how to get around it
Listing 27-4 shows the first Web page you add to the project; it’s calledfriendlylink.aspx
Listing 27-4: The friendlylink.aspx Web page
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<a href="John/Smith/trickiis.aspx">Click this friendly link</a>
</div>
</form>
</body>
</html>
As you can see, you simply created a hyperlink that links to a friendly, easily remembered URL
Now, create the second page calledunfriendly.aspx This is the page that the handle actually executes when a user clicks the hyperlink in thefriendlylink.aspxpage Listing 27-5 shows how to create
unfriendly.aspx
Listing 27-5: The unfriendly.aspx Web page
VB
<%@ Page Language="VB" %>
Continued
Trang 3<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load Label1.Text = Request("firstname").ToString() & _
" " & Request("lastname").ToString() End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Unfriendly Web Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Welcome to the unfriendly URL page <asp:Label ID="Label1"
runat="server" Text="Label"></asp:Label>
</div>
</form>
</body>
</html>
C#
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = Request["firstname"].ToString() +
" " + Request["lastname"].ToString();
}
</script>
Next, you create the directory and file that the hyperlink infriendlyurl.aspxpoints to
Thetrickiis.aspxpage can simply be an empty Web page because you are not really going to
execute it
Finally, you create a new module that parses the request path and rewrites the URL to the page you want
to execute To do this, create another class in theApp_Codedirectory calledSimpleRewriter Listing 27-6
shows the code for this
Listing 27-6: A sample URL rewriting HttpModule
VB
Imports Microsoft.VisualBasic
Imports System.Web
Namespace Demo
Public Class SimpleRewriter
Implements System.Web.IHttpModule
Dim WithEvents _application As HttpApplication = Nothing
Public Overridable Sub Init(ByVal context As HttpApplication) _
Implements IHttpModule.Init _application = context
End Sub
1284
Trang 4Public Overridable Sub Dispose() Implements IHttpModule.Dispose
End Sub
Public Sub context_BeginRequest(ByVal sender As Object, _
ByVal e As EventArgs) Handles _application.BeginRequest
Dim requesturl As String = _
_application.Context.Request.Path.Substring(0, _ _application.Context.Request.Path.LastIndexOf("/"c))
’Here is where we parse the original request url to determine
’ the querystring parameters for the unfriendly url
Dim parameters() As String = _
requesturl.Split(New [Char]() {"/"c}, _ StringSplitOptions.RemoveEmptyEntries)
If (parameters.Length > 1) Then
Dim firstname As String = parameters(1) Dim lastname As String = parameters(2)
’Rewrite the request path _application.Context.RewritePath("~/unfriendly.aspx?firstname=" & _ firstname & "&lastname=" & lastname)
End If
End Sub
End Class
End Namespace
C#
using System.Web;
namespace Demo
{
public class SimpleRewriter: System.Web.IHttpModule
{
HttpApplication _application = null;
public void Init(HttpApplication context)
{
context.BeginRequest+=new System.EventHandler(context_BeginRequest);
_application = context;
}
public void Dispose()
{
}
private void context_BeginRequest(object sender, System.EventArgs e)
{
string requesturl =
_application.Context.Request.Path.Substring(0,
Continued
Trang 5_application.Context.Request.Path.LastIndexOf("//") );
//Here is where we parse the original request url to determine //the querystring parameters for the unfriendly url
string[] parameters = requesturl.Split(new char[] {’/’});
if (parameters.Length > 1)
{ string firstname = parameters[1];
string lastname = parameters[2];
//Rewrite the request path _application.Context.RewritePath("~/unfriendly.aspx?firstname=" + firstname + "&lastname=" + lastname);
} } }
}
As you can see from the listing, in this sample you use the BeginRequest event in the HttpModule to
parse the incoming HTTP request path and create a new URL that you execute Normally, when you
click the hyperlink onfriendlyurl.aspx, an HTTP request is sent to the server for execution and then
IIS returns the page asked for in the hyperlink In this case, you make a request for this page:
http://localhost:1234/WebProject1/John/Smith/trickiis.aspx
But, because you put the HttpModule in the request-processing pipeline, you can modify the HTTP
request and change its behavior The code in theBeginRequestmethod of the module parses the request
path to create a querystring that theunfriendly.aspxpage can understand and execute So when you
execute the code in the listing, you convert the original path into the following:
http://localhost:1234/WebProject1/unfriendly.aspx?var1=John&var2=Smith
This URL is, as the page name states, not very friendly; and the user is less likely to remember and be
able to type this URL Finally, the module uses theRewritePathmethod to tell ASP.NET that you want
to rewrite the path to execute for this request
After you have completed creating the code for this sample, try loadingfriendlylink.aspxinto a
browser When you click the hyperlink on the page, you should notice two things First, notice that the
URL in the browser’s address bar shows that you have been served the page you requested,
trickiis.aspx, but the contents of the page show that you are actually servedunfriendly.aspx
Figure 27-4 shows what the browser looks like
IIS WildCards
There is, however, a drawback to this type of URL rewriting When IIS receives a request to serve a
resource, it first checks to see if the resource exists If the resource does exist, the request is passed to the
appropriate handler; in this case, the handler is ASP.NET, which processes the request IIS then returns
the results to the client However, if the requested resource does not exist, IIS returns a404 File Not
Founderror to the client It never hands the request to ASP.NET In order for a module to execute, you
must create an endpoint that actually exists on the Web server
1286
Trang 6Figure 27-4
In the case of the previous example, you had to actually create the/WebProject1/John/Smith/
trickiis.aspxpath so that IIS would know which handler to give the request to Had you not
cre-ated the path, IIS would have simply returned a 404 error Unfortunately, having to create the physical paths can be a problem if you find you are creating a large number of directories or resources just to
enable URL rewriting Thankfully, however, a solution to this problem exists in IIS: wildcards Wildcards
allow you to tell IIS that it should use a particular handler to process all incoming requests, regardless of the requested paths or file extensions In the previous example, adding a wildcard would keep you from having to actually create the dummy end point for the module
Adding Wildcards in IIS 5
To add a wildcard mapping in IIS 5, start by opening the IIS Management Console After the console
is open, right-click on the Web site or virtual directory you want to modify and select the Properties
option from the context menu When the Properties dialog box opens, select the Configuration button
from the Home Directory Tab The Configuration dialog is where you can create new or modify existing application extension mappings If you take a moment to look at the existing mappings, you see that
most of the familiar file extensions (such as.aspx,.asp, and.html) are configured
To add the wildcard that you need to create a new mapping, click the Add button The Add Application Extension Mapping dialog box is shown in Figure 27-5 You create a mapping that directs IIS to use the ASP.NET ISAPI DLL to process every incoming request To do this, simply put the full path to the ISAPI DLL (usually something such asC:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll)
in the Executable field For the extension, simply use *, which indicates any file extension
Additionally, you uncheck the Check That File Exists check box to tell IIS not to check whether the
requested file exists before processing (because you know that it doesn’t)
Now you don’t have to add the stub file to your Web site IIS will pass any request that it receives to
ASP.NET for processing, regardless of whether the file exists
Adding Wildcards in IIS 6
Adding Wildcards in IIS 6 is similar to adding wildcards in IIS 5 Open the IIS Management Console, and then open the Properties dialog box for the Web site or virtual directory you want to modify Next, click the Configuration button on the Home Directory tab
Trang 7Figure 27-5
The Application Extension Configuration dialog in IIS is slightly different Wildcard application maps
now have their own separate listing, as shown in Figure 27-6
To add a wildcard mapping, click the Insert button, add the path to the ASP.NET ISAPI DLL, and make
sure the Verify That File Exists check box is unchecked
Figure 27-6
1288
Trang 8HttpHandlers differ from HttpModules, not only because of their positions in the request-processing
pipeline (refer to Figure 27-3), but also because they must be mapped to a specific file extension Handlers are the last stop for incoming HTTP requests and are ultimately the point in the request-processing
pipeline that is responsible for serving up the requested content, be it an ASPX page, HTML, plain text,
or an image Additionally, HttpHandlers can offer significant performance gains
In this section, we demonstrate two different ways to create a simple HttpHandler that you can use to
serve up dynamic images First, you look at creating an HttpHandler using an ASHX file extension
Then you learn how you get even more control by mapping your HttpHandler to a custom file extension using IIS
Generic Handlers
In early versions of Visual Studio, HttpHandlers were somewhat hard to understand and create because little documentation was included to help developers understand handlers In addition Visual Studio did not provide any friendly methods for creating them
Since Visual Studio 2005 however this has changed with Visual Studio now providing a standard
template for HttpHandlers to help you get started To add an HttpHandler to your project, you
simply select the Generic Handler file type from the Add New Item dialog Figure 27-7 shows this dialog box with the file type selected
Figure 27-7
Trang 9You can see that when you add the Generic Handler file to your project, it adds a file with an.ashx
extension The.ashxfile extension is the default HttpHandler file extension set up by ASP.NET
Remem-ber that HttpHandlers must be mapped to a unique file extension, so by default ASP.NET uses the.ashx
extension This is convenient because, otherwise, you would be responsible for adding the file extension
yourself This is obviously not always possible, nor is it practical Using the Custom Handler file type
helps you avoid any extra configuration
Notice the class stub that the file type automatically creates for you Listing 27-7 shows the class
Listing 27-7: The HttpHandler page template
VB
<%@ WebHandler Language="VB" Class="Handler" %>
Imports System.Web
Public Class Handler
Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest context.Response.ContentType = "text/plain"
context.Response.Write("Hello World") End Sub
Public ReadOnly Property IsReusable() As Boolean _
Implements IHttpHandler.IsReusable Get
Return False End Get
End Property
End Class
C#
<%@ WebHandler Language="C#" Class="Handler" %>
using System.Web;
public class Handler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
}
public bool IsReusable {
get { return false;
} }
}
1290
Trang 10Notice that the stub implements the IHttpHandler interface, which requires theProcessRequestmethod andIsReusableproperty TheProcessRequestmethod is the method we use to actually process the
incoming HTTP request By default, the class stub changes the content type to plain and then writes
the"Hello World"string to the output stream TheIsReusableproperty simply lets ASP.NET know if
incoming HTTP requests can reuse the sample instance of this HttpHandler
By default, this handler is ready to run right away Try executing the handler in your browser and see
what happens The interesting thing to note about this handler is that because it changes the content to text/plain, browsers handle the responses from this handler in potentially very different ways depending
on a number of factors:
❑ Browser type and version
❑ Applications loaded on the system that may map to the MIME type
❑ Operating system and service pack level
Based on these factors, you might see the text returned in the browser, you might see Notepad open and display the text, or you might receive the Open/Save/Cancel prompt from IE Make sure you understand the potential consequences of changing the ContentType header
You can continue the example by modifying it to return an actual file In this case, you use the handler
to return an image To do this, you simply modify the code in theProcessRequestmethod, as shown in Listing 27-8
Listing 27-8: Outputting an image from an HttpHandler
VB
<%@ WebHandler Language="VB" Class="Handler" %>
Imports System.Web
Public Class Handler : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
’Logic to retrieve the image file
context.Response.ContentType = "image/jpeg"
context.Response.WriteFile("Garden.jpg")
End Sub
Public ReadOnly Property IsReusable() As Boolean _
Implements IHttpHandler.IsReusable Get
Return False End Get
End Property
End Class
C#
<%@ WebHandler Language="C#" Class="Handler" %>
Continued