The nice thing about being a celebrity is that when you bore people, they think it's their fault.
-Henry Kissinger
In Chapter 2, I described in detail the various steps that take an incoming HTTP request to be served by the ASP.NET worker process. I'll summarize the process here. The request is assigned to the aspnet_isapi.dll ISAPI extension which, in turn, hands it over to the HTTP runtime pipeline. A new instance of the HttpRuntime class is created for each request and governs its overall execution. The HttpRuntime class represents the entry point in the ASP.NET pipeline that will generate the response text for the browser. Upon instantiation, the HttpRuntime class performs a number of initialization tasks, the first of which is the creation of a wrapper object to encapsulate all the HTTP-specific information available about the request. The newly created object—an instance of the HttpContext class—is then passed along to the pipeline and is used by the various modules to access intrinsic worker objects such as Request, Response, and Server.
In this chapter, we'll first review the startup process of the ASP.NET application and then move on to examine the various objects that form the context of the HTTP request. If you're a former ASP developer, the contents of this chapter might sound familiar as we discuss old acquaintances such as Request, Response, and Server. However, you need to notice up front that the role of these intrinsic ASP objects is different in ASP.NET. They are fully supported and fully backward-compatible with ASP, but their functionality is built on top of a completely redesigned server architecture.
Once you've created the context for the request, the HttpRuntime class sets up an ASP.NET application object to carry out the request. An ASP.NET application consists of an instance of the HttpApplication class that we briefly discussed in Chapter 2. HttpApplication is a global.asax-derived object that handles all HTTP requests directed to a particular virtual folder.
An ASP.NET running application is wholly represented by its virtual folder and optionally by the global.asax file. The virtual folder name is a sort of key the HTTP runtime uses to selectively identify which of the running HttpApplication objects should take care of the incoming request. The global.asax file, if present, contains code for responding to application-level events raised by ASP.NET or by registered HTTP modules that affect the application. Figure 13-1 shows a detailed view of the process that creates a page for a request. You'll see that requests pass through the application factory that picks up (or creates) a valid HttpApplication object from a pool. The HttpApplication object, in turn, selects the proper resource handler based on the type of the request (.aspx, .asmx, or other type).
Figure 13-1: The process of creating a page for an HTTP request.
The particular HttpApplication selected is responsible for managing the entire lifetime of the request it is assigned to. That instance of HttpApplication can be reused only after the request has been completed. If no HttpApplication object is available, either because the application has not been started or all valid objects are busy, a new HttpApplication is created and pooled.
Although the HttpApplication class provides a public constructor, user applications never need to create instances of the HttpApplication class directly. The ASP.NET runtime infrastructure always does the job for you. As mentioned, instances of the class are pooled and, as such, can process many requests in their lifetime (but always one at a time). Should concurrent requests arrive for the same application, additional instances are created. Because the HttpApplication object serves just one request at a time, its member variables store per-request data. Table 13-1 lists the properties defined on the class.
Property |
Description |
---|---|
Application |
Instance of the HttpApplicationState class, represents the global and shared state of the application. Functionally equivalent to the ASP intrinsic Application object. |
Context |
Instance of the HttpContext class, encapsulates in a single object all HTTP-specific information about the current request. Intrinsic objects (for example, Application and Request) are also exposed as properties. |
Modules |
Gets the collection of modules that affect the current application. |
Request |
Instance of the HttpRequest class, represents the current HTTP request. Functionally equivalent to the ASP intrinsic Request object. |
Response |
Instance of the HttpResponse class, sends HTTP response data to the client. Functionally equivalent to the ASP intrinsic Response object. |
Server |
Instance of the HttpServerUtility class, provides helper methods for processing Web requests. Functionally equivalent to the ASP intrinsic Server object. |
Session |
Instance of the HttpSessionState class, manages user-specific data. Functionally equivalent to the ASP intrinsic Session object. |
User |
An IPrincipal object that represents the user making the request. |
A good question at this point of the discussion would be the following. Because the HttpApplication class is managed by the ASP.NET infrastructure, how can I take advantage of the fairly rich, public programming interface of the class? Properties, overridable methods, and class events, can be accessed and programmatically manipulated in the global.asax file. (We'll return to global.asax later in the section "The global.asax File.")
The Modules property returns a collection of applicationwide components providing ad hoc services. An HTTP module component is a class that implements the IHttpModule interface. Modules can be considered the managed counterpart of ISAPI filters; they are a kind of request interceptor with the built-in capability of modifying the overall context of the request being processed. The .NET Framework defines a number of standard modules as listed in Table 13-2. Custom modules can be defined too. We'll cover this particular aspect of HTTP programming in Chapter 23.
Module |
Description |
---|---|
DefaultAuthenticationModule |
Ensures that an authentication object is present in the context. |
FileAuthorizationModule |
Verifies that the remote user has Windows NT permissions to access the requested resource. |
FormsAuthenticationModule |
Enables applications to use forms authentication. |
OutputCacheModule |
Manages the page output caching. This class is not officially documented. |
PassportAuthenticationModule |
Provides a wrapper around Passport authentication services. |
SessionStateModule |
Provides session-state services for the application. |
UrlAuthorizationModule |
Provides URL-based authorization services to access specified resources. |
WindowsAuthenticationModule |
Enables ASP.NET applications to use Windows and IIS-based authentication. |
The list of default modules is defined in the machine.config file and can be modified to include new modules or exclude some of those shown in the preceding table. The modules listed in machine.config are available to all applications. By creating a proper web.config file, you can also create an application-specific list of modules. (See Chapter 12.)
It's worth noting that no class can be inherited. The reason is because all those classes are associated with the predefined mechanisms for authentication and authorization. Making those classes inheritable would have opened a potential security hole in ASP.NET. A derived class, in fact, often looks like the original but can provide significantly different good and bad features.
The methods of the HttpApplication class can be divided in two groups—operational methods and event handler managers. The HttpApplication operational methods are described in Table 13-3.
Method |
Description |
---|---|
CompleteRequest |
Sets an internal flag that causes ASP.NET to skip all successive steps in the pipeline and directly execute EndRequest. Mostly useful to HTTP modules. |
Dispose |
Overridable method, cleans up the instance variables of all registered modules once the request has been served. At this time, Request, Response, Session, and Application are no longer available. |
GetVaryByCustomString |
Overridable method, provides a way to set output caching based on a custom string for all pages in the application. (We'll say more on output page caching in Chapter 14.) |
Init |
Overridable method, executes custom initialization code after all modules have been linked to the application to serve the request. You can use it to create and configure any object you want to use throughout the request processing. At this time Request, Response, Session, and Application are not yet available. |
Note that Init and Dispose are quite different from well-known event handlers such as Application_OnStart and Application_OnEnd. Init executes for every request directed at the Web application, whereas Application_OnStart fires only once in the Web application's lifetime. Init indicates that a new instance of the HttpApplication object has been created to serve an incoming request; Application_OnStart denotes that the first instance of HttpApplication has been created to start up the Web application and serve its very first request. Likewise, Dispose signals the next termination of the request processing but not necessarily the end of the application. Application_OnEnd is raised only once, when the application is being shut down.
Note |
A similar difference exists between the pair Init/Dispose and Session_OnStart and Session_OnEnd. The latter two events are raised only once in the session lifetime, whereas methods Init and Dispose are invoked at each request. |
You should also be aware that all resources you create that override the Init method are shared only with the current instance of modules, and in no way are those objects visible across multiple requests. Data that must survive multiple requests should be stored in instances of global state classes such as HttpApplicationState (the property Application) or HttpSessionState (the property Session). Any resource that gets created in Init should be cleaned up in Dispose.
In addition to the operational methods in Table 13-3, a few other HttpApplication methods are available and listed in Table 13-4. These methods are of no interest to user applications and are used only by HTTP modules to hook up the events generated during the request's chain of execution. The description of all methods is identical; what really changes is the name of the event that the handlers are attached to. All methods in Table 13-4 add the specified event handlers to the collection of handlers associated with the specified asynchronous application event. Event handlers are detached when the request is completed.
You should note that there are two versions of each application event, a synchronous version and an asynchronous version. The methods listed in Table 13-4 are for the asynchronous versions.
Method |
Event |
---|---|
AddOnAcquireRequestStateAsync |
AcquireRequestState |
AddOnAuthenticateRequestAsync |
AuthenticateRequest |
AddOnAuthorizeRequestAsync |
AuthorizeRequest |
AddOnBeginRequestAsync |
BeginRequest |
AddOnEndRequestAsync |
EndRequest |
AddOnPostRequestHandlerExecuteAsync |
PostRequestHandlerExecute |
AddOnPreRequestHandlerExecuteAsync |
PreRequestHandlerExecute |
AddOnReleaseRequestStateAsync |
ReleaseRequestState |
AddOnResolveRequestCacheAsync |
ResolveRequestCache |
AddOnUpdateRequestCacheAsync |
UpdateRequestCache |
Each module is requested to indicate a begin handler and an end handler. The following code shows the prototype of the AddOnAcquireRequestStateAsync method. Other prototypes are nearly identical.
public void AddOnAcquireRequestStateAsync( BeginEventHandler bh, EndEventHandler eh );
The BeginEventHandler is the delegate called at the start of the asynchronous event processing, while EndEventHandler is the delegate that gets into the game at the end of event processing.
Table 13-5 describes the event model of the HttpApplication class—that is, the set of events that HTTP modules, as well as user applications, can listen to and handle.
Event |
Description |
---|---|
AcquireRequestState |
Occurs when the handler that will actually serve the request acquires the state information associated with the request. |
AuthenticateRequest |
Occurs when a security module has established the identity of the user. |
AuthorizeRequest |
Occurs when a security module has verified user authorization. |
BeginRequest |
Occurs as soon as the HTTP pipeline begins to process the request. |
Disposed |
Occurs when the HttpApplication object is disposed as a result of a call to Dispose. |
EndRequest |
Occurs as the last event in the HTTP pipeline chain of execution. The EndRequest event is always raised when CompleteRequest is called. |
Error |
Occurs when an unhandled exception is thrown. The exception object can be accessed through a call to the Server's GetLastError method. If your application generates custom error output, use the Server's ClearError method to suppress the default error message. |
PostRequestHandlerExecute |
Occurs when the HTTP handler of choice (.aspx, .asmx, .ashx, or other type) finishes execution. The response text has been generated at this point. |
PreRequestHandlerExecute |
Occurs just before the HTTP handler of choice (.aspx, .asmx, .ashx, or other type) begins to work. |
PreSendRequestContent |
Occurs just before the ASP.NET runtime sends the response text to the client. |
PreSendRequestHeaders |
Occurs just before the ASP.NET runtime sends HTTP headers to the client. |
ReleaseRequestState |
Occurs when the handler releases the state information associated with the current request. |
ResolveRequestCache |
Occurs when the ASP.NET runtime resolves the request through the output cache, thus bypassing the regular handler (.aspx, .asmx, .ashx, or other type the requested resource was). |
UpdateRequestCache |
Occurs when the ASP.NET runtime stores the response of the current request in the output cache to be used to serve subsequent requests. |
To handle any of these events asynchronously, an application will use the corresponding method in Table 13-4. To hook up some of these events in a synchronous manner, an application will define in the global.asax file event handler procedures with the following signature:
public void Application_XXX() { // do something here }
Of course the XXX placeholder must be replaced with the name of the event. All the events in the preceding table provide no event-specific data. You could also use the following syntax:
public void Application_XXX(object sender, EventArgs e) { // do something here }
This syntax, however, doesn't give you additional information and programming power. The sender argument evaluates to the sender object, which is always the ASP.global_asax class, with a couple of exceptions. The sender is HttpApplicationFactory when the application starts up and SessionStateModule when the session is started.
Note |
In Application_OnStart, both Response and Request are not yet available in the context of the current application. They won't actually be linked until the request begins. This doesn't mean, though, that you can't access them. The trick is using the objects from the Context request, which, in contrast, has just been created by the HTTP runtime. In other words, resort to Context.Response and Context.Request. This approach is necessary only in the Application_OnStart handler. |
In addition to the events of Table 13-5, in the global.asax file, an application can also handle Application_OnStart and Application_OnEnd. When ASP.NET is about to fire BeginRequest for the very first time in the application lifetime, it makes Application_OnStart precede it. EndRequest will happen at the end of every request to an application. Application_OnEnd occurs outside the context of a request, when the application is ending. Let's examine the order in which events are raised.
Another pair of events can occur during the request, but in a nondeterministic order. They are PreSendRequestHeaders and PreSendRequestContent. The PreSendRequestHeaders event informs the HttpApplication object in charge of the request that HTTP headers are about to be sent. The event normally fires after EndRequest but not always. For example, if buffering is turned off, the event gets fired as soon as some content is going to be sent to the client. Finally, with the PreSendRequestContent event, the HttpApplication object in charge of the request learns that the response body is about to be sent.
In Figure 13-2, you can see a sample application (logevents.aspx) that uses global.asax to accumulate and display text for events as they are detected.
Figure 13-2: Logging the events raised while a request is being processed.
In all these event handlers, you can write code the same as in the context of an HttpApplication class, meaning you can access Request, Response, and Server without instance prefixes. You're just writing methods of a class that inherits from HttpApplication.
The global.asax file is used by Web applications to handle some application-level events raised by the ASP.NET runtime or by registered HTTP modules. The global.asax file is optional. If missing, the ASP.NET runtime environment simply assumes you have no application or module event handlers defined. To be functional, the global.asax file must be located in the root directory of the application. Only one global.asax file per application is accepted. (global.asax files placed in subdirectories are simply ignored.)
Note |
ASP.NET global.asax and ASP global.asax files can happily coexist in the same application. Of course, this consideration holds true even if you're going to have an application half ASP.NET-based and managed and half ASP-driven. |
When the application is started, the global.asax file, if present, is parsed into a source class and compiled. The resultant assembly is created in the temporary directory just as any other dynamically generated assembly would be. (See Chapter 2 for more information on this procedure.) The following listing shows the skeleton of the C# code that ASP.NET generates for any global.asax file:
namespace ASP { public class global_asax : System.Web.HttpApplication { private static bool __initialized = false; // // The source code of "global.asax" file is flushed // here verbatim. For this reason, the following code // in global.asax would generate a compile error. // int i; // i = 2; // can't have statements outside methods // public global_asax() { if ((ASP.global_asax.__initialized == false)) { ASP.global_asax.__initialized = true; } } } }
The class is named ASP.global_asax and is derived from the HttpApplication base class. In most cases, you deploy global.asax as a separate text file; however, you can also write it as a class and compile it either in a separate assembly or within your project's assembly. The class source code must follow the outline shown earlier and, above all, must derive from HttpApplication. The assembly with the compiled version of global.asax must be deployed in the application's Bin subdirectory.
Note, though, that even if you isolate the logic of the global.asax file in a precompiled assembly, you still need to have a (codeless) global.asax file that refers to the assembly. (This is exactly what happens with Visual Studio .NET projects.)
<%@ Application Inherits="ProAspNet.Global" %>
We'll learn more about the syntax of global.asax in the next section, "Syntax of global.asax." With a precompiled global application file, you certainly don't risk exposing your source code over the Web to malicious attacks. However, even if you leave it as source code, you're somewhat safe.
The global.asax file, in fact, is configured so that any direct URL request for it is automatically rejected by IIS. In this way, external users cannot download or view the code it contains. The trick that enables this behavior is the following line of code, excerpted from machine.config:
ASP.NET registers with IIS to handle .asax resouces, but then processes those direct requests through the HttpForbiddenHandler HTTP handler. As a result, when a browser requests a .asax resource, an error message is displayed on the page, as shown in Figure 13-3.
Figure 13-3: Direct access to forbidden resources, such as *.asax files, results in a server error.
Of course, you can duplicate that line in your machine.config file, or even in the application's web.config file, and block direct access to other types of resources specific to your application. For this trick to work, though, make sure that the resource type is redirected to ASP.NET at the IIS level. In other words, you must register aspnet_isapi.dll to handle those files in the IIS metabase.
Note |
When the global.asax file of a running application is modified, the ASP.NET runtime detects the change and prepares to shut down and restart the application. It waits until all pending requests are completed and then fires the Application_OnEnd event. When the next request from a browser arrives, ASP.NET reparses and recompiles the global.asax file, and again raises the Application_OnStart event. |
Four elements determine the syntax of the global.asax file. They are: application directives, code declaration blocks, server-side tags, and server-side includes. These elements can be used in any order and number to compose a global.asax file.
Application Directives
The global.asax file supports three directives, two of which have been discussed in Chapter 1. The supported directives are: @Application, @Import, and @Assembly. The @Import and @Assembly directives work as we have seen in Chapter 1. The @Import directive imports a namespace into an application; the @Assembly directives links an assembly to the application at compile time.
The @Application directive supports a couple of attributes—Description and Inherits. Description can contain any text you want to use to describe the behavior of the application. This text has only a documentation purpose and is blissfully ignored by the ASP.NET parser. The Inherits attribute indicates a code-behind class for the application to inherit. It can be the name of any class derived from the HttpApplication class. The assembly that contains the class must be located in the Bin subdirectory of the application.
Just like the @Page directive, @Application accepts the CodeBehind attribute to allow for Visual Studio .NET editing. The attribute CodeBehind is ignored at run time.
Code Declaration Blocks
A global.asax file can contain code wrapped by a
If the language attribute is not specified, ASP.NET defaults to the language set in the configuration, which is Visual Basic .NET. As of version 1.1 of the .NET Framework, Visual Basic .NET, C#, JScript .NET, and J# are the only languages supported. (J# is supported only in version 1.1.)
The source code can also be loaded from an external file, whose virtual path is set in the Src attribute. The location of the file is resolved using Server.MapPath.
The Counter property defined in the global.asax in the preceding code works like an item stored in Application. Consider that concurrent access to Counter is not serialized; on the other hand, you have a strong typed, direct global item whose access is much faster than retrieving the same piece of information from a generic collection such as Application.
To access the property from a page, you must use the ASP.global_asax qualifier, shown here:
Response.Write(ASP.global_asax.Counter.ToString());
If you don't particularly like the ASP.global_asax prefix, you can alias it as long as you use C#. Add the following code to a C#-based page (or code-behind class) for which you need to access the globals:
using Globals = ASP.global_asax;
The preceding statement creates an alias for the ASP.global_asax class (or whatever name your global.asax class has). The alias—Globals in this sample code—can be used throughout your code wherever ASP.global_asax is accepted.
Response.Write(Globals.Counter.ToString());
Note |
You can use the global.asax file to handle any event exposed by the modules called to operate on the request. Handlers for events exposed by an HTTP module must have a name that conforms to the following scheme: ModuleName_EventName. The module name to use is defined in the machine.config section. Finally, bear in mind that you can handle the ASP-like Session_OnStart and Session_OnEnd events only because of this mechanism. |
When an error occurs, displaying a friendly page to the user is only half the job a good programmer should do. The second half of the work consists in sending appropriate notifications to the system administrator—if possible, in real time. A great help is the Error event of the HttpApplication object. Write an Application_Error event handler in your global.asax file and the system will call it back whenever an unhandled error occurs in the application—either in the user code, a component's code, or ASP.NET code.
In the Application_Error event handler, you first obtain specific information about the error and then implement the tracking policy that best suits your needs—for example, e-mailing the administrator, writing to the Windows Event Log, or dumping errors to a text file. The Server.GetLastError method returns an Exception object that just represents the unhandled exception you want to track down. URL information is contained in the Request object and even session or application state is available.
The following code demonstrates how to write an Application_Error event handler in global.asax to report run-time anomalies to the Event Log. An example of this code in action is shown in Figure 13-4.
Figure 13-4: The Event Viewer tracks an error on an ASP.NET application.
<%@ Import Namespace="System.Diagnostics" %>
Your code doesn't necessarily have to create the event source. If the source specified in the Source property does not exist, it will be created before writing to the event log. The WriteEntry method takes care of that. Windows provides three log files: Application, Security, and System, which is reserved for device drivers. The Log property of the EventLog class gets and sets the log file to use. It is Application by default.
Caution |
To create new event logs, applications should use the static method CreateEventSource. Note, though, that ASP.NET applications can't create new event logs because the running account (ASPNET) doesn't have enough permissions. One way to fix this is by having ASP.NET run as if it is the much more powerful SYSTEM account. As explained in Chapter 12, this can be done by changing the userName attribute in the section of the machine.config file. On the other hand, running ASP.NET applications as SYSTEM opens serious security holes, which is the ultimate reason why Microsoft decided to use an account with limited privileges. If you want your ASP.NET application to use a custom log, create that at setup time. |
During the various steps of the request's chain of execution, an object gets passed along from class to class—this object is the HttpContext object. HttpContext encapsulates all the information available about an individual HTTP request that ASP.NET is going to handle. Defined in the System.Web namespace, the HttpContext class is instantiated by the HttpRuntime object while the request-processing mechanism is being set up. Next, the object is flowed throughout the various stages of the request's lifetime, as Figure 13-5 demonstrates.
Figure 13-5: The HttpContext object, which encapsulates all the request information and gets flowed through the HTTP pipeline until the client response is generated.
The programming interface of the HttpContext class includes two static members, one static property and one static method, to carry out general, noninstance-specific tasks. In the .NET Framework, a static member (a shared member in Visual Basic .NET jargon) of a class is a property or method that belongs to the type rather than to an instance of the type. All instances of the type share that same piece of code. To call static members, you must use the type name as the qualifier.
The HttpContext class has a static property named Current that returns the HttpContext object for the request being processed.
HttpContext cxt = HttpContext.Current;
In the HttpContext programming interface, you also find a static method. It is named GetAppConfig and returns configuration information for the specified section name. The information returned is read at the application level, which means it is a mix of machine.config and the application's main web.config file. The method returns an object whose actual type is determined by the characteristics of the section read.
Table 13-7 enumerates all the properties exposed by the HttpContext class. The class represents a single entry point for a number of intrinsic objects such as ASP's Server, Request, and Response and new ASP.NET-specific Cache and User objects.
Property |
Description |
---|---|
AllErrors |
Gets an array of Exception objects, each of which represents an error that occurred while processing the request. |
Application |
Gets an instance of the HttpApplicationState class, which contains global and shared state of the application. Functionally equivalent to the ASP intrinsic Application object. |
ApplicationInstance |
Gets or sets the HttpApplication object for the current request. The actual type is ASP.global_asax. Use this cast to access public properties and methods you might have defined in global.asax. |
Cache |
Gets the ASP.NET Cache object for the current request. |
Current |
Gets the HttpContext object for the current request. |
Error |
Gets the first Exception object (if any) that has been raised while processing the current request. |
Handler |
Gets or sets the IHttpHandler object for the current request. |
IsCustomErrorEnabled |
Gets whether custom error handling is enabled for the current request. |
IsDebuggingEnabled |
Gets whether the current request is in debug mode. |
Items |
Gets a name/value collection (hash table) that can be used to share custom data and objects between HTTP modules and HTTP handlers during the request lifetime. |
Request |
Gets an instance of the HttpRequest class, which represents the current HTTP request. Functionally equivalent to the ASP intrinsic Request object. |
Response |
Gets an instance of the HttpResponse class, which sends HTTP response data to the client. Functionally equivalent to the ASP intrinsic Response object. |
Server |
Gets an instance of the HttpServerUtility class, which provides helper methods for processing Web requests. Functionally equivalent to the ASP intrinsic Server object. |
Session |
Gets an instance of the HttpSessionState class, which manages user-specific data. Functionally equivalent to the ASP intrinsic Session object. |
SkipAuthorization |
Gets or sets a Boolean value that specifies whether the URL-based authorization module will skip the authorization check for the current request. This is false by default. Mostly used by authentication modules that need to redirect to a page that allows anonymous access. |
Timestamp |
Gets a DateTime object that represents the initial timestamp of the current request. |
Trace |
Gets the TraceContext object for the current response. |
User |
Gets or sets the IPrincipal object that represents the user making the request. |
The Items property is a dictionary object—a hash table, to be exact—that can be used to share information between the modules and handlers involved with the particular request. By using this property, you can add your own information to the HttpContext object serving the request.
Table 13-8 lists the methods specific to the HttpContext class. The table doesn't include methods inherited from the base Object class, such as ToString, GetType, and Equals.
Method |
Description |
---|---|
AddError |
Adds an exception object to the AllErrors collection. |
ClearError |
Clears all errors for the current request. |
GetAppConfig |
Returns requested configuration information for the current application. The information is collected from machine.config and the application's main web.config files. |
GetConfig |
Returns requested configuration information for the current request. The information is collected at the level of the requested URL, taking into account any child web.config files defined in subdirectories. |
RewritePath |
Mostly for internal use; overwrites path and query string of the current Request object. |
In the all-encompassing container represented by the HttpContext object, a few popular objects also find their place. Among them are Server, Request, and Response. They are old acquaintances for ASP developers and indeed feature-rich elements of the ASP.NET programming toolkit. In ASP, the role of these objects was central, as they represented a large part of the ASP object model. The overall design of ASP.NET assigns to them a lower-level infrastructure role, but the set of properties and methods still makes these objects a fundamental resource for developers. Let's learn more about starting with the Server object.
The functionality of the ASP intrinsic Server object in ASP.NET is implemented by the HttpServerUtility class. An instance of the type is created when ASP.NET begins to process the request and is then stored as part of the request context. The bunch of helper methods that HttpServerUtility provides are publicly exposed to modules and handlers—including global.asax, pages, and Web services—through the Server property of the HttpContext object. In addition, to maintain ASP.NET coding as close as possible to the ASP programming style, several other commonly used ASP.NET objects also expose their own Server property. For example, both Page and HttpApplication show off a (technically speaking) redundant Server property. In this way, developers can use in the code, say, Server.MapPath without incurring compile errors. More important, they code exactly as they would have in ASP.
You should note that in ASP.NET, Server, Request, Response, and the like are in truth more intrinsic properties than intrinsic objects. In ASP, they were instances of COM components published to the ActiveX Scripting engine with easy-to-remember names such as Server, Request, and Response. To make them visible throughout all levels of code blocks, the objects were marked as globals, thereby gaining the label of intrinsically available objects.
The architecture is radically different in ASP.NET, in which the specific functionalities have been maintained and even enhanced but are integrated in the context of a true component-based model. The visibility of an object in a certain scope depends on strict syntax rules. Wide-range visibility, such as that of intrinsic objects in ASP, can be obtained only by replicating the objects in all scopes in which they are needed. Hence, the concept of intrinsic properties. Figure 13-6 compares the ASP and ASP.NET models.
Figure 13-6: In ASP, intrinsic objects are published as globals in the ActiveX Scripting engine in which all code blocks are processed. In ASP.NET, the visibility of an object is determined by the syntax.
The ASP.NET HttpServerUtility class extends and enhances the set of properties and methods defined on the COM object working as the ASP Server intrinsic object. Let's look at the new programming interface in more detail.
This class provides two properties, named MachineName and ScriptTimeout. The MachineName property returns the machine name and raises an HttpException if the name of the Web server machine is not readable. The ScriptTimeout property gets and sets the time in seconds that a request is allowed to be processed. This property accepts integers and is populated with the value of the executionTimeout attribute in the section of the machine.config file. The default value is 90 seconds; however, it is set to a virtually infinite value if the page runs with the attribute debug=true.
this.Server.ScriptTimeout = 30000000;
The ScriptTimeout property is explicitly and automatically set in the constructor of the class that represents the page. (See Chapter 2.)
Table 13-9 lists all methods exposed by the HttpServerUtility class. As you can see, they constitute a group of helper methods that come in handy at various stages of page execution. The class provides a couple of methods to create instances of COM components and a few others to deal with errors. Another group of methods relates to the decoding and encoding of content and URL.
Method |
Description |
---|---|
ClearError |
Clears the last exception that was thrown for the request. |
CreateObject |
Creates an instance of the specified COM object. |
CreateObjectFromClsid |
Creates an instance of the COM object identified by the specified CLSID. The class identifier is expressed as a string. |
Execute |
Passes control to the specified page for execution. The child page executes like a subroutine. The output can be retained in a writer object or automatically flushed in the parent response buffer. |
GetLastError |
Returns the last Exception object that was thrown. |
HtmlDecode |
Decodes a string that has been encoded to eliminate invalid HTML characters. For example, it translates <; back into <. |
HtmlEncode |
Encodes a string to be displayed in a browser. For example, encodes < into <;. |
MapPath |
Returns the physical path that corresponds to the specified virtual path on the Web server. |
Transfer |
Works as a kind of server-side redirect. It terminates the execution of the current page and passes control to the specified page. Unlike Execute, control is not passed back to the caller page. It is more effective than Response.Redirect. |
UrlDecode |
Decodes a string encoded for HTTP transmission to the server in a URL. The decoded string can be returned as a string or output to a writer. |
UrlEncode |
Encodes a string for HTTP transmission to a client in a URL. The encoded string can be returned as a string or output to a writer. |
UrlPathEncode |
Encodes only the path portion of a URL string, and returns the encoded string. This method leaves the query string content intact. |
HTML and URL encoding are ways of encoding characters to ensure that the transmitted text is not misunderstood by the receiving browser. HTML encoding, in particular, replaces <, >, &, and quotes with equivalent HTML entities such as <, >, &, and ". It also encodes blanks, punctuation characters, and in general, all characters not allowed in an HTML stream. On the other hand, URL encoding is aimed at fixing the text transmitted in URL strings. In URL encoding, the same critical characters are replaced with different character entities than in HTML encoding.
Both HTML and URL encoding and decoding methods can return a string as well as output to any sort of TextWriter object—typically a StringWriter object. We'll talk about text writers in Chapter 16.
Embedding Another Page's Results
The Execute method allows you to consider an external page as a subroutine. When the execution flow reaches the Server.Execute call, control is passed to the specified page. The execution of the current page is suspended, and the external page is spawned. The response text generated by the child execution is captured and processed according to the particular overload of Execute that has been used.
public void Execute(string); public void Execute(string, TextWriter);
If the first overload is used, the response text is automatically embedded in the response of the main page. (See Figure 13-7.) If a TextWriter object is specified, the response text of the child execution is accumulated into the writer object and left at the disposal of the main page.
Figure 13-7: The response text generated by Execute, which can be automatically embedded in the main response or cached in a writer object.
The source code for the main page in Figure 13-7 is as follows:
<%@ Page Language="C#" %>
Pro ASP.NET (Ch13)
It's interesting to look at the internal implementation of the Execute method. Both the main and child pages are run by the same HttpApplication object as if they were the same request. What happens within the folds of Execute is a sort of context switch. First, the method obtains an HTTP handler from the application factory to serve the new request. The original handler of the main request is cached and replaced with the new handler. The spawned page inherits the context of the parent; when finished, any modification made to Session or Application is immediately visible to the main page.
The handler switching makes the whole operation extremely fast, as there's no need to create a new object to serve the request. When the child page returns, the original handler is restored. The execution of the main page continues from the point in which it was stopped but using the context inherited from the child page.
Server-Side Redirection
The Transfer method differs from the Execute method in that it terminates the current page after executing the specified page. The new page runs as if it was the originally requested one. The Transfer method has the following two overloads:
public void Transfer(string); public void Transfer(string, bool);
The first overload simply redirects to the specified page. The second overload clears or preserves the QueryString and Form collections based on the value of the Boolean argument. When you call the first overload, the collections are always cleared unless the IsPostBack property on the original page is set to true.
The Execute and Transfer methods have a similar architecture. Both methods use the same internal procedure to perform the handler switch. In both cases, the same HttpApplication object is used to carry out the new request, as shown in Figure 13-8.
Figure 13-8: Comparing the internal architecture of the Execute and Transfer methods.
Note that when you call Transfer, the new page request is served immediately. However, the previous request is terminated only when the internal call to Execute, used to implement the redirect, has returned. The following pseudocode illustrates the behavior of the method:
public void Transfer(string path, bool preserveForm) { // the null argument indicates that no writer should // be used in the call to Execute ExecuteInternal(path, null, preserveForm); Context.Response.End(); }
All the code that might be following the call to Transfer in the main page is never executed. In the end, Transfer is just a page redirect method. However, it is particularly efficient for two reasons. First, no roundtrip to the client is requested as is the case, for example, with Response.Redirect. Second, the same HttpApplication that was serving the caller request is reused, thus limiting the impact on the ASP.NET infrastructure.
Late-Bound COM Objects
The HttpServerUtility class provides you with the ability to create late-bound COM objects in much the same way you do in ASP. The methods are CreateObject and CreateObjectFromClsid. They are marked to return a generic Object type. However, the actual type they return is System.__ComObject. Objects can be created either from the string representation of the class CLSID or from the progID. The following code creates an instance of a COM component using the CLSID:
Dim strClsid As String = "42754580-16b7-11ce-80eb-00aa003d7352" Dim comObj As Object = Server.CreateObject(strClsid)
When assigned to a variable declared of type Object, an object is said to be late bound—as opposed to early-bound, strongly typed objects. Late-bound objects can hold references to any object, but they lack many advantages of early-bound objects. Early-bound objects should be used whenever possible because they are significantly faster than late-bound objects and make your code easier to develop, read, and maintain.
Primarily for backward-compatibility reasons, you might sometimes create late-bound instances of COM objects. Using COM objects in ASP.NET applications is a common necessity in real-world projects. The best way to import COM functionality in .NET applications entails the use of managed wrappers—special classes that expose the type library of the COM class as a .NET class. Managed wrappers are usually created by Visual Studio .NET when you reference a COM object in your project.
Note |
A command-line utility is also available should you need to generate the class assembly using a particular namespace, language, or file name different from those automatically set by Visual Studio .NET. The utility is the Type Library Importer (tlbimp.exe) and is located in the installation path of Visual Studio .NET. |
Although not especially effective as an approach, the Server.CreateObject method can be used to create a late-bound instance of a COM component. The ideal language for late binding is Visual Basic .NET; however, bear in mind that late binding is supported as long as the Strict option is Off (the default).
The following code shows how to fill an ADO Recordset object using the ASP programming style:
<%@ Page Language="VB" AspCompat="true" %>
Note the use of the AspCompat attribute in the @Page directive. Apartment-threaded COM components can be created only in ASP.NET pages that have the AspCompat attribute set to true. Before an attempt to create the object is made, the CreateObject method checks the threading model of the component. If the page is already working in ASP compatibility mode—that is, the AspCompat attribute is true—the object is created, regardless of the threading model of the component. If the AspCompat attribute is set to false (the default), CreateObject reads the threading model of the COM component from the registry. If the threading model is apartment, or no threading model is specified, an exception is thrown; otherwise, the object is successfully created. The following pseudocode shows the internals of the HttpServerUtility'sCreateObject method:
public object CreateObject(string progID) { Type managedType = Type.GetTypeFromProgID(progID); if (!IsAspCompatMode) { string threadingModel = GetThreadingModel(managedType.GUID); if (threadingModel == "apartment") throw new HttpException("..."); } return Activator.CreateInstance(managedType); }
Note also that the use of the AspCompat attribute is not strictly necessary with the ADO library because the ADO library supports both the apartment and free-threading model.
Note |
COM components developed using Visual Basic 6.0 need the AspCompat attribute to be used in ASP.NET pages because they typically use the single-threaded apartment model (STA). This situation is detected and throws an exception. Note, though, that if your code instantiates the COM object through a managed wrapper (instead of creating the instance using CreateObject), the runtime will no longer be able to detect the apartment nature of the component and does not throw an exception. A managed wrapper saves you from a run-time exception but not from the need of setting AspCompat to true. |
The Importance of AspCompat
Running STA components in a multithreaded apartment environment (MTA) such as ASP.NET is strongly discouraged performance-wise. The AspCompat attribute is designed to avoid this critical situation. Let's see how and why.
To process HTTP requests, normally ASP.NET uses a pool of threads from an MTA. Objects in an MTA execute on any thread and allow any number of methods to occur simultaneously. Single-threaded apartment COM components (for example, all Visual Basic 6 COM components) execute on the particular thread in which they were created and allow only one method to execute at a time. Until special countermeasures are taken, when you run an STA component in an MTA environment continued thread switching is likely to happen. More importantly, a thread switch can happen only when the particular thread in the pool that can serve the STA component is available. As you can see, this situation is heralding poor performance issues if not even deadlock.
By setting the AspCompat attribute to true, you force ASP.NET to use an STA thread pool to accommodate the COM object on a per-page basis. In this case, both the caller thread and the callee component live in the same apartment and no extra overhead is involved. As a matter of fact, ASP.NET pages that contain STA COM components run better in STA mode than in an, otherwise generally faster, MTA mode.
Because the AspCompat attribute is processed after the instance of the page class is created, you should also avoid creating instances of STA COM objects in the page constructor. If you don't avoid doing this, the page will be served by an MTA thread regardless of the value of AspCompat and probably incur poor performance.
Setting AspCompat to true also has another advantage—it makes ASP intrinsic objects (ObjectContext, Request, Response, and so forth) available to the COM component. ASP.NET creates unmanaged ASP intrinsic objects and passes them to the COM components used in the page.
In ASP.NET, the functionality of the ASP intrinsic Response object is provided through the HttpResponse class. An instance of the HttpResponse object is created when the HTTP pipeline is set up to serve the request. The instance is then linked to the HttpContext object associated with the request. The HttpResponse class defines methods and properties to manipulate the text that will be sent to the browser. Although user-defined ASP.NET code never needs to use the HttpResponse constructor, looking at it is still useful to get the gist of the class:
public HttpResponse(TextWriter writer);
As you can see, the constructor takes a writer object, which will then be used to accumulate the response text that controls the generated page. The actual writer used by HttpResponse is the HttpWriter class. All calls made to Response.Write are resolved in terms of internal calls to the HttpWriter object.
All properties of the class are grouped and described in Table 13-10. You set a few of these properties to configure key fields on the HTTP response packet, such as content type, character set, page expiration, and status code.
Property |
Description |
---|---|
Buffer |
Gets or sets a Boolean value that indicates whether the response text should be buffered and sent only at the end of the request. This property is deprecated and provided only for backward compatibility with ASP. ASP.NET applications use BufferOutput. |
BufferOutput |
Gets or sets a Boolean value that indicates whether response buffering is enabled. The default is true. |
Cache |
Gets the caching policy set for the page. The caching policy is an HttpCachePolicy object that can be used to set the cache-specific HTTP headers for the current response. |
CacheControl |
Sets the Cache-Control HTTP header. Acceptable values are Public or Private. The property is deprecated in favor of Cache. |
Charset |
Gets or sets a string value for the HTTP character set of the output stream. If it's set after headers have been sent, it throws an exception. If it's set to null, it suppresses the Content-Type header. |
ContentEncoding |
Gets or sets an object of type Encoding for the character encoding of the output stream. |
ContentType |
Gets or sets the string that represents the MIME type of the output stream. The default value is text/html. |
Cookies |
Gets a collection (HttpCookieCollection) object that contains instances of the HttpCookie class generated on the server. All the cookies in the collection will be transmitted to the client through the set-cookie HTTP header. |
Expires |
Gets or sets the number of minutes before a page cached on a browser expires. Provided for compatibility with ASP, the property is deprecated in favor of Cache. |
ExpiresAbsolute |
Gets or sets the absolute date and time at which the page expires in the browser cache. Provided for compatibility with ASP, the property is deprecated in favor of Cache. |
Filter |
Gets or sets a filter Stream object through which all HTTP output sent by Response.Write passes. |
IsClientConnected |
Get a Boolean value that indicates whether the client is still connected. |
Output |
Gets a TextWriter object that is used to output text to the response stream. |
OutputStream |
Gets a Stream object that is used to output binary data to the response stream. |
RedirectLocation |
Gets or a sets a string for the value of the Location header. |
Status |
Sets the string returned to the client describing the status of the response. Provided for compatibility with ASP, the property is deprecated in favor of StatusDescription. |
StatusCode |
Gets or sets an integer value for the HTTP status code of the output returned to the client. The default value is 200 (OK). An exception is raised if the property is set after the HTTP headers have been sent. |
StatusDescription |
Gets or sets the HTTP status string, which is a description of the overall status of the response returned to the client. The default value is OK. |
SuppressContent |
Gets or sets a Boolean value that indicates whether HTTP content should be sent to the client. This is set to false by default; if set to true, only headers are sent. |
As you can see, a few of the HttpResponse properties are provided only for backward compatibility with previous versions of ASP. In some cases (for example, BufferOutput and StatusDescription), the property has just been renamed; in other cases, the properties deprecated have been replaced by a more general and powerful API. This is certainly the case for cache and expiration properties.
Setting the Response Cache Policy
In ASP, the Response object has three properties dedicated to control the ability of the page being sent to the browser to be cached. The Expires and ExpiresAbsolute properties define relative and absolute times at which the page cached on the client expires and is no longer utilized by the browser to serve a user request. In fact, if the user navigates to a currently cached page, the cached version is displayed and no roundtrip occurs to the server.
A third property somehow related to page caching is CacheControl. The property sets a particular HTTP header—the Cache-Control header. The Cache-Control header controls how a document is to be cached across the network. Allowable values come from the HttpCacheability enumeration and are listed in Table 13-11.
Value |
Description |
---|---|
NoCache |
The page response is not cached on the client. |
Private |
The page response is cached only on the client and not on possible intermediate proxy servers. (This is the default setting.) |
Public |
The page response is cached both on the client and proxy servers. |
The HttpCacheability enumeration has a few more members like Server. This member has nothing to do with HTTP caching and, in fact, sets the Cache-Control header to no-cache. However, it indicates that the page is cached on the origin server.
In ASP.NET, all caching capabilities are grouped in the HttpCachePolicy class. With regard to page caching, the class has a double role. It provides methods for both setting cache-specific HTTP headers and controlling the ASP.NET page output cache. In this chapter, we're mostly interested in the HTTP headers, and we'll keep page output caching warm for Chapter 14.)
To set the visibility of a page in a client cache, use the SetCacheability method of the HttpCachePolicy class with one of the values in Table 13-11. To set an expiration time, use the SetExpires method, which takes for input an absolute DateTime object. Finally, to set a lifetime for the cached page, pass to SetExpires the current time plus the desired interval.
Note |
In the case of conflicting cache policies, ASP.NET maintains the most restrictive settings. For example, if a page contains two controls that set the Cache-Control header to public and private, the most restrictive policy will be used. In this case, Cache-Control: Private will be sent to the client. |
Setting an Output Filter
In ASP.NET, a new component makes its debut—the response filter. A response filter is a Stream-derived object that can be associated with the HttpResponse object to monitor and filter any output being generated. If you set the Filter property with the instance of an object derived from Stream, all output being written to the underlying HTTP writer first passes through your output filter.
The custom filter, if any, is invoked during the HttpResponse's Flush method before the actual text is flushed and then sent to the client. Building a response filter is a matter of creating a new class and making it inherit from Stream and override some of the methods. The class should have a constructor that accepts a Stream object. In light of this, a response filter class is more a wrapper stream class than a purely inherited stream class. If you try to set Response.Filter with a new instance of, say, MemoryStream or FileStream, an exception is thrown.
The following listing shows how to create a stream class that works as a response filter. For simplicity, the class inherits from MemoryStream. You might want to make it inherit from Stream, but in this case you need to override (because they are abstract) a number of methods, such as CanRead, CanWrite, CanSeek, and Read. The class converts lowercase characters to uppercase.
public class MyFilterStream : MemoryStream { private Stream m_Stream; public MyFilterStream(Stream filterStream) { m_Stream = filterStream; } // The Write method actually does the filtering public override void Write(byte[] buffer, int offset, int count) { byte[] data = new byte[count]; Buffer.BlockCopy(buffer, offset, data, 0, count); // Change lowercase chars to uppercase. for (int i = 0; i < count; i++) { if (data[i] >= 'a' && data[i] <= 'z') data[i] -= ('a'-'A'); } m_Stream.Write(data, 0, count); } }
Use the following code to associate this output filter with the Response.Filter property. Here's a sample page:
Table 13-12 lists all the methods defined on the HttpResponse class. The class contains one deprecated method added only for compatibility with previous versions of ASP. This method is AddHeader.
Method |
Description |
---|---|
AddCacheItemDependencies |
Adds an array of items in the output cache the current page is dependent upon. When any of the specified items is removed from the cache, the cached output of the current page becomes invalid. |
AddCacheItemDependency |
Adds a single cache key the current page is dependent upon. When the specified key is removed from the cache, the cached output of the current page becomes invalid. |
AddFileDependencies |
Adds a group of file names to the collection of file names on which the current page is dependent. When any of the files is modified, the cached output of the current page is invalid. |
AddFileDependency |
Adds a single file name to the collection of file names on which the current page is dependent. If the file is modified, the cached output of the current page becomes invalid. |
AddHeader |
Adds an HTTP header to the output stream. It is provided for compatibility with previous versions of ASP. In ASP.NET, use AppendHeader. |
AppendHeader |
Adds an HTTP header to the output stream. |
AppendToLog |
Adds custom log information to the IIS log file.AppendToLog. |
ApplyAppPathModifier |
Adds a session ID to the specified virtual path and returns the result. It is mostly used with cookieless sessions to construct an absolute HREF. |
BinaryWrite |
Writes binary characters to the HTTP output stream. |
Clear |
Clears all content output from the buffer stream. |
ClearContent |
Calls into Clear. |
ClearHeaders |
Clears all headers from the buffer stream. |
Close |
Closes the socket connection with the client. |
End |
Sends all buffered text to the client, stops execution, and raises the Application_EndRequest event. |
Flush |
Sends all currently buffered output to the client. |
Pics |
Appends a PICS-Label HTTP header to the output. PICS stands for Platform for Internet Content Selection and is a W3C standard for rating pages. Any string is acceptable, and ASP.NET does not validate the text as long as it doesn't exceed 255 characters. The header is added through AppendHeader. |
Redirect |
Redirects a client to a new URL. Needs a roundtrip. |
RemoveOutputCacheItem |
A static method that takes a file system path and removes from the cache all cached items associated with the specified path. |
Write |
Writes content to the underlying output stream. The method can write a string, a single character, an array of characters, as well as an object. In this case, though, what gets written is the output of the object's ToString method. |
WriteFile |
Writes the specified file (or a portion of it) directly to the output stream. The file can be identified with its path or a Win32 handle (an IntPtr object). |
The Redirect method causes the specified page to execute. However, the trick used in this case is less efficient than with Server.Execute or Server.Transfer. The method sends a response that the browser interprets as an invitation to request the specified page. Although the final effect is always that of redirecting the user to a different page, the way in which this effect is obtained requires a roundtrip. The HttpResponse's Redirect method has two overloads:
public void Redirect(string); public void Redirect(string, bool);
The second overload lets you specify whether the execution of the current page should terminate. By default, the redirection is unconditional and the execution of the current page is stopped.
The HttpRequest object groups all the information contained in the HTTP packet that represents the incoming Web request. The contents of the various HTTP headers, the query string, or the form's input fields, path, and URL information are organized in a series of collections and other ad hoc objects for easy and effective programmatic access. The HttpRequest object is populated as soon as ASP.NET begins working on a Web request and is made available through the Request property of HttpContext.
HttpRequest exposes a fair number of properties and is one of the objects that has been more significantly enriched in the transition from ASP to ASP.NET.
The class properties can be classified in three groups based on the type of information they contain: type of the request, client data, and connection. Table 13-13 lists the properties that define the type of request being issued.
Property |
Description |
---|---|
AcceptTypes |
Gets an array of strings denoting the list of MIME types supported by the client for the specified request. |
Browser |
Gets an HttpBrowserCapabilities object that contains information about the capabilities of the client's browser. |
ContentEncoding |
Gets or sets an Encoding object that represents the client's character set. If specified, this property overrides the ASP.NET default encoding. |
ContentLength |
Gets the length in bytes of the content sent by the client. |
ContentType |
Gets or sets the MIME content type of the incoming request. |
CurrentExecutionFilePath |
Gets the current virtual path of the request even when the client is redirected to another page via Execute or Transfer. FilePath, instead, always returns the path to the originally requested page. |
FilePath |
Gets the virtual path of the current request. The path doesn't change in cases of server-side page redirection. |
HttpMethod |
Gets a string that denotes the HTTP method used for the request. Values are GET, POST, or HEAD. |
RequestType |
Gets or sets a string that denotes the HTTP command used to issue the request. Can be GET or POST. |
TotalBytes |
Gets the total number of bytes in the input stream. This property differs from ContentLength in that it also includes headers. |
UserAgent |
Gets a string that identifies the browser. This property gets the raw content of the user agent header. Note that the Internet Explorer user agent string contains version information about COM+ and the .NET common language runtime (CLR). (The CLR version does not contain build information to recognize installed service packs.) |
Initially, CurrentExecutionFilePath and FilePath share the same content—the requested URL. However, in cases of server-side redirects, the value of CurrentExecutionFilePath is automatically updated. You should check CurrentExecutionFilePath for up-to-date information about the target URL.
The HttpBrowserCapabilities object groups in a single place values that identify a fair number of browser capabilities, including support for ActiveX controls, scripting languages, frames, cookies, and more. (Browser capabilities was discussed in Chapter 4.) When the request arrives, the user agent information is used to identify the requesting browser and a new empty instance of the HttpBrowserCapabilities class is created. The instance is then populated with browser-specific information read from the machine.config file. The information returned through HttpBrowserCapabilities is in no way dynamically set by the browser. The browser sets only the user agent string, and ASP.NET uses that small piece of information as a key to retrieve statically set information from the configuration.
The HttpRequest's Browser property also supports mobile scenarios in version 1.1 of the .NET Framework. In this case, the actual object returned is of class MobileCapabilities—a HttpBrowserCapabilities-derived class. When you obtain the Browser property reference you should cast it as a MobileCapabilities class.
Table 13-14 lists the HttpRequest properties that expose the client data that ASP.NET pages might want to use for server-side processing. The following table includes, for example, cookies, forms, and query string collections.
Property |
Description |
---|---|
ClientCertificate |
Gets an HttpClientCertificate object containing information on the client's security certificate settings, if any. The HttpClientCertificate object wraps up information such as number, validity, and issuer of the certificate. |
Cookies |
Gets an HttpCookieCollection object representing all cookies sent by the client. A cookie is identified by the HttpCookie object. |
Files |
Gets an HttpFileCollection object representing a collection of client-uploaded files. The Files property requires the HTTP Content-Type header to be set to multipart/ form-data. |
Filter |
Gets or sets a Stream-based object through which all HTTP input passes when received. |
Form |
Gets a NameValueCollection object filled with the values of the input fields in the form posted. The collection is populated when the Content-Type header is either application/x-www-form-urlencoded or multipart/form-data. |
Headers |
Gets a NameValueCollection object filled with all the header values in the request. |
InputStream |
Gets a Stream object representing the contents of the incoming HTTP content body. |
Params |
Gets a NameValueCollection object that is a union of four other similar collections: QueryString, Form, ServerVariables, and Cookies. |
QueryString |
Gets a NameValueCollection object containing all the query string variables sent by the client. |
ServerVariables |
Gets a NameValueCollection object filled with a collection of Web server–defined variables. |
UserHostAddress |
Gets the IP address of the remote client. |
UserHostName |
Gets the Domain Name System (DNS) name of the remote client. |
UserLanguages |
Gets an array of strings denoting the list of the languages accepted by the client for the specified request. The languages are read from the Accept-Language header. |
The Params collection combines four different but homogeneous collections—QueryString, Form, ServerVariables, and Cookies—and replicates the information contained in each of them. Although not particularly high, the risk of creating conflicting names does exist especially because the entries in Form, QueryString, and Cookies are decided by the programmers. The collections are added in the following order: QueryString, Form, Cookies, and finally ServerVariables.
Table 13-15 lists the properties that relate to the open connection.
Property |
Description |
---|---|
ApplicationPath |
Gets the virtual path of the current application. |
IsAuthenticated |
Gets a Boolean value that indicates whether or not the user has been authenticated. |
IsSecureConnection |
Gets a Boolean value that indicates whether the connection is taking place over a Secure Sockets Layer (SSL) using HTTPS. |
Path |
Gets the virtual path of the current request. |
PathInfo |
Gets additional path information for the requested resource, if any. The property returns any text that follows the URL. |
PhysicalApplicationPath |
Gets the file system path of the current application's root directory. |
PhysicalPath |
Gets the physical file system path corresponding to the requested URL. |
RawUrl |
Gets the raw URL of the current request. |
Url |
Gets the Uri object that represents the URL of the current request. |
UrlReferrer |
Gets the Uri object that represents the URL from which the current request originated. |
The Uri class provides an object representation of a Uniform Resource Identifier (URI)—a unique name for a resource available on the Internet. The Uri class provides easy access to the parts of the URI as well as properties and methods for checking host, loopback, ports, and DNS.
The server variables set in the ServerVariables collection are decided by the run-time environment that processes the request. The information packed in the collection is for the most part excerpted from the HTTP worker request object; another part contains Web server–specific information. The ServerVariables collection is just a friendly name/value model to expose that information.
In ASP.NET applications, the usefulness of ServerVariables is limited, as a large number of variables are also exposed as individual properties. For example, the URL and path information—whose corresponding variables are URL and PATH_INFO—are also available through more direct properties on the HttpRequest object, such as Url and PathInfo. (See Table 13-15.) However, some information is not available to Web applications other than through server variables. A few examples are the name of the Web server software (SERVER_SOFTWARE) and the meta path of the current instance of the application in IIS (INSTANCE_META_PATH).
Table 13-16 lists all methods exposed by the HttpRequest class. The list doesn't include methods such as Equals and ToString, which are inherited from Object.
Method |
Description |
---|---|
BinaryRead |
Performs a binary read from the current input stream. The method lets you specify the number of bytes to read and returns an array of bytes. The method is provided for compatibility with ASP. ASP.NET applications should read from the stream associated with the InputStream property. |
MapImageCoordinates |
Maps an incoming image-field form parameter to x/y coordinate values. |
MapPath |
Maps the specified virtual path to a physical path on the Web server. |
SaveAs |
Saves the current request to a file disk with or without headers. This method is especially useful for debugging purposes. |
The SaveAs method lets you create a file to store the entire content of the HTTP request. Note that the storage medium can only be disk file; no stream or writer can be used. Since ASP.NET by default isn't granted write permissions, this method causes an access denied exception unless you take ad hoc measures. Granting the ASPNET account full control over the file to create (or over the whole folder) is one of the possible ways to successfully use the SaveAs method. The following listing shows possible content that SaveAs writes to disk.
GET /test/main.aspx HTTP/1.1 Connection: Keep-Alive Accept: */* Accept-Encoding: gzip, deflate Accept-Language: en-us Cookie: ASP.NET_SessionId=3ogcmn550gnzl4zlao5h3545 Host: expo-star User-Agent: Mozilla/ 4.0 (compatible; MSIE 6.0; Windows NT 5.0; COM+ 1.0.2204; .NET CLR 1.1.4322)
In this chapter, we covered some basic objects that are the foundation of ASP.NET programming—Server, Response, Request, and others. An ASP.NET application is represented by an instance of the HttpApplication class properly configured by the contents of the global.asax file. And both the HttpApplication class and the global.asax files found their space in this chapter, too.
In ASP.NET, as well as in ASP, you can use an unqualified Server object in the source of the page. The context that allows you to execute that code is different in the two models, though. In ASP, Server is the name that identifies an instance of a COM component globally available in the scripting environment. In ASP.NET, Server is simply a property exposed by the page class. We summarized this key architectural difference with the expression intrinsic properties to distinguish it from the intrinsic objects of ASP.
While discussing the interface of the objects that generate the context of an HTTP request, we reviewed in detail some specific programming issues such as the instantiation of late-bound COM objects, server-side page redirection, and the setup of response filters. In the next chapter, we'll discuss an important topic related to Web applications and ASP.NET—state management. Fundamentally, Web applications are stateless, but ASP.NET provides various mechanisms for maintaining application state and caching pages.
Part I - Building an ASP.NET Page
Part II - Adding Data in an ASP.NET Site
Part III - ASP.NET Controls
Part IV - ASP.NET Application Essentials
Part V - Custom ASP.NET Controls
Part VI - Advanced Topics
Index