Anatomy of an ASP.NET Page
- 2/15/2011
- Invoking a Page
- The Page Class
- The Page Life Cycle
- Summary
The wise are instructed by reason; ordinary minds by experience; the stupid, by necessity; and brutes by instinct.
—Cicero
ASP.NET pages are dynamically compiled on demand when first requested in the context of a Web application. Dynamic compilation is not specific to ASP.NET pages alone (.aspx files); it also occurs with services (.svc and asmx files), Web user controls (.ascx files), HTTP handlers (.ashx files), and a few more ASP.NET application files such as the global.asax file. A pipeline of run-time modules takes care of the incoming HTTP packet and makes it evolve from a simple protocol-specific payload up to the rank of a server-side ASP.NET object—whether it’s an instance of a class derived from the system’s Page class or something else.
The ASP.NET HTTP runtime processes the page object and causes it to generate the markup to insert in the response. The generation of the response is marked by several events handled by user code and collectively known as the page life cycle.
In this chapter, we’ll review how an HTTP request for an .aspx resource is mapped to a page object, the programming interface of the Page class, and how to control the generation of the markup by handling events of the page life cycle.
Invoking a Page
Let’s start by examining in detail how the .aspx page is converted into a class and then compiled into an assembly. Generating an assembly for a particular .aspx resource is a two-step process. First, the source code of the resource file is parsed and a corresponding class is created that inherits either from Page or another class that, in turn, inherits from Page. Second, the dynamically generated class is compiled into an assembly and cached in an ASP.NET-specific temporary directory.
The compiled page remains in use as long as no changes occur to the linked .aspx source file or the whole application is restarted. Any changes to the linked .aspx file invalidate the current page-specific assembly and force the HTTP runtime to create a new assembly on the next request for the page.
The Runtime Machinery
Most of the requests that hit Internet Information Services (IIS) are forwarded to a particular run-time module for actual processing. The only exception to this model is made for static resources (for example, images) that IIS can quickly serve on its own. A module that can handle Web resources within IIS is known as an ISAPI extension and can be made of managed or unmanaged code. The worker process that serves the Web application in charge of the request loads the pinpointed module and commands it through a contracted programming interface.
For example, old-fashioned ASP pages are processed by an ISAPI extension named asp.dll whereas files with an .aspx extension—classic Web Forms pages—are assigned to an ISAPI extension named aspnet_isapi.dll, as shown in Figure 5-1. Extension-less requests like those managed by an ASP.NET MVC application are intercepted at the gate and redirected to completely distinct runtime machinery. (At least this is what happens under IIS 7 in integrated mode. In older configurations, you still need to register a specific extension for the requests to be correctly handled by IIS.)
FIGURE 5-1 Setting the handler for resources with an .aspx extension.
Resource Mappings
IIS stores the list of recognized resources in the IIS metabase. Depending on the version of IIS you are using, the metabase might be a hidden component or a plain configuration file that an administrator can freely edit by hand. Regardless of the internal implementation, the IIS manager tool provides a user interface to edit the content of the metabase.
Upon installation, ASP.NET modifies the IIS metabase to make sure that aspnet_isapi.dll can handle some typical ASP.NET resources. Table 5-1 lists some of these resources.
TABLE 5-1 IIS Application Mappings for aspnet_isapi.dl
Extension |
Resource Type |
.asax |
ASP.NET application files. Note, though, that any .asax file other than global.asax is ignored. The mapping is there only to ensure that global.asax can’t be requested directly. |
.ascx |
ASP.NET user control files. |
.ashx |
HTTP handlers—namely, managed modules that interact with the low-level request and response services of IIS. |
.asmx |
Files that represent the endpoint of old-fashioned .NET Web services. |
.aspx |
Files that represent ASP.NET pages. |
.axd |
Extension that identifies internal HTTP handlers used to implement system features such as application-level tracing (trace.axd) or script injection (webresource.axd). |
.svc |
Files that represent the endpoint of a Windows Communication Foundation (WCF) service. |
In addition, the aspnet_isapi.dll extension handles other typical Microsoft Visual Studio extensions such as .cs, .csproj, .vb, .vbproj, .config, and .resx.
As mentioned in Chapter 2, “ASP.NET and IIS,” the exact behavior of the ASP.NET ISAPI extension depends on the process model selected for the application—integrated pipeline (the default in IIS 7 and superior) or classic pipeline. Regardless of the model, at the end of the processing pipeline the originally requested URL that refers to an .aspx resource is mapped to, and served through, an instance of a class that represents an ASP.NET Web Forms page. The base class is the System.Web.UI.Page class.
Representing the Requested Page
The aforementioned Page class is only the base class. The actual class being used by the IIS worker process is a dynamically created derived class. So the ASP.NET HTTP runtime environment first determines the name of the class that will be used to serve the request. A particular naming convention links the URL of the page to the name of the class. If the requested page is, say, default.aspx, the associated class turns out to be ASP.default_aspx. The transformation rule applies a fixed ASP namespace and replaces any dot (.) with an underscore (_). If the URL contains a directory name, any slashes are also replaced with an underscore.
If no class exists with the specified name in any of the assemblies currently loaded in the AppDomain, the HTTP runtime orders that the class be created and compiled on the fly. This step is often referred to as the dynamic compilation of ASP.NET pages.
The source code for the new class is created by parsing the source code of the .aspx resource, and it’s temporarily saved in the ASP.NET temporary folder. The parser attempts to create a class with an initializer method able to create instances of any referenced server controls found in the ASPX markup. A referenced server control results from tags explicitly decorated with the runat=server attribute and from contiguous literals, including blanks and carriage returns. For example, consider the following short piece of markup:
<html> <body> <asp:button runat="server" ID="Button1" text="Click" /> </body> </html>
When parsed, it sparks three distinct server control instances: two literal controls and a Button control. The first literal comprehends the text “<html><body>” plus any blanks and carriage returns the editor has put in. The second literal includes “</body></html>”.
Next, the Page-derived class is compiled and loaded in memory to serve the request. When a new request for the same page arrives, the class is ready and no compile step will ever take place. (The class will be re-created and recompiled only if the source code of the .aspx source changes at some point.)
The ASP.default_aspx class inherits from Page or, more likely, from a class that in turn inherits from Page. More precisely, the base class for ASP.default_aspx will be a combination of the code-behind, partial class you created through Visual Studio and a second partial class dynamically arranged by the ASP.NET HTTP runtime. The second, implicit partial class contains the declaration of protected properties for any explicitly referenced server controls. This second partial class is the key that allows you to write the following code successfully:
// No member named Button1 has ever been explicitly declared in any code-behind // class. It is silently added at compile time through a partial class. Button1.Text = ...;
Partial classes are a hot feature of .NET compilers. When partially declared, a class has its source code split over multiple source files, each of which appears to contain an ordinary class definition from beginning to end. The keyword partial, though, informs the compiler that the class declaration being processed is incomplete. To get full and complete source code, the compiler must look into other files specified on the command line.
Partial Classes in ASP.NET Projects
Partial classes are a compiler feature originally designed to overcome the brittleness of tool-generated code back in Visual Studio 2003 projects. Ideal for team development, partial classes simplify coding and avoid manual file synchronization in all situations in which many authors work on distinct segments of the class logical class.
Generally, partial classes are a source-level, assembly-limited, non-object-oriented way to extend the behavior of a class. A number of advantages are derived from intensive use of partial classes. As mentioned, you can have multiple teams at work on the same component at the same time. In addition, you have a neat and elegant way to add functionality to a class incrementally. In the end, this is just what the ASP.NET runtime does.
The ASPX markup defines server controls that will be handled by the code in the code-behind class. For this model to work, the code-behind class needs to incorporate references to these server controls as internal members—typically, protected members. In Visual Studio, the code-behind class is a partial class that just lacks members’ declaration. Missing declarations are incrementally added at run time via a second partial class created by the ASP.NET HTTP runtime. The compiler of choice (C#, Microsoft Visual Basic .NET, or whatever) will then merge the two partial classes to create the real parent of the dynamically created page class.
Processing the Request
So to serve a request for a page named default.aspx, the ASP.NET runtime gets or creates a reference to a class named ASP.default_aspx. Next, the HTTP runtime environment invokes the class through the methods of a well-known interface—IHttpHandler. The root Page class implements this interface, which includes a couple of members: the ProcessRequest method and the Boolean IsReusable property. After the HTTP runtime has obtained an instance of the class that represents the requested resource, invoking the ProcessRequest method—a public method—gives birth to the process that culminates in the generation of the final response for the browser. As mentioned, the steps and events that execute and trigger out of the call to ProcessRequest are collectively known as the page life cycle.
Although serving pages is the ultimate goal of the ASP.NET runtime, the way in which the resultant markup code is generated is much more sophisticated than in other platforms and involves many objects. The IIS worker process passes any incoming HTTP requests to the so-called HTTP pipeline. The HTTP pipeline is a fully extensible chain of managed objects that works according to the classic concept of a pipeline. All these objects form what is often referred to as the ASP.NET HTTP runtime environment.
This ASP.NET-specific pipeline is integrated with the IIS pipeline in place for any requests when the Web application is configured to work in IIS 7 Integrated mode. Otherwise, IIS and ASP.NET use distinct pipelines—an unmanaged pipeline for IIS and a managed pipeline for ASP.NET.
A page request passes through a pipeline of objects that process the original HTTP payload and, at the end of the chain, produce some markup code for the browser. The entry point in this pipeline is the HttpRuntime class.
The HttpRuntime Class
The ASP.NET worker process activates the HTTP pipeline in the beginning by creating a new instance of the HttpRuntime class and then calling its ProcessRequest method for each incoming request. For the sake of clarity, note that despite the name, HttpRuntime.ProcessRequest has nothing to do with the IHttpHandler interface.
The HttpRuntime class contains a lot of private and internal methods and only three public static methods: Close, ProcessRequest, and UnloadAppDomain, as detailed in Table 5-2.
TABLE 5-2 Public Methods in the HttpRuntime Class
Method |
Description |
Close |
Removes all items from the ASP.NET cache, and terminates the Web application. This method should be used only when your code implements its own hosting environment. There is no need to call this method in the course of normal ASP.NET request processing. |
ProcessRequest |
Drives all ASP.NET Web processing execution. |
UnloadAppDomain |
Terminates the current ASP.NET application. The application restarts the next time a request is received for it. |
Note that all the methods shown in Table 5-2 have limited applicability in user applications. In particular, you’re not supposed to use ProcessRequest in your own code, whereas Close is useful only if you’re hosting ASP.NET in a custom application. Of the three methods in Table 5-2, only UnloadAppDomain can be considered for use if, under certain run-time conditions, you realize you need to restart the application. (See the sidebar “What Causes Application Restarts?” later in this chapter.)
Upon creation, the HttpRuntime object initializes a number of internal objects that will help carry out the page request. Helper objects include the cache manager and the file system monitor used to detect changes in the files that form the application. When the ProcessRequest method is called, the HttpRuntime object starts working to serve a page to the browser. It creates a new empty context for the request and initializes a specialized text writer object in which the markup code will be accumulated. A context is given by an instance of the HttpContext class, which encapsulates all HTTP-specific information about the request.
After that, the HttpRuntime object uses the context information to either locate or create a Web application object capable of handling the request. A Web application is searched using the virtual directory information contained in the URL. The object used to find or create a new Web application is HttpApplicationFactory—an internal-use object responsible for returning a valid object capable of handling the request.
Before we get to discover more about the various components of the HTTP pipeline, a look at Figure 5-2 is in order.
FIGURE 5-2 The HTTP pipeline processing for a page.
The Application Factory
During the lifetime of the application, the HttpApplicationFactory object maintains a pool of HttpApplication objects to serve incoming HTTP requests. When invoked, the application factory object verifies that an AppDomain exists for the virtual folder the request targets. If the application is already running, the factory picks an HttpApplication out of the pool of available objects and passes it the request. A new HttpApplication object is created if an existing object is not available.
If the virtual folder has not yet been called for the first time, a new HttpApplication object for the virtual folder is created in a new AppDomain. In this case, the creation of an HttpApplication object entails the compilation of the global.asax application file, if one is present, and the creation of the assembly that represents the actual page requested. This event is actually equivalent to the start of the application. An HttpApplication object is used to process a single page request at a time; multiple objects are used to serve simultaneous requests.
The HttpApplication Object
HttpApplication is the base class that represents a running ASP.NET application. A derived HTTP application class is dynamically generated by parsing the contents of the global.asax file, if any is present. If global.asax is available, the application class is built and named after it: ASP.global_asax. Otherwise, the base HttpApplication class is used.
An instance of an HttpApplication-derived class is responsible for managing the entire lifetime of the request it is assigned to. The same instance can be reused only after the request has been completed. The HttpApplication maintains a list of HTTP module objects that can filter and even modify the content of the request. Registered modules are called during various moments of the elaboration as the request passes through the pipeline.
The HttpApplication object determines the type of object that represents the resource being requested—typically, an ASP.NET page, a Web service, or perhaps a user control. HttpApplication then uses the proper handler factory to get an object that represents the requested resource. The factory either instantiates the class for the requested resource from an existing assembly or dynamically creates the assembly and then an instance of the class. A handler factory object is a class that implements the IHttpHandlerFactory interface and is responsible for returning an instance of a managed class that can handle the HTTP request—an HTTP handler. An ASP.NET page is simply a handler object—that is, an instance of a class that implements the IHttpHandler interface.
Let’s see what happens when the resource requested is a page.
The Page Factory
When the HttpApplication object in charge of the request has figured out the proper handler, it creates an instance of the handler factory object. For a request that targets a page, the factory is a class named PageHandlerFactory. To find the appropriate handler, HttpApplication uses the information in the <httpHandlers> section of the configuration file as a complement to the information stored in the IIS handler mappings list, as shown in Figure 5-3.
FIGURE 5-3 The HTTP pipeline processing for a page.
Bear in mind that handler factory objects do not compile the requested resource each time it is invoked. The compiled code is stored in an ASP.NET temporary directory on the Web server and used until the corresponding resource file is modified.
So the page handler factory creates an instance of an object that represents the particular page requested. As mentioned, the actual object inherits from the System.Web.UI.Page class, which in turn implements the IHttpHandler interface. The page object is returned to the application factory, which passes that back to the HttpRuntime object. The final step accomplished by the ASP.NET runtime is calling the IHttpHandler’s ProcessRequest method on the page object. This call causes the page to execute the user-defined code and generate the markup for the browser.
In Chapter 17, “ASP.NET State Management,” we’ll return to the initialization of an ASP.NET application, the contents of global.asax, and the information stuffed into the HTTP context—a container object, created by the HttpRuntime class, that is populated, passed along the pipeline, and finally bound to the page handler.
The Processing Directives of a Page
Processing directives configure the run-time environment that will execute the page. In ASP.NET, directives can be located anywhere in the page, although it’s a good and common practice to place them at the beginning of the file. In addition, the name of a directive is case insensitive and the values of directive attributes don’t need to be quoted. The most important and most frequently used directive in ASP.NET is @Page. The complete list of ASP.NET directives is shown in Table 5-3.
TABLE 5-3 Directives Supported by ASP.NET Pages
Directive |
Description |
@ Assembly |
Links an assembly to the current page or user control. |
@ Control |
Defines control-specific attributes that guide the behavior of the control compiler. |
@ Implements |
Indicates that the page, or the user control, implements a specified .NET Framework interface. |
@ Import |
Indicates a namespace to import into a page or user control. |
@ Master |
Identifies an ASP.NET master page. (See Chapter 8, “Page Composition and Usability.”) |
@ MasterType |
Provides a way to create a strongly typed reference to the ASP.NET master page when the master page is accessed from the Master property. (See Chapter 8.) |
@ OutputCache |
Controls the output caching policies of a page or user control. (See Chapter 18, “ASP.NET Caching.”) |
@ Page |
Defines page-specific attributes that guide the behavior of the page compiler and the language parser that will preprocess the page. |
@ PreviousPageType |
Provides a way to get strong typing against the previous page, as accessed through the PreviousPage property. |
@ Reference |
Links a page or user control to the current page or user control. |
@ Register |
Creates a custom tag in the page or the control. The new tag (prefix and name) is associated with the namespace and the code of a user-defined control. |
With the exception of @Page, @PreviousPageType, @Master, @MasterType, and @Control, all directives can be used both within a page and a control declaration. @Page and @Control are mutually exclusive. @Page can be used only in .aspx files, while the @Control directive can be used only in user control .ascx files. @Master, in turn, is used to define a very special type of page—the master page.
The syntax of a processing directive is unique and common to all supported types of directives. Multiple attributes must be separated with blanks, and no blank can be placed around the equal sign (=) that assigns a value to an attribute, as the following line of code demonstrates:
<%@ Directive_Name attribute="value" [attribute="value"...] %>
Each directive has its own closed set of typed attributes. Assigning a value of the wrong type to an attribute, or using a wrong attribute with a directive, results in a compilation error.
The @Page Directive
The @Page directive can be used only in .aspx pages and generates a compile error if used with other types of ASP.NET files such as controls and Web services. Each .aspx file is allowed to include at most one @Page directive. Although not strictly necessary from the syntax point of view, the directive is realistically required by all pages of some complexity.
@Page features over 40 attributes that can be logically grouped in three categories: compilation (defined in Table 5-4), overall page behavior (defined in Table 5-5), and page output (defined in Table 5-6). Each ASP.NET page is compiled upon first request, and the HTML actually served to the browser is generated by the methods of the dynamically generated class. The attributes listed in Table 5-4 let you fine-tune parameters for the compiler and choose the language to use.
TABLE 5-4 @Page Attributes for Page Compilation
Attribute |
Description |
ClassName |
Specifies the name of the class that will be dynamically compiled when the page is requested. It must be a class name without namespace information. |
CodeFile |
Indicates the path to the code-behind class for the current page. The source class file must be deployed to the Web server. |
CodeBehind |
Attribute consumed by Visual Studio, indicates the path to the code-behind class for the current page. The source class file will be compiled to a deployable assembly. |
CodeFileBaseClass |
Specifies the type name of a base class for a page and its associated code-behind class. The attribute is optional, but when it is used the CodeFile attribute must also be present. |
CompilationMode |
Indicates whether the page should be compiled at run time. |
CompilerOptions |
A sequence of compiler command-line switches used to compile the page. |
Debug |
A Boolean value that indicates whether the page should be compiled with debug symbols. |
Explicit |
A Boolean value that determines whether the page is compiled with the Visual Basic Option Explicit mode set to On. Option Explicit forces the programmer to explicitly declare all variables. The attribute is ignored if the page language is not Visual Basic .NET. |
Inherits |
Defines the base class for the page to inherit. It can be any class derived from the Page class. |
Language |
Indicates the language to use when compiling inline code blocks (<% … %>) and all the code that appears in the page <script> section. Supported languages include Visual Basic .NET, C#, JScript .NET, and J#. If not otherwise specified, the language defaults to Visual Basic .NET. |
LinePragmas |
Indicates whether the run time should generate line pragmas in the source code to mark specific locations in the file for the sake of debugging tools. |
MasterPageFile |
Indicates the master page for the current page. |
Src |
Indicates the source file that contains the implementation of the base class specified with Inherits. The attribute is not used by Visual Studio and other Rapid Application Development (RAD) designers. |
Strict |
A Boolean value that determines whether the page is compiled with the Visual Basic Option Strict mode set to On. When this attribute is enabled, Option Strict permits only type-safe conversions and prohibits implicit conversions in which loss of data is possible. (In this case, the behavior is identical to that of C#.) The attribute is ignored if the page language is not Visual Basic .NET. |
Trace |
A Boolean value that indicates whether tracing is enabled. If tracing is enabled, extra information is appended to the page’s output. The default is false. |
TraceMode |
Indicates how trace messages are to be displayed for the page when tracing is enabled. Feasible values are SortByTime and SortByCategory. The default, when tracing is enabled, is SortByTime. |
WarningLevel |
Indicates the compiler warning level at which you want the compiler to abort compilation for the page. Possible values are 0 through 4. |
Attributes listed in Table 5-5 allow you to control to some extent the overall behavior of the page and the supported range of features. For example, you can set a custom error page, disable session state, and control the transactional behavior of the page.
TABLE 5-5 @Page Attributes for Page Behavior
Attribute |
Description |
AspCompat |
A Boolean attribute that, when set to true, allows the page to be executed on a single-threaded apartment (STA) thread. The setting allows the page to call COM+ 1.0 components and components developed with Microsoft Visual Basic 6.0 that require access to the unmanaged ASP built-in objects. (I’ll return to this topic in Chapter 16, “The HTTP Request Context.”) |
Async |
If this attribute is set to true, the generated page class derives from IHttpAsyncHandler rather than having IHttpHandler add some built-in asynchronous capabilities to the page. |
AsyncTimeOut |
Defines the timeout in seconds used when processing asynchronous tasks. The default is 45 seconds. |
AutoEventWireup |
A Boolean attribute that indicates whether page events are automatically enabled. It’s set to true by default. Pages developed with Visual Studio .NET have this attribute set to false, and page events for these pages are individually tied to handlers. |
Buffer |
A Boolean attribute that determines whether HTTP response buffering is enabled. It’s set to true by default. |
Description |
Provides a text description of the page. The ASP.NET page parser ignores the attribute, which subsequently has only a documentation purpose. |
EnableEventValidation |
A Boolean value that indicates whether the page will emit a hidden field to cache available values for input fields that support event data validation. It’s set to true by default. |
EnableSessionState |
Defines how the page should treat session data. If this attribute is set to true, the session state can be read and written to. If it’s set to false, session data is not available to the application. Finally, if this attribute is set to ReadOnly, the session state can be read but not changed. |
EnableViewState |
A Boolean value that indicates whether the page view state is maintained across page requests. The view state is the page call context—a collection of values that retain the state of the page and are carried back and forth. View state is enabled by default. (I’ll cover this topic in Chapter 17. “ASP.NET State Management.”) |
EnableTheming |
A Boolean value that indicates whether the page will support themes for embedded controls. It’s set to true by default. |
EnableViewStateMac |
A Boolean value that indicates ASP.NET should calculate a machine-specific authentication code and append it to the view state of the page (in addition to Base64 encoding). The Mac in the attribute name stands for machine authentication check. When the attribute is true, upon postbacks ASP.NET will check the authentication code of the view state to make sure that it hasn’t been tampered with on the client. |
ErrorPage |
Defines the target URL to which users will be automatically redirected in case of unhandled page exceptions. |
MaintainScrollPositionOnPostback |
A Boolean value that indicates whether to return the user to the same position in the client browser after postback. |
SmartNavigation |
A Boolean value that indicates whether the page supports the Microsoft Internet Explorer 5 or later smart navigation feature. Smart navigation allows a page to be refreshed without losing scroll position and element focus. |
Theme, StylesheetTheme |
Indicates the name of the theme (or style-sheet theme) selected for the page. |
Transaction |
Indicates whether the page supports or requires transactions. Feasible values are Disabled, NotSupported, Supported, Required, and RequiresNew. Transaction support is disabled by default. |
ValidateRequest |
A Boolean value that indicates whether request validation should occur. If this attribute is set to true, ASP.NET checks all input data against a hard-coded list of potentially dangerous values. This functionality helps reduce the risk of cross-site scripting attacks for pages. The value is true by default. |
Attributes listed in Table 5-6 allow you to control the format of the output being generated for the page. For example, you can set the content type of the page or localize the output to the extent possible.
TABLE 5-6 @Page Directives for Page Output
Attribute |
Description |
ClientTarget |
Indicates the target browser for which ASP.NET server controls should render content. |
ClientIDMode |
Specifies the algorithm to use to generate client ID values for server controls. This attribute requires ASP.NET 4. |
CodePage |
Indicates the code page value for the response. Set this attribute only if you created the page using a code page other than the default code page of the Web server on which the page will run. In this case, set the attribute to the code page of your development machine. A code page is a character set that includes numbers, punctuation marks, and other glyphs. Code pages differ on a per-language basis. |
ContentType |
Defines the content type of the response as a standard MIME type. Supports any valid HTTP content type string. |
Culture |
Indicates the culture setting for the page. Culture information includes the writing and sorting system, calendar, and date and currency formats. The attribute must be set to a non-neutral culture name, which means it must contain both language and country/region information. For example, en-US is a valid value, unlike en alone, which is considered country/region neutral. |
LCID |
A 32-bit value that defines the locale identifier for the page. By default, ASP.NET uses the locale of the Web server. |
MetaDescription |
Sets the “description” meta element for the page. The value set through the @Page directive overrides any similar values you might have specified as literal text in the markup. This attribute requires ASP.NET 4. |
MetaKeywords |
Sets the “keywords” meta element for the page. The value set through the @Page directive overrides any similar values you might have specified as literal text in the markup. This attribute requires ASP.NET 4. |
ResponseEncoding |
Indicates the character encoding of the page. The value is used to set the CharSet attribute on the content type HTTP header. Internally, ASP.NET handles all strings as Unicode. |
UICulture |
Specifies the default culture name used by Resource Manager to look up culture-specific resources at run time. |
ViewStateEncryptionMode |
Determines how and if the view state is encrypted. Feasible values are Auto, Always, or Never. The default is Auto, meaning that view state will be encrypted only if an individual control requests that. |
ViewStateMode |
Determines the value for the page’s ViewStateMode property that influences the way in which the page treats the view state of child controls. (More details are available in Chapter 17.) This attribute requires ASP.NET 4. |
As you can see, many attributes discussed in Table 5-6 are concern with page localization. Building multilanguage and international applications is a task that ASP.NET, and the .NET Framework in general, greatly simplify.
The @Assembly Directive
The @Assembly directive adds an assembly to a collection of assembly names that are used during the compilation of the ASP.NET page so that classes and interfaces in the assembly are available for early binding to the code. You use the @Assembly directive when you want to reference a given assembly only from a specific page.
Some assemblies are linked by default for any ASP.NET application. The complete list can be found in the root web.config file of the Web server machine. The list is pretty long in ASP.NET 4, but it no longer includes the System.Web.Mobile assembly that was there for older versions of ASP.NET. The mobile assembly is now deprecated, but if you’re trying to upgrade an existing application to ASP.NET 4 that uses the assembly, you are required to add the assembly explicitly via an @Assembly directive or via a custom <compilation> section in the application.
Table 5-7 lists some of the assemblies that are automatically provided to the compiler for an ASP.NET 4 application.
TABLE 5-7 Assemblies Linked by Default in ASP.NET 4
Assembly File Name |
Description |
mscorlib |
Provides the core functionality of the .NET Framework, including types, AppDomains, and run-time services |
System.dll |
Provides another bunch of system services, including regular expressions, compilation, native methods, file I/O, and networking |
System.Configuration.dll |
Defines classes to read and write configuration data. |
System.Core.dll |
Provides some other core functionality of the .NET Framework, including LINQ-to-Objects, the time-zone API, and some security and diagnostic classes |
System.Data.dll |
Defines data container and data access classes, including the whole ADO.NET framework |
System.Data.DataSetExtensions.dll |
Defines additional functions built over the ADO.NET DataSet object |
System.Drawing.dll |
Implements the GDI+ features |
System.EnterpriseServices.dll |
Provides the classes that allow for serviced components and COM+ interaction |
System.Web.dll |
Indicates the assembly implements the core ASP.NET services, controls, and classes |
System.Web.ApplicationServices.dll |
Provides classes that enable you to access ASP.NET authentication, roles, and profile functions via a bunch of built-in WCF services |
System.Web.DynamicData.dll |
Provides classes behind the ASP.NET Dynamic Data framework |
System.Web.Entity.dll |
Contains the code for the EntityDataSource component that supports Entity Framework |
System.Web.Extensions.dll |
Contains the code for AJAX extensions to ASP.NET |
System.Web.Services.dll |
Contains the core code that makes Web services run |
System.Xml.dll |
Implements the .NET Framework XML features |
System.Xml.Linq.dll |
Contains the code for the LINQ-to-XML parser |
Note that you can modify, extend, or restrict the list of default assemblies by editing the global settings in the root web.config file under
%Windows%\Microsoft.NET\Framework\v4.0.30319\Config
If you do so, changes will apply to all ASP.NET applications run on that Web server. Alternatively, you can modify the assembly list on a per-application basis by editing the <assemblies> section under <compilation> in the application’s specific web.config file. Note also that the <compilation> section should be used only for global assembly cache (GAC) resident assemblies, not for the private assemblies that you deploy to the Bin folder.
By default, the <compilation> section in the root web.config file contains the following entry:
<add assembly="*" />
It means that any assembly found in the binary path of the application should be treated as if it were registered through the @Assembly directive. To prevent all assemblies found in the Bin directory from being linked to the page, remove the entry from the root configuration file. To link a needed assembly to the page, use the following syntax:
<%@ Assembly Name="AssemblyName" %> <%@ Assembly Src="assembly_code.cs" %>
The @Assembly directive supports two mutually exclusive attributes: Name and Src. Name indicates the name of the assembly to link to the page. The name cannot include the path or the extension. Src indicates the path to a source file to dynamically compile and link against the page. The @Assembly directive can appear multiple times in the body of the page. In fact, you need a new directive for each assembly to link. Name and Src cannot be used in the same @Assembly directive, but multiple directives defined in the same page can use either.
Any assemblies you register through the @Assembly directive are used by the compiler at compile time, which allows for early binding. After the compilation of the requested ASP.NET file is complete, the assembly is loaded into the application domain, thus allowing late binding. In the end, any assemblies listed through the directive (implicitly through the root configuration or explicitly through the application configuration) is loaded into the AppDomain and referenced on demand.
The @Import Directive
The @Import directive links the specified namespace to the page so that all the types defined can be accessed from the page without specifying the fully qualified name. For example, to create a new instance of the ADO.NET DataSet class, you either import the System.Data namespace or specify the fully qualified class name whenever you need it, as in the following code:
System.Data.DataSet ds = new System.Data.DataSet();
After you’ve imported the System.Data namespace into the page, you can use more natural coding, as shown here:
DataSet ds = new DataSet();
The syntax of the @Import directive is rather self-explanatory:
<%@ Import namespace="value" %>
@Import can be used as many times as needed in the body of the page. The @Import directive is the ASP.NET counterpart of the C# using statement and the Visual Basic .NET Imports statement. Looking back at unmanaged C/C++, we could say the directive plays a role nearly identical to the #include directive. For example, to be able to connect to a Microsoft SQL Server database and grab some disconnected data, you need to import the following two namespaces:
<%@ Import namespace="System.Data" %> <%@ Import namespace="System.Data.SqlClient" %>
You need the System.Data namespace to work with the DataSet and DataTable classes, and you need the System.Data.SqlClient namespace to prepare and issue the command. In this case, you don’t need to link against additional assemblies because the System.Data.dll assembly is linked by default.
The @Implements Directive
The directive indicates that the current page implements the specified .NET Framework interface. An interface is a set of signatures for a logically related group of functions. An interface is a sort of contract that shows the component’s commitment to expose that group of functions. Unlike abstract classes, an interface doesn’t provide code or executable functionality. When you implement an interface in an ASP.NET page, you declare any required methods and properties within the <script> section. The syntax of the @Implements directive is as follows:
<%@ Implements interface="InterfaceName" %>
The @Implements directive can appear multiple times in the page if the page has to implement multiple interfaces. Note that if you decide to put all the page logic in a separate class file, you can’t use the directive to implement interfaces. Instead, you implement the interface in the code-behind class.
The @Reference Directive
The @Reference directive is used to establish a dynamic link between the current page and the specified page or user control. This feature has significant implications for the way you set up cross-page communication. It also lets you create strongly typed instances of user controls. Let’s review the syntax.
The directive can appear multiple times in the page. The directive features two mutually exclusive attributes: Page and Control. Both attributes are expected to contain a path to a source file:
<%@ Reference page="source_page" %> <%@ Reference control="source_user_control" %>
The Page attribute points to an .aspx source file, whereas the Control attribute contains the path of an .ascx user control. In both cases, the referenced source file will be dynamically compiled into an assembly, thus making the classes defined in the source programmatically available to the referencing page. When running, an ASP.NET page is an instance of a .NET Framework class with a specific interface made of methods and properties. When the referencing page executes, a referenced page becomes a class that represents the .aspx source file and can be instantiated and programmed at will. For the directive to work, the referenced page must belong to the same domain as the calling page. Cross-site calls are not allowed, and both the Page and Control attributes expect to receive a relative virtual path.