Web Services


ASP.NET web services allow you to easily expose programmable application logic over the Web using Simple Object Access Protocol ( SOAP ). Developers who want to use a web service do not need to know a thing about the implementation of our service. Rather, they simply need to know how to call our service using SOAP and that they will get a SOAP reply in return, if the application is configured to send SOAP replies.

ASP.NET provides a flexible framework for building web services. As part of that framework, you have the ability to configure aspects of ASP.NET web services. Although there are other configuration options for web services, the only one we will address is changing the ASP.NET page used to create the web service Help page:

click to expand
Figure 13-10:

The ASP.NET page used to create this view of our web service can be found at WINNT\Microsoft.NET\Framework\[version]\CONFIG\DefaultWSDLHelpGenerator.aspx .To customize DefaultWSDLHelpGenerator.aspx , you can instruct ASP.NET to use the custom file:

 <configuration>    <system.web>       <webServices>  <wsdlHelpGenerator href="MyWsdlHelpGenerator.aspx" />  </webServices>    </system.web> </configuration> 

You could use this web.config file in your application and instruct ASP.NET to use a custom template page used to describe an ASP.NET web service.

Internationalization and Encoding

The settings defined within <globalization> allow us to configure the culture and encoding options, in other words, the code page used by a request and the code page used by a response for the application. The following web.config file mirrors the default settings found in machine.config :

 <configuration>    <system.web>  <globalization   requestEncoding="utf-8"   responseEncoding="utf-8"   />  </system.web> </configuration> 

<globalization> supports five attributes that allow you to configure various globalization properties for your application:

  • requestEncoding :The requestEncoding attribute allows you to set the assumed encoding of each incoming request; the default is utf-8 . The values allowed for requestEncoding can be found within the Encoding class in the System.Text namespace. For example, if you wish to set the encoding to utf-7 , you could simply set.

      <globalization requestEncoding="utf-7"/>  
  • responseEncoding :The responseEncoding attribute allows you to set the encoding of outgoing responses. The default is utf-8 . The values allowed can be found within the Encoding class in the System.Text namespace.

  • fileEncoding :The fileEncoding attribute lets ASP.NET know the encoding type used for all ASP.NET file resources. The default is utf-8 . The values allowed can be found within the Encoding class in the System.Text namespace.

  • culture :The culture attribute is used to localize content using culture strings. For example, en-US represents United States English, while en-GB represents British English. This setting allows for strings to be formatted in both the appropriate language as well as using the appropriate format for dates, and so on.

  • uiCulture :The uiCulture attribute is used to define the culture string, used to look up resources.

If, for example, you were building a web application that was used in France, you could configure the following globalization and culture settings:

 <configuration>    <system.web>  <globalization   requestEncoding="utf-8"   responseEncoding="utf-8"   culture="fr-FR"   uiCulture="fr-FR"   />  </system.web> </configuration> 

You could then write a simple ASP.NET page using Visual Basic .NET to test your culture settings, such as ensuring that the current date value is formatted correctly:

  <Script runat="server">   Public Sub Page_Load(sender As Object, e As EventArgs)   ' Use ToString("D") to format display: Week Day, Month Day, Year   lblDateTime.Text = DateTime.Now.ToString("D")   End Sub   </Script>   Server Date/Time: <b><asp:label id="lblDateTime" runat="server" /></b>  

The default settings of culture, en-US , would display:

Server Date/Time: Tuesday, January 08, 2002

While the localized setting, using fr-FR , would display:

Server Date/Time: mardi 8 janvier 2002

Compilation Options

The settings defined in the <compilation> section of machine.config allow you to control some of the settings that ASP.NET uses to compile ASP.NET resources, such as ASP.NET pages. A common setting that you can change if you don't want Visual Basic .NET to be the default language, is the defaultLanguage option. This is where you can also add additional CLR compilers, such as COBOL or Perl. Within the <compilation> settings, you can also name the assemblies (compiled reusable code libraries) that ASP.NET will link to when compiling ASP.NET application files.

The following code is the default configuration from machine.config :

 <configuration>    <system.web>  <compilation debug="false" explicit="true" defaultLanguage="vb">   <compilers>   <compiler language="c#;cs;csharp" extension=".cs"   type="Microsoft.CSharp.CSharpCodeProvider,System" />   <compiler language="vb;visualbasic;vbscript" extension=".vb"   type="Microsoft.VisualBasic.VBCodeProvider,System" />   <compiler language="js;jscript;javascript" extension=".js"   type="Microsoft.JScript.JScriptCodeProvider,Microsoft.JScript" />   </compilers>   <assemblies>   <add assembly="mscorlib"/>   <add assembly="System"/>   <add assembly="System.Web"/>   <add assembly="System.Data"/>   <add assembly="System.Web.Services"/>   <add assembly="System.Xml"/>   <add assembly="System.Drawing"/>   <add assembly="*"/>   </assemblies>   </compilation>  </system.web> </configuration> 

The <compilation> tag supports the following attributes:

  • debug .

  • defaultLanguage .

  • tempDirectory .

  • strict .

  • explicit .

  • batch .

  • batchTimeout .

  • maxBatchSize .

  • maxBatchGeneratedFileSize .

  • numRecompilesBeforeAppRestart .

The debug attribute enables you to debug ASP.NET application files with the command line debugger or Visual Studio .NET. When you build a project with Visual Studio .NET, it creates its own web.config ile and sets the debug to true or false depending on whether the project is in debug mode (a compile option). The default setting is false .

