Installing Modules
The modules that comprise the IIS 7.0 feature
set in Windows Vista or Windows Server 2008 can be installed via Windows
Setup. Thanks to the modular architecture, Windows Setup enables very
fine-grained installation of IIS 7.0 features—you can install most of
the IIS 7.0 modules separately (along with all of their supporting
configuration and administration features). You can also install the .NET Extensibility role service, which enables ASP.NET managed modules to run on IIS 7.0, or the ASP.NET
role service, which also installs all of the of the ASP.NET managed
modules and handlers to support fully functional ASP.NET applications.
Windows Setup actually uses the same IIS 7.0
configuration APIs that you can use to manually install a third-party
module on the server. In fact, Windows Setup uses Appcmd.exe, the IIS
7.0 command line tool, to perform module installation, which is just one
of the ways that you can install modules on IIS 7.0.
Installing Native Modules
To install a native module, it must be
registered with the system.webServer/globalModules configuration section
at the server level, in the ApplicationHost.config configuration file.
Because only server administrators have access to this file, the
installation of native modules requires Administrative privileges on the
server. This is by design—allowing native code to execute in the IIS
worker process is a potential security risk, and so Administrators must
be sure to trust the source of the module.
The globalModules section contains an entry for each native module installed on the server, specifying the module name and the module image, which is the physical path to the module DLL.
<globalModules>
<add name="UriCacheModule"
image="%windir%\System32\inetsrv\cachuri.dll" />
<add name="FileCacheModule"
image="%windir%\System32\inetsrv\cachfile.dll" />
<add name="TokenCacheModule"
image="%windir%\System32\inetsrv\cachtokn.dll" />
<add name="HttpCacheModule"
image="%windir%\System32\inetsrv\cachhttp.dll" />
<add name="StaticCompressionModule"
image="%windir%\System32\inetsrv\compstat.dll" />
<add name="DefaultDocumentModule"
image="%windir%\System32\inetsrv\defdoc.dll" />
...
</globalModules>
The image
attribute is an expanded string, which means that it can contain
environment variables (as it does for modules installed by Windows
Setup). This is a good practice to make sure that the
ApplicationHost.config file remains portable and can be copied between
servers and works on servers with different system drives.
Note
Native module DLLs should be located on the
server’s local file system and not on remote network shares. This is
because the server attempts to load them under the application pool
identity and not the identity of the authenticated user or the
configured virtual path (UNC) identity. This identity will not typically
have access to network shares.
The act of registering a native module
instructs IIS worker processes in all application pools to load the
module DLL. The globalModules configuration section is also one of the
few sections that cause IIS worker processes to recycle whenever changes
are made. This means that you can install new modules, or uninstall
existing modules, and IIS will automatically pick up those changes
without needing to manually recycle application pools, restart IIS
services, or run IISRESET.
Note
By adding the module to globalModules, you
are instructing IIS worker processes to load the module DLL. This alone
does not enable the module to run. To do that, you also need to enable
the module on the server or for a particular application.
After the module is installed, it will be
loaded by all IIS worker processes on the server. Unfortunately, IIS 7.0
does not enable native modules to be installed for a particular
application pool, so there is no easy way to load a native module only
into certain application pools and not into others.
Note
IIS
7.0 does provide a way to load native modules selectively into a
specific application pool, by using the application pool name
preconditions. Though loading
native modules in this way is possible, you should not use this
mechanism in most situations because of its management complexity.
However, loading the module alone is not
sufficient to enable the module to execute. It also needs to be enabled
by listing its name in the system.webServer/modules configuration
section. This is an important distinction that serves to provide more
flexible control over the enabled module set. Unlike the globalModules
section, which can only be specified at the server level, the modules
configuration section can be specified at the application level, such as
in the application’s root Web.config. This enables each application to
control the set of enabled modules that process requests to itself.
Typically, a native module is also enabled at
the server level (in ApplicationHost.config) during its installation,
which enables it for all applications on the server by default (except
for applications that specifically remove it in their configuration).
This is the case for most of the built-in native modules.
<modules>
<add name="HttpCacheModule" />
<add name="StaticCompressionModule" />
<add name="DefaultDocumentModule" />
...
<modules>
Each native module is enabled simply by listing its name in the modules collection.
Note
When
the modules section changes, the IIS worker process does not need to
recycle. Instead, it picks up the changes automatically and applies the
resulting module set to subsequent requests. However, ASP.NET
applications whose modules configuration changes will restart.
Uninstalling Native Modules
Caution
Before removing modules, you should
consider the security and performance implications that the module
removal will have on your server.
To uninstall a native module, you need to
remove the corresponding module entry from the globalModules list. This
prevents the module from being loaded in IIS worker processes on the
entire server. Removing the module from globalModules causes all IIS
worker processes to gracefully recycle.
In addition, when the native module is
removed from the globalModules list, references to it in the modules
list also must be removed. Otherwise, all requests to the server or an
application that enables the missing module will generate an "HTTP 500 –
Internal Server Error" error until the module entry is removed.
Typically, you should remove both the globalModules and modules entry
for the module at the same time. However, if you do it in two separate
steps, changing the modules section will not cause a worker process
recycle—IIS will automatically pick up this change by recycling any
affected applications. Be sure to make a configuration backup in case
you need to restore the original configuration later.
When uninstalling a native module that is
part of the IIS 7.0 feature set, you should instead uninstall the
corresponding IIS Windows Setup component (Windows Vista) or Role
Service (Windows Server 2008). Doing so has the benefit of removing the
module binaries and related configuration components, as well as
indicating that the corresponding feature is not installed to the
Windows Setup infrastructure. The binaries remain stored in the OS
installation cache, where they are inaccessible to anyone other than the
OS TrustedInstaller subsystem. This ensures that you can re-install
these modules later, and that any required patches are applied to these
binaries even when the patches are not installed on your server.
Caution
You should not remove built-in IIS 7.0 modules manually. Use Windows Setup instead to uninstall the corresponding feature or role service.
When a custom module is uninstalled and
all IIS worker processes have recycled, you can remove the module binary
from the machine if necessary.
Installing Managed Modules
Managed modules developed using the ASP.NET
APIs are not required to be installed globally on the server. Instead,
they simply need to be enabled in configuration for the application
where they are to be used, similar to classic ASP.NET applications in
previous versions of IIS. This enables simple xcopy deployment of
applications containing managed modules, since unlike native modules
they do not require Administrative privileges to be deployed.
Needless to say, this makes managed
modules very appealing in scenarios in which the application
administrator does not have administrative privileges on the server,
such as on shared hosting servers or departmental servers. Such
applications can now deploy Web server features without contacting the
server administrator to install a global and trusted component, which is
often not possible. In these environments, the server administrator can
constrain the execution of managed modules by limiting the trust of the
ASP.NET applications.
Note
Running managed modules requires
installation of the ".NET Extensibility" Windows Setup component
(Windows Vista) or Role Service (Windows Server 2008). This installs the
ManagedEngine module that enables managed modules to run inside
Integrated mode applications pools.
Installing the "ASP.NET" setup
component/role service automatically installs the ".NET Extensibility"
component and also adds the modules and handler mappings used by the
ASP.NET framework. It also installs the classic ASP.NET handler mappings
that enable application pools that use Classic integration mode to run
ASP.NET using the legacy ASPNET_ISAPI.dll integration mechanism.
To install a managed module, the module
simply needs to be added to the modules configuration section. This is
the same section that enables installed native modules, except managed
modules do not have to be listed in the globalModules configuration
section. The modules section, therefore, provides a unified view of
enabled modules, whether they are native or managed. Because this
configuration section can be delegated down to the application level,
each application can specify the complete set of enabled modules
(managed or native) by using its modules configuration. Here is a more
complete example of the modules configuration section at the server
level after the ASP.NET feature is installed.
<modules>
<add name="HttpCacheModule" />
<add name="StaticCompressionModule" />
<add name="DefaultDocumentModule" />
<add name="DirectoryListingModule" />
...
<add name="FormsAuthentication"
type="System.Web.Security.FormsAuthenticationModule"
preCondition="managedHandler" />
<add name="DefaultAuthentication"
type="System.Web.Security.DefaultAuthenticationModule"
preCondition="managedHandler" />
<add name="RoleManager"
type="System.Web.Security.RoleManagerModule" preCondition="managedHandler"
/>
...
</modules>
As you can see, this section contains both native modules that are simply identified by the name attribute, and managed modules that also specify a type
attribute. For each application, the server resolves the enabled
modules by looking up the native modules’ names in the globalModules
section and directly loading the specified .NET type for managed
modules. The type is the fully qualified .NET type name that refers to
the class that implements this module and resolves to an assembly that
is packaged with the application or an assembly installed in the
machine’s Global Assembly Cache (GAC).
Important
ASP.NET applications that define modules in the
system.web/httpModules configuration section and ASP.NET handler
mappings in the system.web/httpHandlers configuration section need to
have their configurations migrated to the IIS system.webServer/modules
and system.webServer/handlers configuration sections to operate
correctly in Integrated mode. The server will generate a HTTP 500 error
notifying you of this requirement if you attempt to run such an
application in Integrated mode. You can migrate the application easily
by using the Appcmd Migrate Config ApplicationPath command.
Deploying Assemblies Containing Managed Modules
Managed modules are classes
implemented inside .NET assemblies. To support delegated deployment of
managed modules, the server provides several options, as shown in Table 3, for deploying the module assemblies so that they can be added both globally on the server and for a specific application only.
Table 3. Managed Modules and Deployment Options
Deployment Option |
Assembly Location |
Module Registration Location |
---|
Server |
Global Assembly Cache (GAC) |
Server level modules section in ApplicationHost.config |
Application |
Assembly in application’s /BIN directory
OR
Source code in application’s /App_Code directory |
Application’s modules section in application root’s Web.config |
Deploying the Module Assembly at the Server Level
If
the module is to be installed globally for all applications on the
server, it needs to be registered with the machine’s Global Assembly
Cache (GAC). Before the managed assembly can be deployed to the GAC, it
needs to be strongly signed by the developer (for more information on
strongly signing .NET assemblies, see http://msdn2.microsoft.com/en-us/library/xc31ft41.aspx).
In particular, Microsoft Visual Studio makes the signing process
simple. Then, the managed assembly can be added to the GAC by running
the following command.
gacutil.exe /if AssemblyPath
Note
The gacutil.exe command line tool is not
available in the .NET Framework run-time installation that comes with
the operating system, so you have to download the .NET Framework SDK to
obtain it. After you obtain it, though, you can copy the tool to use on
other machines.
After your assembly is added to the Global
Assembly Cache, you can add any of the modules it contains to the server
level modules section by specifying their type. This type name must be
fully qualified; that is, it must contain the full namespace path to the
class (for example, System.Web.Security.FormsAuthenticationModule).
Because when it creates your module, ASP.NET needs to locate an
assembly that contains this type, the assembly must either be listed in
the system.web/compilation/assemblies configuration collection or
included in the type name by using the strong name notation. Here is an
example of a strong name for the built-in FormsAuthentication module.
System.Web.Security.FormsAuthenticationModule, System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=x86
Note
You can get the assembly part of the strong
name by using the gacutil.exe tool you used earlier when you installed
the assembly to the Global Assembly Cache. Run "gacutil.exe /l AssemblyName"
to display the assembly’s strong name signature. You can omit all parts
of the assembly’s strong name signature except for the assembly name,
and ASP.NET will attempt to find the first matching assembly based on
the attributes you do include.
You may wonder why the default module entries
for ASP.NET modules do not specify the strong names and simply specify
the fully qualified type names. This is because their parent assembly, System.Web.dll,
is configured to be automatically preloaded by the ASP.NET applications
(by being listed in the system.web/compilation/assemblies configuration
collection in .NET Framework’s root Web.config). Thus, ASP.NET can
locate the types of built-in ASP.NET modules by searching the preloaded
assemblies, without having to specify the assembly signature in the
module type string.
Deploying the Module Assembly with the Application
If the module is to be available in a specific
application only, it can be xcopy-deployed with that application without
registering anything
globally on the server. In this case, the application owner can provide
the module in two ways: as a compiled .NET assembly DLL in the /BIN
subdirectory of the application root or as a source code file in the
/App_Code subdirectory of the application root.
Note
It is not necessary to sign the assembly in the application’s /BIN subdirectory.
The /App_Code deployment model is more
appropriate for development and test environments, because it enables
editing of the module source code on the live server without recompiling
the module DLL. The /BIN deployment model is recommended for production
servers, because it does not require run-time compilation of the
assembly and provides a more compact way to deploy large codebases than
source code does.
Because the module type deployed inside
the application is available only in the application, it can be used
only in that application (unlike assemblies placed in the Global
Assembly Cache, which are available to all applications on the server).
To add the module, you simply need to add the fully qualified type into
the modules configuration section in the application’s root Web.config
file. For modules whose assemblies are in the /BIN directory, you can
optionally specify the assembly name, although it is not
necessary—ASP.NET by default preloads all /BIN assemblies. This is also
true for modules that are deployed as source code to the /App_Code
directory, because ASP.NET automatically compiles and loads it.
Packaging IIS 7.0 managed modules in the
application is a powerful way to create self-contained applications that
can be xcopy-deployed to a server and immediately function without
globally installing any functionality on the server.
Uninstalling Managed Modules
Caution
Before removing modules, you should
consider the security and performance implications that this action will
have on your server.
Unlike native modules, you can install
managed modules simply by adding them to the modules list. Therefore,
uninstalling managed modules is identical to disabling them and requires
a single step.
Managed modules installed as part of ASP.NET
installation cannot be individually uninstalled using Windows Setup
(Windows Vista) or Server Manager (Windows Server 2008). So, if you need
to remove any one of them, you have to do so by manually removing their
entries from the modules section. Be sure to make a configuration backup in case you need to restore the original configuration later.
Understanding Module Preconditions
The modular architecture of IIS 7.0 relies heavily
on controlling which modules are installed and enabled on the server
and at the application level. Sometimes, making this determination based
on static configuration is not sufficient, and the decision to use the
module in a specific scenario must be made based on factors known only
at run time. To support this functionality, IIS 7.0 introduces the
concept of preconditions, which are configured conditions that the
server evaluates at run time to determine whether a particular module
should be used.
The following types of preconditions are supported:
-
Module load preconditions. These
preconditions may be associated with each installed native module in
the globalModules configuration section, and they determine whether a
particular module is loaded by each worker process when it starts. If
any of the preconditions do not evaluate to true, the module is not
loaded in the worker process. These preconditions can also be used in
the isapiFilters configuration section to control the loading of ISAPI
filters. -
Module enablement preconditions. These
preconditions may be associated with each enabled module in the modules
configuration section, and they determine whether the module is enabled
for a particular application (or request). If any of the preconditions
do not evaluate to true, the module does not run. -
Handler mapping preconditions. These
preconditions may be associated with each handler mapping in the
handlers configuration section, and they determine whether this handler
mapping is considered when mapping a request to handlers. If any of the
preconditions do not evaluate to true, the handler mapping is ignored.
In each case, one or more
precondition strings may be specified to allow the configuration entry
to be selectively used in cases where all of the specified preconditions
evaluate to true. If any of the preconditions fail, the module is not
loaded or enabled, or the handler mapping is not considered, depending
on the scenario in which the precondition is being used. Here is an
example of ASP.NET setup using preconditions to load the "ManagedEngine"
native module only in application pools that use Integrated mode, run
Framework version 2.0, and are configured to execute in a 32-bit mode.
<globalModules>
...
<add name="ManagedEngine"
image="%windir%\Microsoft.NET\Framework\v2.0.50727\webengine.dll"
preCondition="integratedMode,runtimeVersionv2.0,bitness32" />
</globalModules>
Table 4 lists the supported precondition strings and scenarios in which they can be used.
Table 4. Precondition Strings
Precondition |
Applicable To |
---|
bitness32, bitness64
Matches the "bitness" of the application pool |
globalModules, isapiFilters, modules, handlers |
classicMode, integratedMode
Matches the configured managed pipeline mode of the application pool |
globalModules, isapiFilters, modules, handlers |
runtimeVersionv1.1, runtimeVersionv2.0
Matches the configured .NET run-time version of the application pool |
globalModules, isapiFilters, modules, handlers |
appPoolName=Name, appPoolName!=Name
Matches the application pool name;
this precondition can be used to selectively load a native module into a
specific application pool |
globalModules, isapiFilters, modules, handlers |
managedHandler
Matches requests to handler mappings with managed handlers |
modules only |
The bitness32 and bitness64
preconditions match the bitness of the worker process and can be used to
selectively load modules in 32-bit or 64-bit application pools. In
mixed 32-bit and 64-bit IIS environments, it may be necessary to load
32-bit native modules only in 32-bit application pools, because IIS will
fail to load the 32-bit native DLLs into the 64-bit worker process. To
help with this, the 32-bit native modules should configure the bitness32
precondition, which selectively loads them in 32-bit application pools
only.
The classicMode and integratedMode preconditions match the configured managedPipelineMode
attribute of each application pool. Together with the runtimeVersion
preconditions, they provide a foundation for the ASP.NET versioning in
IIS 7.0 and also allow for selecting the right set of ASP.NET handler
mappings based on the integration mode of the application pool. In
application pools that either use the Classic ASP.NET integration mode
or use a .NET version that does not support direct integration, IIS 7.0
uses legacy ISAPI-based handler mappings for ASP.NET. Both of these sets
of handler mappings are configured at the server level, and they use
the classicMode/integratedMode and runtimeVersion preconditions to
automatically select the right set of handler mappings based on the
application pool’s managed pipeline mode and Framework version.
You
can use the applicationPoolName precondition to selectively load/enable
modules and handler mappings in a particular application pool. An IIS
7.0 mechanism is provided to enable specific customer scenarios
primarily on shared Web hosting servers. IIS 7.0 does not use it by
default.
Finally, the managedHandler precondition
enables modules to be enabled only for requests to ASP.NET handlers. For
ASP.NET Integrated mode applications, IIS 7.0 enables managed modules
to execute for all requests, whether or not they are mapped to ASP.NET
handlers. However, by default, all ASP.NET modules use the
managedHandler precondition to run only for requests to managed
handlers. This also enables the ASP.NET appdomain creation to be delayed
until the first request to an ASP.NET handler is made. This
precondition can be removed from each module to allow it to run for all
content types, regardless of whether they are managed or native. For
example, to allow ASP.NET Forms-based authentication to occur for all
content on the site, you need to remove the managedHandler precondition
from the "FormsAuthentication" module.
Preconditions solve a number of key problems
in IIS 7.0. However, they can also add management complexity, and if
configured incorrectly, they can result in unintended behavior. The
largest cause of precondition-related problems is due to preconditions
preventing modules from being loaded/enabled or handler mappings from
being used, resulting in missing functionality. Though the module or
handler mapping may appear present, its precondition can be preventing
it from being active. These types of problems may be hard to diagnose
because missing functionality does not always manifest in errors.
Another common problem is precondition
inconsistency, where related configuration is not preconditioned
correctly and results in configuration errors. For example, if a native
module has a bitness32 load precondition, but the corresponding
enablement entry in the modules list does not, requests to 64-bit
application pools will produce a "bad module" error because the module
being enabled is not loaded. Likewise, if a handler mapping refers to a
module whose enablement precondition in the modules list prevents it
from being enabled, requests that are mapped to this handler mapping
will encounter an error.
To avoid these problems, remember
that preconditions primarily serve to prevent a module/handler mapping
from being used in scenarios where it cannot function. Make sure that
the preconditions do not restrict the module from being available in
scenarios where it’s needed.
Also keep in mind the precondition
relationships between the different configuration sections where they
exist. Preconditions must get more restrictive as they go from module
load preconditions, to module enablement preconditions, and finally to
the handler mapping precondition for the module. For example, if the
module load precondition in globalModules is "bitness32", the module
enablement precondition for the corresponding entry in the modules
section must at least contain that precondition. If the module is
referenced in a handler mapping in the handlers configuration, the
precondition of that entry must contain at
least the precondition strings from the modules entry (which in turn
contains at least the preconditions from globalModules entry).
Installing Modules for x64 Environments
When IIS 7.0 is installed on 64-bit versions of
the operating system, it functions in native 64-bit mode by default.
This means that all application pools create native 64-bit worker
processes and load 64-bit IIS core engine components and modules.
However, by allowing any of its application pools to use the 32-bit
emulation mode called wow64, IIS 7.0 supports hosting both native 64-bit
and 32-bit applications. Unlike IIS 6.0, which also provided the
ability to use wow64, IIS 7.0 allows each application pool to configure
this individually, enabling side by side hosting of native 64-bit and
32-bit applications on the same server.
Each application pool that has the enable32BitAppOnWin64
property set to true will create 32-bit worker processes and load the
32-bit version of the IIS core and modules. This is possible because IIS
setup on 64-bit operating systems installs both 64-bit and 32-bit
versions of all IIS components and modules—the native 64-bit versions go
into the standard %windir%\System32\Inetsrv directory, and the 32-bit versions go into the %windir%\Syswow64\Inetsrv directory. At run time, when IIS tries to load modules located in the %windir%\System32\Inetsrv
directory in a 32-bit wow64 worker process, the wow64 file system
redirection feature automatically redirects the file access to the
\Syswow64 directory where the 32-bit versions of the DLLs are located.
This mechanism enables IIS or third-party
modules installed under the system32 directory to provide 32-bit
versions under the \Syswow64 directory and then automatically load the
correct version based on the "bitness" of the worker process.
However, the entire reason mixed 64-bit and
32-bit environments exist is that some functionality may not be
available in native 64-bit flavors, requiring the worker process to
operate in 32-bit mode. This is often needed for ASP applications that
invoke in-process 32-bit COM components, 32-bit only ISAPI filters, or
32-bit only native modules. Likewise, some components may be available
only in 64-bit flavors, and therefore they are not supported in 32-bit
worker processes. To support such a scenario, you must be able to
install native modules, ISAPI filters, and ISAPI extensions so that IIS
never attempts to load a 32-bit component in a 64-bit worker process,
and vice versa. IIS 7.0 provides this support via the bitness
preconditions , which enable native modules, ISAPI filters,
and handler mappings to indicate whether they are available only in
32-bit or 64-bit application pools.
For example, handler mappings that map
requests to the 32-bit version of the ASP.NET ISAPI use the bitness32
precondition to insure that they are used only inside 32-bit worker
processes.
<handlers accessPolicy="Read, Script">
<add name="PageHandlerFactory-ISAPI-2.0" path="*.aspx"
verb="GET,HEAD,POST,DEBUG" modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi
dll" preCondition="classicMode,runtimeVersionv2.0,bitness32"
responseBufferLimit="0" />
...
</handlers>
By default, the 64-bit version of the .NET
Framework also registers an identical mapping to the 64-bit version of
the aspnet_isapi.dll, which uses the bitness64 precondition so that it
is selected only in 64-bit worker processes.
Using the bitness32 and bitness64
preconditions can therefore allow native modules, ISAPI filters, and
ISAPI extensions specified in the handler mapping configuration to
directly target 64-bit or 32-bit application pools, without using the
file system redirection mechanism to provide both 32-bit and 64-bit
flavors.
|