11.2 Deploying Assemblies
Assemblies
are the basic unit of deployment for managed applications, including
ASP.NET applications. Assemblies are used in ASP.NET in several ways,
each of which has different implications for deployment. The three
categories of assembly are described below. The steps required to
deploy application-specific and global assemblies appear in
subsequent sections.
- Automatically generated assemblies
-
Includes assemblies that are dynamically generated by the ASP.NET
runtime for each .aspx page in your application,
as well as for code-behind files identified by the
src attribute of the @
Page directive, and for global.asax and
.ascx user control files. Because these
assemblies are generated at runtime automatically, no action is
required on the part of the developer at deployment time.
- Application-specific assemblies
-
Includes assemblies resulting from the compilation of code-behind
files, whether through building an application in Visual Studio .NET
or using the command-line compilers. This category also includes
compiled assemblies containing business logic code, and/or assemblies
containing custom server controls. All application-specific
assemblies should reside in the application's
bin subdirectory (also known as the local
assembly cache), which allows your application to locate and use the
assembly's members. There they are automatically
loaded into memory by the ASP.NET runtime. Because these assemblies
reside within the folder tree of the application, when you deploy the
application using XCOPY, FTP, or Windows Explorer, they are copied
with the rest of the files in your application and available to the
deployed application automatically. Additionally, the ASP.NET runtime
automatically modifies the IIS permissions on the local assembly
cache directory to deny all HTTP access to the directory, which
prevents anyone from reading or accessing assemblies directly.
- Global assemblies
-
Includes any assemblies that are shared across all applications on a
machine by installing them in the global assembly cache
(GAC). Assemblies must be strongly named in order to be installed in
the GAC and can be versioned to support side-by-side installation of
multiple versions of the same assembly.
11.2.1 Deploying Application-Specific Assemblies
As noted in the preceding section, deploying application-specific
assemblies is as simple as deploying other application files. As long
as the assemblies reside in the bin subdirectory
of the application, no further action is required on the part of the
developer apart from copying the application's files
to the target server.
The magic of the bin directory is enabled by the
<assemblies> configuration element in
machine.config, which contains the following
<add> element by default:
<add assembly="*" />
This element tells the ASP.NET runtime to load any assemblies
residing in the bin subdirectory for use by the
application.
Another important point is that when assemblies are loaded by the
ASP.NET runtime, the actual physical DLL containing the assembly is
never loaded into memory. Instead, the ASP.NET runtime makes a shadow
copy of the DLL and loads and locks it on the disk instead (while
setting up a file monitor on the original DLL file). This means that
you can update the .NET assemblies associated with your application
at any time, without the need to shut down IIS or restart the server.
The ASP.NET runtime automatically detects when an assembly is updated
and serves all new requests using the new version of the assembly.
This makes it significantly easier to maintain and update
applications with a minimum of downtime.
If you use
code-behind for your page-specific
logic, you can deploy only the .aspx pages and
the precompiled assembly (or assemblies) for your code-behind files,
without deploying the code-behind files. This allows you to run your
application while protecting the source code contained in the actual
code-behind files.
Some have argued that, as with Java bytecode, the
Intermediate Language (IL)
contained in .NET managed assemblies is readily decompiled into a
managed language such as C#. Thus, even if you do not deploy the
code-behind files for an application, it may still be possible for
someone to derive this code from the assemblies by using an IL
decompiler, assuming that they could get access to the assemblies,
which would require either physical access to the machine, or would
require the attacker to exploit a vulnerability that allowed access
to the filesystem.
|
Application developers should consider the relative value represented
by their code versus the effort required to decompile that code, and
determine whether additional means for protecting the code are
warranted. One such measure is a code obfuscator, which renders most
member names meaningless to make understanding of decompiled code
more difficult.
|
|
11.2.2 Deploying Global Assemblies
The global
assembly cache (GAC) provides a centralized location for the storage
of assemblies that are to be shared across applications on a given
machine. As noted previously, to be stored in the GAC, an assembly
must be named strongly. This process is outlined in this section.
Because of this requirement, the extra deployment effort entailed,
and the fact that global assemblies are available to all applications
on a machine by default, you should only use the GAC for assemblies
that fit the following profile:
They need to be shared by many applications. The effort of maintaining and/or updating individual local copies of
the assembly for each application outweighs the effort of strongly
naming and deploying the assembly to the GAC.
The first step in deploying an assembly to the GAC is to provide the
assembly with a strong name. This is a three-step process:
Generate a cryptographic key pair using the
sn.exe command line tool: sn -k keyPair.snk To see all the options for
the
sn.exe tool, run sn
/? at a command prompt. Add an assembly-level AssemblyKeyFile
attribute. You can also optionally add an
AssemblyVersion attribute to provide a version
number for the assembly. The * in the following
version number example auto-increments the last two of the four
version number parts with each compilation: ' VB.NET
<Assembly: AssemblyKeyFile("keyfile.snk")>
<Assembly: AssemblyVersion("0.1.*")>
// C#
[assembly: AssemblyKeyFile(@"..\..\sgKey.snk")]
[Assembly: AssemblyVersion("0.1.*")] Compile the assembly using the appropriate command-line compiler.
Note that the key pair should be copied to the location of the code
files to be compiled, since this location is where the compiler will
look for the file based on the AssemblyKeyFile
attribute shown previously.
|
Assemblies placed in the GAC are given full trust by the code access
security system. If an application configured for a lower trust level
attempts to call the assembly, an exception of type
SecurityException will be thrown.
|
|
Once the
assembly has been strongly named, you can install it into the GAC in
any one of three ways:
Use the
gacutil.exe
command-line tool to install (or uninstall) an assembly into the GAC,
as follows: gacutil -i myAssembly.dll Note that this syntax assumes that gacutil.exe
is called from the directory containing the
assembly's physical file. The
gacutil.exe utility is recommended only for
development systems. Use Windows Explorer to drag and drop a copy of the assembly to the
GAC. Access to the GAC is provided via a Windows Explorer shell
extension, which displays the contents of the GAC as the folder
%windir%\Assembly. Use Microsoft Windows Installer 2.0 to create an installation package
that will install the assembly or assemblies to the GAC. This
installation ensures easier rollback of assemblies and other
benefits. See the Windows Installer 2.0 documentation for information
on
creating Installer packages.
If you're using only managed assemblies in your
application, the deployment picture is pretty rosy.
It's considerably easier to deploy, update, and
maintain managed assemblies than it was to maintain COM components in
classic ASP. But what if your application requires you to use COM
components through the .NET COM interoperability layer?
The good news is that if the version of the COM component you are using is
already installed on the target machine, you should need to deploy
only the runtime-callable wrapper (RCW)
assembly for the component, since that assembly contains the
information necessary to locate the component based on information in
the registry.
However, if the COM component is a custom component or is not
installed on the target system, you need to deploy the COM component
to the target system and register it using
regsvr32.exe as follows:
regsvr32 <dllname>
Note that you would replace
<dllname> with the name of the
component to register.
|
|