One of the side benefits of setting debug="true" is that ASP.NET will save the source file it generates, which you can then view! Let's look at an example of how this is done. ASP.NET takes a source file, such as the ASP.NET page in the following code snippet, compiles it, and saves the resulting .NET .dll file to disk in a directory under \WINNT\Microsoft.NET\Framework\[version]\Temporary ASP.NET Files\ . Directories found within this directory are unique entities that ASP.NET creates automatically.

Let's look at what happens when we set debug="true" . First, set debug to "true" in machine.config . Next , you need a simple ASP.NET page. This one is written in VB.NET:

  <Script runat="server">   Public Sub Page_Load(sender As Object, e As EventArgs)   lblHello.Text = "Hello!"   End Sub   </Script>   <b><asp:label id="lblHello" runat="server" /></b>  

You then need to request this page through a browser. The URL that I'm using to make the request is http://localhost/Configuration/Compilation/Hello.aspx.

You can then navigate to the ...\Temporary ASP.NET Files\ directory. ASP.NET will create the directory based on the name of the web application. In this case, the Configuration folder is marked as a web application. If you do a file search in the Configuration folder for *.vb , you will find a single Visual Basic file. Mine is named ohgemg-9.0.vb “ the name of the file is hashed to create a unique value. If you open this file in Visual Studio .NET, you'll see the screen depicted in Figure 13-11:

click to expand
Figure 13-11:

Here, you can see your code, lblHello.Text = "Hello!" along with the rest of the code that ASP.NET automatically generated to build the ASP.NET page. If you ever want to know what an ASP.NET page is doing behind the scenes, this is a great resource.

Changing the Default Language

The defaultLanguage attribute of <compilation> allows you to configure the default language that ASP.NET resources use. In code samples within this book, we have been using both page directives and script blocks. When we have shown code examples in C#, or other languages, we have used one of three options to override the default language of Visual Basic .NET.

The options are shown here:

  <%@ Page Language="C#" %>   <%@ WebService Language="C#" %>   <Script Language="C#" runat=server>   ...   </Script>  

If you code your application in C#, set the defaultLanguage attribute in the <compilation> tag:

  <compilation debug="false" explicit="true" defaultLanguage="C#">  

The language value specified for defaultLanguage must be one of the supported languages named in a <compiler> sub-element of <compilers> .

Additional <compilation> Attributes

Here are the additional attributes for the <compilation> element:

  • tempDirectory :The directory in which ASP.NET stores compiled assemblies. By default, this is \WINNT\Microsoft.NET\Framework\[version]\Temporary ASP.NET Files\ . However, the temporary directory may be changed using this option.

  • strict :This attribute controls the Option Strict compile option for Visual Basic .NET. By default it is set to false .

  • explicit :This attribute controls the Option Explicit compile option for Visual Basic .NET. By default it is set to true .

  • batch :The batch attribute controls whether batch compilation is supported. By default it is set to true , indicating that ASP.NET will attempt to compile all resources found in a given application upon the first request.

  • batchTimeout :The period of time, in seconds, for batch compilation to complete. If the compilation cannot complete within the specified time, only the requested resource is compiled. The default value is 15 seconds.

  • maxBatchSize :Controls the maximum number of batch compiled resources. By default this is set to 1000.

  • maxBatchGeneratedFileSize :Controls the maximum size in KB of the file generated during batch compilation. By default this is set to 3000 KB.

  • numRecompilesBeforeAppRestart :Controls the number of compilations allowed before the application is automatically recycled. The default is 15.

The <compilation> setting defines two sub-elements:

  • <compilers> :Section pertaining to the supported .NET language compilers for ASP.NET.

  • <assemblies> :Section that allows you to define .NET assemblies that are added to the compilation of ASP.NET application files.

<compilers>

