Pro ASP.NET 2.0 In CSharp 2005 (2005) [eng]
.pdf
188 C H A P T E R 5 ■ A S P. N E T A P P L I C AT I O N S
response.Write("<html><body>");
// Get the name of the requested file. string file = request.QueryString["file"]; try
{
// Open the file and display its contents one line at a time. response.Write("<b>Listing " + file + "</b><br />"); StreamReader r = File.OpenText(
server.MapPath(Path.Combine("./", file))); string line = "";
while (line != null)
{
line = r.ReadLine();
if (line != null)
{
//Make sure tags and other special characters are
//replaced by their corresponding HTML entities so that
//they can be displayed appropriately.
line = server.HtmlEncode(line);
//Replace spaces and tabs with nonbreaking spaces
//to preserve whitespace.
line = line.Replace(" ", " "); line = line.Replace(
"\t", " ");
//A more sophisticated source viewer might apply
//color coding.
response.Write(line + "<br />");
}
}
r.Close();
}
catch (Exception err)
{
response.Write(err.Message);
}
response.Write("</html></body>");
}
public bool IsReusable
{
get {return true;}
}
}
}
This code simply finds the requested file, reads its content, and uses a little string substitution (for example, replacing spaces with nonbreaking spaces and line breaks with the <br /> element) and HTML encoding to create a representation that can be safely displayed in a browser. You’ll learn more about techniques for reading and manipulating files in Chapter 13.
C H A P T E R 5 ■ A S P. N E T A P P L I C AT I O N S |
189 |
Next, you can map the handler to a file extension, as follows:
<httpHandlers>
<add verb="*" path="source.simple" type="HttpExtensions.SourceHandler,HttpExtensions"/>
</httpHandlers>
To test this handler, you can use a URL in this format:
http://localhost:[Port]/Chapter05/source.simple?file=HolmesQuote.aspx.cs
The HTTP handler will then show the source code for the .cs file, as shown in Figure 5-14.
Figure 5-14. Using a more sophisticated HTTP handler
Based on this example, you can probably imagine a variety of different ways you can use HTTP handlers. For example, you could render a custom image, perform an ad hoc database query, or return some binary data. These examples extend the ASP.NET architecture but bypass the web-page model. The result is a leaner, more efficient component.
You can also create HTTP handlers that work asynchronously. This means they create a new thread to do their work, instead of using one of the ASP.NET worker threads. This improves scalability in situations where you need to perform a task that takes a long amount of time but isn’t CPU-intensive. A classic example is waiting to read an extremely slow network resource. ASP.NET allows a fixed set of worker threads to run only at one time (typically 25), so once this limit is reached additional requests will be queued, even if the computer has available CPU time.
190 C H A P T E R 5 ■ A S P. N E T A P P L I C AT I O N S
HTTP HANDLERS AND SESSION STATE
By default, HTTP handlers do not have access to client-specific session state. That’s because HTTP handlers are generally used for lower-level tasks, and skipping the steps needed to serialize and retrieve session state information achieves a minor increase in performance. However, if you do need access to session state information, you simply need to implement one of the following two interfaces:
•IRequiresSessionState
•IReadOnlySessionState
If you require just read-only access to session state, you should implement the IRequiresSessionState interface. If you need to modify or add to session information, you should implement the IReadOnlySessionState interface. You should never implement both at the same time.
These two interfaces are just marker interfaces and do not contain any methods. That means you don’t need to write any extra code to enable session support. For example, if you want to use read-only session state with the SimpleHandler class, you would declare it in this way:
public class SimpleHandler : IHttpHandler, IReadOnlySessionState {...}
To actually access the Session object, you’ll need to work through the HttpContext object that’s submitted to the ProcessRequest() method. It provides a Session property.
With asynchronous handlers, additional requests can be accepted, because the handler creates a new thread to process each request rather than using the worker process. Of course, there is a risk with this approach. Namely, if you create too many threads for the computer to manage efficiently, or if you try to do too much CPU-intensive work at once, the performance of the entire web server will be adversely affected. Asynchronous HTTP handlers are beyond the scope of this book, but you can read an excellent introduction from MSDN Magazine at http://msdn.microsoft.com/msdnmag/ issues/03/06/Threading.
Creating a Custom HTTP Module
It’s just as easy to create custom HTTP modules as custom HTTP handlers. You simply need to author a class that implements the System.Web.IHttpModule interface. You can then register your module by adding it to the <httpModules> section of the web.config file. However, you don’t need to configure IIS to use your HTTP modules. That’s because modules are automatically used for every web request.
So, how does an HTTP module plug itself into the ASP.NET request processing pipeline? It does so in the same way as the global.asax file. Essentially, when an HTTP module is created, it registers to receive specific global application events. For example, if the module is concerned with authentication, it will register itself to receive the authentication events. Whenever those events occur, ASP.NET invokes all the interested HTTP modules. The HTTP module wires up its events with delegate code in the Init() method.
The IHttpModule interface defines the two methods shown in Table 5-5.
C H A P T E R 5 ■ A S P. N E T A P P L I C AT I O N S |
191 |
Table 5-5. IHttpModule Members
Member |
Description |
Init() |
This method allows an HTTP module to register its event handlers to receive |
|
the events of the HttpApplication object. This method provides the current |
|
HttpApplication object for the request as a parameter. |
Dispose() |
This method gives an HTTP module an opportunity to perform any cleanup |
|
before the object gets garbage collected. |
|
|
The following class is a custom HTTP module that handles the event HttpApplication.AuthenticateRequest and then logs the user information to a new entry in the Windows event log using the EventLog class from the System.Diagnostics namespace. To use this example, the account used to run ASP.NET code must have permission to write to the event log.
using System; using System.Web;
using System.Diagnostics;
namespace HttpExtensions
{
public class LogUserModule : IHttpModule
{
public void Init(HttpApplication httpApp)
{
// Attach application event handlers.
httpApp.AuthenticateRequest += new EventHandler(OnAuthentication);
}
private void OnAuthentication(object sender, EventArgs a)
{
// Get the current user identity.
string name = HttpContext.Current.User.Identity.Name;
// Log the user name. EventLog log = new EventLog();
log.Source = "Log User Module"; log.WriteEntry(name + " was authenticated.");
}
public void Dispose() {}
}
}
Now you can register the module with the following information in the web.config file. Here’s an example that assumes it’s compiled in a separate assembly named HttpExtensions.dll:
<httpModules>
<add name="LogUserModule" type="HttpExtensions.LogUserModule,HttpExtensions" />
</httpModules>
To test this module, request any other page in the web application. Then check the entry in the Windows application event log. (To view the log, select Programs Administrative Tools Event Viewer from the Start menu.) Figure 5-15 shows the logged messages.
192 C H A P T E R 5 ■ A S P. N E T A P P L I C AT I O N S
Figure 5-15. Logging messages with an HTTP module
In Part 4, you’ll see a more detailed example that uses an HTTP module to perform custom authentication.
HANDLING EVENTS FROM OTHER MODULES
The previous example shows how you can handle application events in a custom HTTP module. However, some global events aren’t provided by the HttpApplication class but are still quite important. These include events raised by other HTTP modules, such as the events fired to start and end a session.
Fortunately, you can wire up to these events in the Init() event; you just need a slightly different approach. The HttpApplication class provides a collection of all the modules that are a part of the current HTTP pipeline through the Modules collection. You can retrieve a module by name and then use delegate code to connect an event handler.
For example, if you want to connect an event handler named OnSessionStart() to the SessionStateModule.Start event, you could use code like this for the Init() method in your HTTP module:
public void Init(HttpApplication httpApp)
{
SessionStateModule sessionMod = httpApp.Modules["Session"]; sessionMod.Start += new EventHandler(OnSessionStart);
}
C H A P T E R 5 ■ A S P. N E T A P P L I C AT I O N S |
193 |
Summary
In this chapter, you took a closer look at what constitutes an ASP.NET application. After learning more about the life cycle of an application, you learned how to code global application event handlers with the global.asax file and how to set application configuration with the web.config file. Finally, you learned how to use separately compiled components in your web pages and how to extend the HTTP pipeline with your own handlers and modules.
C H A P T E R 6
■ ■ ■
State Management
No web application framework, no matter how advanced, can change that HTTP is a stateless protocol. After every web request, the client disconnects from the server, and the ASP.NET engine discards the page objects. This architecture ensures that web applications can scale up to serve thousands of simultaneous requests without running out of server memory. The drawback is that your code needs to use other techniques to store information between web requests and retrieve it when needed.
In this chapter, you’ll see how to tackle this challenge by maintaining information on the server and on the client using a variety of techniques. You’ll also learn how to transfer information from one web page to another.
STATE MANAGEMENT CHANGES IN .NET 2.0
The standbys of state management remain the same in ASP.NET 2.0. That means the programming interface for session state, application state, view state, and the query string hasn’t changed at all. However, session state now offers more configuration options, and there’s a new way to transfer information between pages.
Here’s a preview of the changes:
•Cross-page postbacks: In ASP.NET 1.x, a page could post only to itself. In ASP.NET 2.0, you can post from one page to another, transferring the page’s state at the same time.
•New session state settings: Session state is now more configurable. You have options that allow you to use a custom SQL Server database (instead of one named ASPState), set timeouts, and configure how cookies are used and named.
•Custom session state providers: Microsoft has opened the session state model so that you can develop custom session state providers (and session ID providers) that store state in other data sources or generate session IDs using different algorithms.
•Profiles: Rather than coding your own database retrieval logic, you can use the new profile API to store userspecific information in a database. Best of all, this information is strongly typed, unlike session state. Profiles build on the ASP.NET authentication model.
Out of these four topics, you’ll see only the first two in this chapter. Profiles are discussed in Chapter 24, because you need to use them in conjunction with Windows authentication or forms authentication. Custom session state providers are beyond the scope of this book. However, expect to see third-party session providers that allow you to use sessions with other relational databases.
195
196 C H A P T E R 6 ■ S TAT E M A N A G E M E N T
ASP.NET State Management
ASP.NET includes a variety of options for state management. It features the same Session and Application state collections as traditional ASP (with a few enhancements) and an entirely new view state model. ASP.NET even includes a caching system that allows you to retain information without sacrificing server scalability. Each state management choice has a different lifetime, scope, performance overhead, and level of support.
Table 6-1, Table 6-2, and Table 6-3 show an at-a-glance comparison of your state management options.
Table 6-1. State Management Options Compared (Part 1)
|
View State |
Query String |
Custom Cookies |
Allowed Data Types |
All serializable .NET |
A limited amount |
String data. |
|
data types. |
of string data. |
|
Storage Location |
A hidden field in the |
The browser’s |
The client’s |
|
current web page. |
URL string. |
computer (in |
|
|
|
memory or a |
|
|
|
small text file, |
|
|
|
depending on its |
|
|
|
lifetime settings). |
Lifetime |
Retained permanently |
Lost when the user |
Set by the |
|
for postbacks to a |
enters a new URL |
programmer. It |
|
single page. |
or closes the browser. |
can be used in |
|
|
However, can be |
multiple pages |
|
|
stored in a bookmark. |
and can persist |
|
|
|
between visits. |
Scope |
Limited to the current |
Limited to the target |
The whole |
|
page. |
page. |
ASP.NET |
|
|
|
application. |
Security |
By default it’s insecure, |
Clearly visible and easy |
Insecure and can |
|
although you can use |
for the user to modify. |
be modified by |
|
Page directives to enforce |
|
the user. |
|
encryption and hashing. |
|
|
Performance |
Storing a large amount |
None, because the |
None, because the |
Implications |
of information will slow |
amount of data is |
amount of data is |
|
transmission but will not |
trivial. |
trivial. |
|
affect server performance. |
|
|
Typical Use |
Page-specific settings. |
Sending a product ID |
Personalization |
|
|
from a catalog page to |
preferences for a |
|
|
a details page. |
website. |
|
|
|
|
Table 6-2. State Management Options Compared (Part 2)
|
Session State |
Application State |
Allowed Data Types |
All serializable .NET data types. |
All .NET data types. |
|
Nonserializable types are |
|
|
supported if you are using |
|
|
the default in-process state |
|
|
service. |
|
Storage Location |
Server memory. |
Server memory. |
C H A P T E R 6 ■ S TAT E M A N A G E M E N T |
197 |
Session State |
Application State |
Lifetime |
Times out after a predefined |
|
period (usually 20 minutes |
|
but can be altered globally |
|
or programmatically). |
The lifetime of the application (typically, until the server is rebooted).
Scope |
The whole ASP.NET application. |
The whole ASP.NET application. |
|
|
Unlike most other types of |
|
|
methods, application data is |
|
|
global to all users. |
Security |
Secure, because data is never |
|
transmitted to the client. |
|
However, subject to session |
|
hijacking if you don’t use SSL. |
Performance |
Storing a large amount of |
Implications |
information can slow down |
|
the server severely, especially |
|
if there are a large number of |
|
users at once, because each |
|
user will have a separate copy |
|
of session data. |
Typical Use |
Store items in a shopping |
|
basket. |
Very secure, because data is never transmitted to the client.
Storing a large amount of information can slow down the server, because this data will never time out and be removed.
Storing any type of global data.
Table 6-3. State Management Options Compared (Part 3)
|
Profiles |
Caching |
Allowed Data Types |
All serializable .NET data types. |
All .NET data types. |
|
Nonserializable types are |
|
|
supported if you create a |
|
|
custom profile. |
|
Storage Location |
A back-end database. |
Lifetime |
Permanent. |
Scope |
The whole ASP.NET application. |
|
May also be accessed by other |
|
applications. |
Security |
Fairly secure, because although |
|
data is never transmitted, it is |
|
stored in a database that could |
|
be compromised. |
Performance |
Large amounts of data can be |
Implications |
stored easily, but there may |
|
be a nontrivial overhead in |
|
retrieving and writing the |
|
data for each request. |
Typical Use |
Store customer account |
|
information. |
Server memory.
Depends on the expiration policy you set but may possibly be released early if server memory becomes scarce.
The same as application state (global to all users and all pages).
Very secure, because data is never transmitted to the client.
Storing a large amount of information may force out other, more useful cached information. However, ASP.NET has the ability to remove items early to ensure optimum performance.
Storing data retrieved from a database.