The <compilers> element is the parent element for <compiler> entries. The <compiler> element, which is a sub-element of the <compilers> tag, allows you to name and configure the languages supported by ASP.NET. By default, ASP.NET supports the three languages that .NET ships with (Visual Basic .NET, C#, JScript .Net).

The <compiler> element has four attributes:

  • language :The value used when you name the language from Language = [setting] within your code files.

  • extension : Names the extension for the code files when using a codebehind model.

  • type :Both the language and extension settings are used so that ASP.NET knows the class named in the type attribute to use to compile the resource.

  • warningLevel :Controls the compiler warning level setting.

For example, to include support for Perl, you'd need to make the following entry:

 <configuration>    <system.web>  <compilation>   <compilers>   <compiler language="Perl" extension=".pl"   type="[Perl CodeDOM Class]"/>   </compilers>   </compilation>  </system.web> </configuration> 

<assemblies>

The <assemblies> element is used to add, remove, or clear assemblies that should be used in the compile path of the ASP.NET applications. Assemblies are units of compiled application logic, and contain classes and other information necessary for .NET applications to load and use the compiled application logic.

We need some assemblies to be available intrinsically for ASP.NET, since we rely upon classes found in these assemblies in the ASP.NET applications. The following assemblies are referenced in machine.config (and are therefore available in all ASP.NET applications):

  • mscorlib.dll :Contains the base classes such as String , Object , int , and so on, and the Root namespace of System . Additionally, defines other namespaces such as System.IO , and so on.

  • System.dll :Contains the code generators for C#, Visual Basic .NET, and JavaScript. Extends definition of the System namespace, and includes additional namespaces such as Net (the namespace for the network class libraries).

  • System.Web.dll :The classes and namespaces used and required by ASP.NET, such as HttpRequest , Page , and namespaces such as System.Web.UI for ASP.NET server controls.

  • System.Data.dll :Contains the classes and namespaces belonging to ADO.NET.

  • System.Web.Services.dll :Contains the classes and namespaces such as System.Web.Services used for building ASP.NET web services.

  • System.Xml.dll :Contains the XML classes and namespaces such as XmlDocument or XmlNode, and namespaces, such as the System.Xml.XPath .

  • System.Drawing.dll :Contains classes and namespaces for working with images such as Bitmap .

  • System.EnterpriseServices.dll :Contains classes and namespaces for COM+ integration and transactions.

  • * :The special * entry tells ASP.NET also to include all assemblies found within ASP.NET application bin\ directories. bin\ directories, discussed in the previous chapter, are used to register assemblies that are specific to a web application.

These assemblies are added using an <add> tag within <assemblies> and the .dll extension of the assembly is not included in the reference.

<add>

The <add> tag is used to name .NET assemblies you wish to have available to your ASP.NET applications. For example, to use the classes found in System.DirectoryServices.dll in your web application, you need to add a reference for it in the web.config file (alternatively, you could add it to machine.config , and make it available to all applications):

 <configuration>    <system.web>       <compilation>  <assemblies>   ...   <add assembly="System.DirectoryServices" />   ...   </assemblies>   </compilation>  </system.web> </configuration> 

<remove>

The <remove> tag is used to remove assemblies. This is very useful if machine.config names assemblies using the <add> tag, but you wish to restrict the use of assemblies within the ASP.NET application. For example, machine.config lists System.Drawing as one of the assemblies to include in the compilation of ASP.NET application files. If you didn't need the classes found in System.Drawing.dll , you could ensure that ASP.NET didn't compile the assembly as part of the application. You could add an entry to a web.config file that used the <remove> tag to remove the System.Drawing assembly for only that application:

 <configuration>    <system.web>  <compilation>   <assemblies>   <remove assembly="System.Drawing" />   </assemblies>   </compilation>  </system.web> </configuration> 

<clear>

The <clear> entry goes one step further than the <remove> tag. Whereas the <remove> tag removes individual assemblies, <clear> removes any and all assembly references. When <clear> is used, no inherited assemblies are loaded.

The compilation settings in machine.config give a granular control over many settings that apply to ASP.NET application files, such as the default language, support for other compilers, and the assemblies (libraries of code) you want available by default within your application.

Although the compilation settings allow you to control how the application is compiled, they do not allow you to control how the application is run. To control the identity of the process that ASP.NET uses for compiling, processing, and servicing requests of your ASP.NET application, you have the identity settings.

Controlling the Identity of Execution

You can use the <identity> setting of machine.config (note that identity can be set in web.config files as well) to define which Windows user to impersonate when making requests from the operating system.

Note

This is separate from the trust level assigned to a particular application. The trust level, set in the configuration system for an application, determines what a particular application may or may not do. Trust levels are used to sandbox applications.

Three attributes are used with <identity> :

  • impersonate :The impersonate attribute of <identity> is a Boolean value that determines the Windows NT user the ASP.NET worker process runs under. If impersonate="true" , ASP.NET will run under the identity provided by IIS. If set to true , this would be IUSR[server name] , or whatever identity that IIS is configured to impersonate. However, if Windows NT authentication is enabled on the web server, ASP.NET will impersonate the authenticated user. Alternatively, you can name a Windows NT user and password for the ASP.NET process to run as. The default setting of impersonate is False .

  • userName :Available when impersonate="true" , the name value names a valid Windows NT account to impersonate.

  • password :Complementary to name , the password of the user to impersonate .

As mentioned, the default setting is impersonate="false" . Let's look at some examples where ASP.NET runs with impersonate="true" allowing the impersonation to flow from IIS, as well as configuring the user/password for ASP.NET to run as.

Impersonating the IIS User

To impersonate the user that IIS uses, you first need to set impersonate to "true" :

 <configuration>    <system.web>  <identity impersonate="true" />  </system.web> </configuration> 

To test impersonation, you can use the following ASP.NET page, written in Visual Basic .NET:

  <%@ Import Namespace="System.Security.Principal" %>     <Script runat="server">   Public Sub Page_Load(sender As Object, e As EventArgs)   lblIdentity.Text = WindowsIdentity.GetCurrent().Name   End Sub   </Script>   Current identity is: <asp:label id="lblIdentity" runat="server" />  

This code simply uses the WindowsIdentity class's GetCurrent method to return the name of the Windows user the request is processed as.

On my server, when impersonate="false" , the result of a request to this page is:

Current identity is: NT AUTHORITY\SYSTEM

When impersonate="true" , the result is:

Current identity is: RHOWARD-LAPTOP\IUSR_RHOWARD-LAPTOP

ASP.NET is impersonating the Windows user that IIS is using to process the request. Here, this is the IUSR_[machine name] Windows account that IIS uses for anonymous requests. If you configured IIS to use a different anonymous account, or enabled IIS security to support NTLM authentication, you would see a different result. For example, if we enable NTLM authentication for the server (see Chapter 14 for details on NTLM authentication), when I run the code I see:

Current identity is: REDMOND\RHOWARD

Since NTLM authentication is enabled, as is impersonation with ASP.NET, ASP.NET impersonates the Windows users that IIS NTLM authenticates “ in this case, the user RHOWARD in the domain REDMOND.

The last option you can configure with identity is to explicitly name a username and password. Note that the username and password values are stored in clear text in the configuration system:

 <configuration>    <system.web>  <identity impersonate="true"   username="ASPNET_Anonymous"   password="93%dk12"   />  </system.web> </configuration> 

In this example, we've identified a user ASPNET_Anonymous as the user for ASP.NET to impersonate.

Keep in mind that the user impersonated needs to have the necessary file access permissions “ ASPNET_Anonymous needs to have access to the necessary ASP.NET files and common directory paths. Please see the next chapter for more details on ASP.NET security.

Controlling the identity of the impersonation account used by ASP.NET allows you to have granular system-level control over what a particular user may or may not do. However, you also have to provide the impersonation account with the appropriate levels of access to be able to accomplish meaningful work in your system.

Extending ASP.NET with HTTP Handlers

ASP.NET builds upon an extensible architecture known simply as the HTTP runtime . The runtime is responsible for handling requests and sending responses. It is up to individual handlers, such as an ASP.NET page or web service, to implement the work to be done on a request.

Similar to the way IIS supports a low-level API known as ISAPI, for letting developers implement custom solutions (such as building a JSP implementation that runs on IIS), ASP.NET implements a similar concept with HTTP Handlers. A request is assigned to ASP.NET from IIS. ASP.NET then examines entries in the <httpHandlers> section, based on the extension ( .aspx for example) of the request to determine which handler the request should be routed to.

The most common entry used is the .aspx extension. The following entry in machine.config is for the HTTP Handler used for the .aspx extension (as well as several other familiar extensions):

 <configuration>    <system.web>  <httpHandlers>   <add verb="*" path="*.aspx"   type="System.Web.UI.PageHandlerFactory,System.Web" />   <add verb="*" path="*.asmx"   type="System.Web.Services.Protocols.WebServiceHandlerFactory,   System.Web.Services" validate="false"/>   <add verb="*" path="*.ascx"   type="System.Web.HttpForbiddenHandler,System.Web" />   <add verb="*" path="*.config"   type="System.Web.HttpForbiddenHandler,System.Web" />   </httpHandlers>  </system.web> </configuration> 

In this configuration code, four common handlers are identified (the actual machine.config file identifies about 18 entries). We have the HTTP handlers for pages ( .aspx ), web services ( .asmx ), user controls ( .ascx ), and configuration ( .config ).

Both page and web services map to actual classes, while user controls and configuration map to a special handler called HttpForbiddenHandler . This handler explicitly denies access to these extensions when requested directly, so a request for Address.ascx or web.config will send back an access denied reply.

As mentioned, HTTP Handlers are the ASP.NET equivalent of IIS ISAPI extensions. However, unlike ISAPI, which was only accessible to developers who could code C++, HTTP Handlers can be coded in any .NET language “ Visual Basic .NET developers can now author the equivalent of an ISAPI extension.

Let's look at a simple HTTP Handler written in Visual Basic .NET:

  Imports System   Imports System.Web     Public Class HelloWorldHandler   Implements IHttpHandler     Sub ProcessRequest(ByVal context As HttpContext) _   Implements IHttpHandler.ProcessRequest   Dim Request As HttpRequest = context.Request   Dim Response As HttpResponse = context.Response     Response.Write("<html>")   Response.Write("<body>")   Response.Write("<h1> Hello " + _   Request.QueryString("Name") + "</h1>")   Response.Write("</body>")   Response.Write("</html>")   End Sub     Public ReadOnly Property IsReusable As Boolean _   Implements IHttpHandler.IsReusable   Get   Return True   End Get   End Property   End Class  

Here, we have written a Visual Basic .NET HelloWorldHandler class, which implements the IHttpHandler interface. This interface requires that we implement a single method, ProcessRequest , as well as a single property, IsReusable . Within the ProcessRequest method, which is responsible for processing the request, we Response.Write some simple HTML. Within the body of the HTML, we use the Request to access the Name parameter passed on the query string.

To register this handler, you first must build it using either the command line compilers or Visual Studio .NET. You can then deploy the compiled .dll file to an ASP.NET bin directory and add the entry into your configuration file (in this particular case, a web.config file). The <add> tag of <httpHandlers> is used.

Adding Handlers

The <add> tag is used to name a class that implements either the IHttpHandler or the IHttpHandlerFactory interface. All HTTP Handlers must implement one of these interfaces so that the HTTP runtime knows how to call them.

The following code snippet shows the format used for this tag:

 <configuration>    <system.web>  <httpHandlers>   <add verb="[HTTP Verb]" path="[Request Path]" type="[.NET Class]"/>   </httpHandlers>  </system.web> </configuration> 

There are three attributes within the <add> tag that tell ASP.NET how the HTTP Handler is to be interpreted:

  • verb:This attribute instructs the HTTP runtime about the HTTP verb type that the handler services request. Values for the verb attribute include asterisks (*), which instructs the HTTP runtime to match on all HTTP verbs, or a string value that names an HTTP verb (for example, the HTTP GET verb, verb="Get" ), or a string value of semi- colon -separated HTTP verbs (for example, verb="Get; Post; Head" ).

  • path :This attribute instructs the HTTP runtime as to the request path, for example /MyApp/test.aspx , that this HTTP Handler is executed for. Valid values for path include asterisks ( * ) with an extension ( *.aspx ), which instruct the HTTP runtime to match only resources that match the extension, or a string value with an extension. You can name one resource that maps to an HTTP Handler. A good example here is the Trace.axd HTTP Handler, which uses the path="trace.axd" value.

  • type :This attribute names the .NET class that implements the HTTP Handler code. The value for type follows the format [Namespace].[Class], [Assembly name] .

If you compile the preceding sample, HelloWorldHandler.vb , to an assembly named Simple.dll , you could make the following entry in a configuration file:

 <configuration>    <system.web>       <httpHandlers>  <add verb="*" path="HelloWorld.aspx"   type="Simple.HelloWorldHandler, Simple"/>  </httpHandlers>    </system.web> </configuration> 

This configuration entry names an assembly, Simple , that contains a HelloWorldHandler class. ASP.NET will assume that HelloWorldHandler implements the IHttpHandler interface. We then identify the path and verb that the ASP.NET HTTP runtime uses to route to this handler. In this case, the HTTP runtime has been told that we wish to route on all verbs (via the * ) and that we will service requests for HelloWorld.aspx .

Note

You could use a custom extension, such as *.wrox , but this would further require you to map this .wrox extension to ASP.NET in ISS Manager (as discussed in the previous chapter).

We are now ready to service requests for this handler. If you open a web browser and point it to the web application that contains bin\Simple.dll as well as the web.config file that we defined, you can make a request for .../HelloWorld.aspx?Name=Rob as shown in Figure 13-12:

click to expand
Figure 13-12:

ASP.NET maps the request HelloWorld.aspx to the HTTP Handler we built called Simple.dll . The result is that the HTTP Handler is executed and the request is served . This is a somewhat simple example, but it let's you envision the types of applications that could be created. What if this HTTP Handler was declared in machine.config and you didn't want a given application to have access to it? In that case, you can use the <remove> tag of the <httpHandlers> section.

Removing Handlers

The <remove> tag can be used to override <add> entries that are either inherited or declared within the same configuration file. This is useful for removing HTTP Handlers from some web applications or commenting out HTTP Handlers so that the functionality is unavailable to end users:

  <remove verb="[http verb  *]" path="[path]"/>  

A good example is the trace.axd HTTP Handler used for tracing, which you may decide not to support in all of your web applications. machine.config defines the following entry for the trace.axd :

 <configuration>    <system.web>  <httpHandlers>   <add verb="*"   path="trace.axd"   type="System.Web.Handlers.TraceHandler,System.Web"   />   </httpHandlers>  </system.web> </configuration> 

You could remove support of this handler in web applications by creating a web.config file and making the following entry using the <remove> tag. The web application using this web.config file will generate a file not found error when a request is made for trace.axd :

 <configuration>    <system.web>  <httpHandlers>   <remove verb="*" path="trace.axd"/>   </httpHandlers>  </system.web> </configuration> 

HTTP Handlers allow you, at a low-level, to handle the application request. You can build a simple example, such as the HelloWorld example, or could write more complex examples that take over well- known extensions such as .jpg to add additional functionality (for example, a request for chart.jpg?x=10&y=13 could draw a graph). The opportunities are endless! However, what if you simply want to look at the request? Rather than replace the functionality that ASP.NET pages provide you with, you may simply want to examine the request before or after the HTTP Handler processes it. For this, you have HTTP Modules.

Extending ASP.NET with HTTP Modules

Whereas HTTP Handlers allow you to map a request to a specific class to handle the request, HTTP Modules act as filters (note that HTTP Modules are similar in function to ISAPI filters) that you can apply before the handler sees the request or after the handler is done with the request.

ASP.NET makes use of modules for cookieless session state, output caching, and several security- related features. In the advanced topics discussion in Chapter 20, we will look at an HTTP Module that authenticates web service requests. Before the request is 'handled' by the appropriate .asmx file, the HTTP Module looks at the request, and determines if it is a SOAP message. If it is a SOAP message, it extracts the username and password values from the SOAP header.

As it relates to configuration, there are the same three settings as for HTTP Handlers: <add> , <remove> , and <clear> . <add> is the only tag that differs from HTTP Handlers.

Adding Modules

The <add> entry for <httpModules> simply names the module and references the class that implements the IHttpModule interface and the assembly the class exists within. Just as HTTP Handlers implement a common interface, IHttpHandler , we have an interface that modules implement. The following code snippet is an <httpModules> entry for the OutputCache module from machine.config :

 <configuration>    <system.web>  <httpModules>   <add name="OutputCache"   type="System.Web.Caching.OutputCacheModule,System.Web" />   </httpModules>  </system.web> </configuration> 

Similar to HTTP Handlers, HTTP Modules require that you implement an interface. In this case, that interface is IHttpModule . If you implement this interface, you can build a simple HTTP Module. Handlers and modules are definitely an advanced feature of ASP.NET. They give complete control over the request and allow you to look at the request as it comes in, execute the request, and then look at the request again as it goes out.

The machine.config file gives you access to a number of advanced configuration features such as the two we just examined. Another configuration option found in machine.config is the process model setting. The process model settings allow you to configure the ASP.NET Worker Process.

Configuring the ASP.NET Worker Process

Unlike ASP, ASP.NET runs in a separate process from IIS. When code misbehaved in ASP “ say we forgot to free memory in a COM object “ the leak could degrade the server performance and possibly crash the process ASP ran in. In some cases, this could crash the IIS process, which would result in the application not servicing requests!

ASP.NET, on the other hand, was designed to take into account the errors that can and will occur within the system. Rather than running in process with IIS, ASP.NET runs in a separate worker process, aspnet_wp.exe . ASP.NET uses IIS only to receive requests and to send responses (as a request/response broker). IIS is not involved in executing any ASP.NET code. The ASP.NET process can come and go, and it doesn't affect the stability of IIS in any way.

Note

When using ASP.NET 1.1 on IIS 6.0, the new IIS worker process settings are used, and the settings in the <processMode /> section of machine.config are ignored.

You can view the ASP.NET process ( aspnet_wp.exe ) through the Windows Task Manager after a request for an ASP.NET resource has been made, as the process starts when ASP.NET applications are being used. To view the process, first request an ASP.NET resource and then open up the Windows Task Manager (press Control+Shift+Escape). Once the Task Manager is open, switch to the Processes tab and look for aspnet_wp.exe in the Image Name column as shown in Figure 13-13:

click to expand
Figure 13-13:

Figure 13-13 shows the aspnet_wp.exe process, the process ID (PID) of 1744, the CPU usage as 0%, CPU time, and memory usage in KB.

The <processModel> section of machine.config is used to configure ASP.NET process management. These settings can only be made in machine.config as they apply to all ASP.NET applications on that machine. Within the <processModel> settings, you can configure options such as which processor each ASP.NET worker process should affinitize with, and can additionally configure settings such as automatically recycling the process after n requests or n amount of time.

Note

An important but subtle change in the final released version of ASP.NET is the Windows identity that the ASP.NET worker process runs as. In previous beta versions it was the System account. The final version uses a special Windows account created when the .NET Framework is installed: aspnet. For more details on the implications of these changes, please see the chapter on security. This, of course, is still configurable using the username/password attributes of the <processModel ...> settings.

The following code shows the default machine.config settings:

 <configuration>    <system.web>  <processModel   enable="true"   timeout="Infinite"   idleTimeout="Infinite"   shutdownTimeout="0:00:05"   requestLimit="Infinite"   requestQueueLimit="5000"   restartQueueLimit="10"   memoryLimit="60"   webGarden="false"   cpuMask="0xffffffff"   userName="machine"   password="AutoGenerate"   logLevel="Errors"   clientConnectedCheck="0:00:05"   comAuthenticationLevel="Connect"   comImpersonationLevel="Impersonate"   responseRestartDeadlockInterval="00:09:00"   responseDeadlockInterval="00:03:00"   maxWorkerThreads="25"   maxIoThreads="25"   serverErrorMessageFile="[Not Configured]"   />  </system.web> </configuration> 

As you can see, there are 21 options that you can configure. Let's examine all of these, starting with the enable option.

Enabling the ASP.NET Worker Process

The enable attribute is a Boolean setting used to determine if ASP.NET should run in a separate worker process, be the default, or in-process with IIS. If you set it to false , the <processModel> settings are ignored:

  enable="[true  false]"  

If you do set enable to "false" , you won't see the aspnet_wp.exe show up in the task manager; it's now loaded in-process with IIS.

Note

IIS has to be stopped and restarted if the enable option is changed.

It is recommended that this setting be left as true so that applications can reap the benefits that the ASP.NET worker process provides.

Timing Out the Process

The timeout attribute determines how long the worker process will live before a new worker process is created to take its place. The default value is Infinite . However, you can also set this value to a time using an HH:MM:SS format:

  timeout = "[Infinite  HH:MM:SS]"  

This value can be extremely useful if a scenario exists where the application's performance starts to degrade slightly after running for several weeks, such as in the case of a memory leak. Rather than having to manually start and stop the process, ASP.NET can restart automatically:

 <configuration>    <system.web>       <processModel          enable="true"  timeout="336:00:00"  idleTimeout="Infinite"          ...          serverErrorMessageFile="[Not Configured]"       />    </system.web> </configuration> 

In this setting, the ASP.NET worker process will recycle itself automatically after approximately 336 hours (two weeks). The clock starts ticking on the life of the process when the process is started (on the first request after the changes have been made).

Shutting Down the Process Automatically

You can shut down the ASP.NET worker process automatically using the idleTimeout option. idleTimeout is used to shut down the worker process when it has not served any requests within a given period of time. By default, it is set to Infinite and once started, will not shut down. You can also set this value to a time using the HH:MM:SS format:

  idleTimeout = "[Infinite  HH:MM:SS]"  

Starting a process for the first request can make a performance hit on the server. Two scenarios for use of idleTimout include:

  • To release resources that ASP.NET is using when not actively servicing requests.

  • To recycle processes during down time. You could configure idleTimout to shutdown after 20 minutes of no requests. For example, if you don't receive requests between the hours of midnight to 3 a.m., ASP.NET can quietly exit the process. When a new request comes in, a new process is started.

Graceful Shutdown

The shutDownTimeout attribute is used to specify how long the worker process is given to shut itself down gracefully before ASP.NET calls the kill command on the process “ kill is a low-level command that forcefully removes the process. By default, shutDownTimeout is set to five seconds, but this is configurable:

  shutDownTimeout = "[HH:MM:SS]"  

This is a very useful configuration setting for processes that have crossed some threshold and appear to have crashed. ASP.NET can kill the process after it is given the opportunity to shutdown gracefully.

Recycling the Process after n Requests

requestLimit allows you to configure ASP.NET to recycle after a certain number of requests are served. The default value is Infinite , no request limit, but you can also set it to a number:

  requestLimit = "[Infinite  int]"  

If the performance of the application degrades after a certain number of requests, for example 5000, you can configure the requestLimit property to a threshold of 5000. ASP.NET will then recycle the process after 5000 requests.

You can take this example a step further and see the requestLimit being enforced by ASP.NET, if you:

  • Set the requestLimit to 5.

  • Save your machine.config file.

  • Open the Windows Task Manager, view the aspnet_wp.exe process, and take note of the process ID.

Next, if you make more than five requests for an ASP.NET application file, ASP.NET will recycle the process. To see this, go back and check the process ID of aspnet_wp.exe; after five requests, you will have a new process ID.

Recycling the Process If Requests Are Queued

The requestQueueLimit option instructs ASP.NET to recycle the worker process if the number of queued requests limit is exceeded. ASP.NET uses threads within a process to service user requests. If a thread is blocked or is unable to service requests, requests can be queued. The requestQueueLimit option gives you the opportunity to detect if requests are queued and recycle the process if the queued requests exceed the allowed limit. The default setting is 5000:

  requestQueueLimit = "[int]"  

Recycling the Process If Too Much Memory is Consumed

The memoryLimit option determines how much physical memory the worker process is allowed to consume before it is considered to be misbehaving. The default value is 60 (representing 60 percent):

  memoryLimit = "[int]"  

You should never 'leak' memory in a .NET application since the CLR is performing garbage collection (memory management) for you. However, since .NET also supports the use of native code, and is able to interoperate with COM, it is possible to leak memory if either the native code or the COM object is mismanaging memory.

The simplest way to demonstrate the use of memoryLimit is with a simple ASP.NET page that fills application state memory with useless information “ this simulates a memory leak. The following page is written in Visual Basic .NET:

  <%@ Import Namespace="System.Diagnostics" %>   <%@ Import Namespace="System.Text" %>   <script runat=server>   Sub Page_Load(Sender as Object, E as EventArgs)   Dim i As Integer   Dim garbage As New StringBuilder   If Application("garbage") Is Nothing Then   Dim c As Integer   For c=1 to 1000   garbage = garbage.Append("xxxxxxxxxx")   Next c   Application("garbage") = garbage   Else   garbage = Application("garbage")   End If     For i=1 to 500   ' Make sure we create a unique entry   Application(i.ToString + DateTime.Now.ToString("r")) = _   (garbage.ToString() + DateTime.Now.ToString("r"))   Next i     Dim p as ProcessInfo   p = ProcessModelInfo.GetCurrentProcessInfo()   ProcessID.Text = p.ProcessID.ToString()   End Sub   </script>   <html>   <body>   <h2>The Process ID serving this request is:   <asp:label id="ProcessID" forecolor=red runat=server/>   </h2>   <h2>There are <%=Application.Count.ToString()%>   items in Application state memory.   </h2>   </body>   </html>  

We can then set memoryLimit to a very low threshold, such as 5 percent:

 <configuration>    <system.web>       <processModel          ...          restartQueueLimit="10"  memoryLimit="5"  webGarden="false"          ...       />    </system.web> </configuration> 

Next, we make requests for the ASP.NET page that simulates a leak. Again, watch the aspnet_wp.exe worker process in the Task Manager. As the resource is requested, you will see memory increase for the process. Finally, when 5 percent of memory has been utilized, you will see a new process appear next to the old process, which disappears. From the end user's perspective, the application just keeps running. Figure 13-14 shows the process (PID 1572) that has exceeded the memory threshold, and the new process (PID 1972) that has just started:

click to expand
Figure 13-14:

This is also evident in the sample ASP.NET page since we display the process ID.

Supporting Multiple Worker Processes

There are usually two ways to scale an application; write tighter and better code, or simply add more hardware. The term web farm is used to describe a collection of nearly identical web servers that can be used to service requests. As the user-base grows, we simply add more servers into the server farm and are able to increase the scalability of our application. This is very cost effective since adding a server is, in most cases, less expensive than rewriting the entire application.

When you build a server farm, you essentially put all the required hardware in place to host another process that can service requests. A new option that ASP.NET now supports is a web garden “ multiple processes on the same server.

A web garden lets you host multiple ASP.NET worker processes on a single server, thus providing the application with better hardware scalability.

Note

Web garden mode is only supported on multi-processor servers. To support a web garden with ASP.NET, we use two inter-related <processModel> configuration settings:

  • webGarden :The webGarden attribute determines whether web garden mode is enabled. The default setting is false .

      webGarden = "[true  false]"  
  • cpuMask :The cpuMask (a hexadecimal value) is used to determine which processors should be affinitized to ASP.NET worker processes when webGarden is set to "true" . The default value is all processors, as 0xFFFFFFFF is a bit mask of 11111111111111111111111111111111 . In other words, if the server had 32 processors, each would be affinitized to its own ASP.NET worker process.

      cpuMask="0xffffffff""  

The settings of cpuMask do nothing if webGarden="false" .

Setting the Identity of the Process

The username and password settings found in <processModel> are used to control the user that the ASP.NET Worker process runs as. By default, it is a restricted ASPNET Windows account. However, by using these settings, you can instruct the process to execute under another Windows identity or the System account. For example, if you create a Windows user ASPNET_WP with a password of &dotnet$12 , you could set these as the username and password values:

 <configuration>    <system.web>       <processModel          ...          cpuMask="0xffffffff"  userName="ASPNET_WP"   password="&dotnet"  logLevel="Errors"          ...       />    </system.web> </configuration> 

When you view the process information in the Windows Task Manager, you'll see that the process is executing as user ASPNET_WP rather than ASPNET . To run as the system account, as previous Beta versions of ASP.NET did, simply change the username/password to the following values:

  userName="System"   password="AutoGenerate"  

Logging Process Events

The logLevel attribute allows you to configure how the ASP.NET worker process logs events. The default setting is to log only errors:

  logLevel="[All  None  Errors]"  

In addition to logging errors that occur, you can also configure to log all events or log none of the events. The events are written to the Windows Application Event Log.

Checking If the Client Is Connected

When an application is slow to respond, some users will simply issue a new request from the browser by hitting page refresh several times. This will force the web server to do unnecessary work, since the client may make 15 requests but only the last request completes “ the web server will still do the associated work for the other 14 requests.

The clientConnectedCheck setting allows you to check if the client is still connected at timed intervals before performing work. Thus, rather than processing all the requests, ASP.NET will only process requests where the client is expecting a response. The other requests that sit in the queue waiting for work can then be discarded.

The default setting for this attribute is 5 seconds, which means that for requests that are queued, ASP.NET will check if the client is connected every 5 seconds. If not, the request can be discarded from the queue.

The following settings are supported:

  clientConnectedCheck="[HH:MM:SS  Infinite]"  

The process model settings of ASP.NET introduce a new level of flexibility and stability for our applications. All of the options for controlling the processing, including the identity that the process runs as, as well as which CPU the process should affinitize to, are provided.

COM Impersonation and Authentication

For COM integration, there are two <processModel> attributes that control both authentication level and impersonation level:

  • comAuthenticationLevel :Controls the level of authentication for DCOM security. The default is set to Connect .

  • comImpersonationLevel :Controls the authentication level for COM security. The default is set to Impersonate .

Process Restarts due to Deadlock

In some rare scenarios, the ASP.NET worker process may get into a deadlocked state. The process has work to complete (queued requests), but due to some unknown reason, the process is no longer responding to responses. There are two <processModel> attributes that control the behavior of the ASP.NET worker process during a deadlock:

  • responseDeadlockInterval :A deadlock is considered to exist when there are requests queued and no responses have been sent during this interval, after which the process is restarted. By default, this is set to 3 minutes. The format is 00:03:00 .

  • responseRestartDeadlockInterval :This interval exists to prevent thrashing, for example, continuous stopping and restarting of processes due to deadlock. By default, this is set to 9 minutes, with the format 00:09:00 . If a process has been restarted due to a deadlock issue, this specifies the amount of time that must elapse before another deadlock process restart is initiated.

Controlling Worker Process Threads

There are two attributes within <processModel> that control the maximum number of worker threads and I/O threads used by the ASP.NET worker process:

  • maxWorkerThreads :The maximum number of threads that exist within the thread pool of an ASP.NET worker process. The default is 25. Note that this does not mean that 25 threads exist at all times. Rather, the thread pool dynamically manages the size of the threads available.

  • maxIoThreads :The maximum number of I/O threads that exist within the ASP.NET worker process. The default is 25.

    Note

    It is recommended that neither of the options be changed unless you understand exactly what the implications are.

Server Unavailable Error Message

When the ASP.NET worker process is recycling, it is possible to encounter a Server Unavailable error message. The process model's serverErrorMessageFile attribute allows you to control the contents of the error message. The location of the file is relative to machine.config , the contents of which will be returned if a server unavailable error message is required.

Machine Key

ASP.NET uses a key to encrypt or hash some data so that the data is only accessible from the server that created the data. In a single server environment, we will never touch this setting. However, in a multi-server environment in which a request can be directed to a farm of web servers, each server in the farm needs to share the same machine key. This way, server A and server B can both encrypt, decrypt, or hash the same values, so that data created on A can be understood and used on B and vice-versa. The default setting of <machineKey> , from machine.config , is:

  <machineKey validationKey="AutoGenerate"   decryptionKey="AutoGenerate"   validation="SHA1"   />  

There are three settings for <machineKey> :

  • validationKey .

  • decryptionKey .

  • validation .

Let's look at each of these in more detail.

validationKey

The validationKey is used for the validation of data, such as the hash that is done for forms-based authentication cookies. The validationKey is used as part of the hash so that the hash can only be recomputed by ASP.NET applications that have the appropriate validationKey . The default setting is AutoGenerate (ASP.NET automatically creates a value for you), but in a server farm environment, you would need to configure the value and ensure that each server, or application, has the same value. Here are the acceptable settings:

  validationKey="[AutoGenerate  40-128 hex Chars]"  

If a user-defined validationKey is to be used, the recommendation is to use the full 128 chars. This is a valid entry:

  validationKey="0123456789abcdef0123456789abcdef0123456789abcdef   0123456789abcdef0123456789abcdef0123456789abcdef   0123456789abcdef0123456789abcdef"  

Key lengths shorter than 40 or longer than 128 hex chars will generate an error.

decryptionKey

The decryptionKey is used to encrypt data stored in the Forms Authentication cookie. The default is AutoGenerate (ASP.NET automatically generates the value). In a web farm environment, just as with the validationKey , each server needs to use an identical value for this key. The value of the string should be 16 to 48 hex characters . The validationKey ensures that the information is valid; decryptionKey protects the information from prying eyes.

validation

The validation attribute of <machineKey> is used to determine what type of hash is to be computed. Valid values include MD5 , SHA1 , and 3DES .

The hash can be sent to the client along with, for example, the Forms Authentication cookie. The data in the cookie can be validated by the server by re-hashing the values with the validationKey, and the appropriate algorithm determined by validation . If the values match, the data is considered valid. If not, the data represented by the hash is considered invalid (it may have been tampered with). The validationKey guarantees the data is valid. Another setting decryptionKey , guarantees that the plain text of the message cannot be read by nontrusted parties.




Professional ASP. NET 1.1
Professional ASP.NET MVC 1.0 (Wrox Programmer to Programmer)
ISBN: 0470384611
EAN: 2147483647
Year: 2006
Pages: 243

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net