Thursday, June 9, 2011

Assemblies and Application Domain


1. Introduction
In Microsoft .NET, when an application is compiled, the output of the compilation
produces what is known as an Assembly. Two types of assemblies can be produced by the
compilation procedure. One is the executable file (*.exe) and the other is a dynamic link
library file (*.dll). Basically the assembly is the unit of deployment in Microsoft .NET
and it can be thought of as a collection of types and resources that form a logical unit of
functionality.
An assembly is a self-describing entity. It contains all information about the types
(classes) contained in the assembly, all external references needed for executing the
assembly and so on. This is possible with an assembly manifest. The manifest contains
assembly’s identity and version information, a file table containing all files that make up
the assembly and the assembly reference list for all external dependencies. Thus
assemblies do not need to depend on the registry values for compilation or execution.
An assembly contains manifest data and one or more modules. Manifest data contains
information about the assembly and other list of assemblies that it depends on. It also
contains all the publicly exposed types and resources. An assembly contains various
modules. Each module contains metadata and IL.
Assemblies can be viewed by application developers with the help of a tool called ildasm
(IL Disassembler) provided by the .NET Framework.
2. Assembly Types
Assemblies can be single file assemblies or multi file assemblies. In multi file assemblies
one of the files must contain the assembly’s manifest data. Multi file assemblies can have
only one entry point even though the assembly can contain multiple code modules. A
multi file assembly is created primarily for combining modules written in different
programming languages. Once the assembly is created, the file that contains the
assembly manifest (and hence the assembly) can be signed, or one can give the file (and
the assembly) a strong name and put it in the global assembly cache.
Main uses of multi file assembly are for combining modules written in different
programming languages. They enable optimization of downloading an application by
putting seldom-used types in a module that is downloaded only when needed. The .NET
Framework downloads a file only when it is referenced; keeping infrequently referenced
code in a separate file from the application optimizes code download.
Let us look at an example of how to create multi file assembly.
AddModule.cs
Copy and Paste the following code into Notepad and save it as or AddModule.vb,
depending on the language that you are using
Code Listing in C#
using System;
public class AddClass
{
public int Add(int Operand1, int Operand2)
{
return Operand1 + Operand2;
}
}
Compiling in C#
/Compilation csc /r:System.dll /t:Module AddModule.cs
Code Listing in VB.NET
Imports System
Public Module AddModule
Public Class AddClass
Function Add(ByVal Operand1 As Integer, ByVal Operand2 As Integer) As Integer
Add = Operand1 + Operand2
End Function
End Class
End Module
Compiling in VB.NET
vbc /r:System.dll /t:Module AddModule.vb
This file is compiled with the target option as module. Hence an assembly is not created.
The output is a file with an extension of .netmodule.
Similarly create SubtractModule.cs/ as shown below
SubtractModule.vb
Code Listing in C#
using System;
public class SubtractClass
{
public int Subtract(int Operand1 , int Operand2 )
{
return Operand1 - Operand2;
}
}
Compiling in C#
csc /r:System.dll /t:Module SubtractModule.cs
Code Listing in VB.NET
Imports System
Public Module SubtractModule
Public Class SubtractClass
Function Subtract(ByVal Operand1 As Integer, ByVal Operand2 As Integer) As
Integer
Subtract = Operand1 - Operand2
End Function
End Class
End Module
Compiling in VB.NET
vbc /r:System.dll /t:Module SubtractModule.vb
Now create the main module, which references the above modules. The code is as shown
below for MainModule.cs/MainModule.vb
MainModule.cs
Code Listing in C#
using System;
public class MainModule
{
public static void Main()
{
int iOperand1, iOperand2, iResult ;
iOperand1 = 22;
iOperand2 = 11;
iResult = 0;
AddClass objAddClass = New AddClass();
SubtractClass objSubtractClass = New SubtractClass();
iResult = objAddClass.Add(iOperand1, iOperand2);
Console.WriteLine(iResult.ToString());
iResult = objSubtractClass.Subtract(iOperand1, iOperand2);
Console.WriteLine(iResult.ToString());
Console.ReadLine();
}
}
Compiling in C#
Compilation csc /r:System.dll MainModule.cs
Code Listing in VB.NET
Imports System
Public Module MainModule
Sub Main()
Dim iOperand1, iOperand2, iResult As Integer
iOperand1 = 22
iOperand2 = 11
iResult = 0
Dim objAddClass As New AddClass
Dim objSubtractClass As New SubtractClass
iResult = objAddClass.Add(iOperand1, iOperand2)
Console.WriteLine(iResult.ToString)
iResult = objSubtractClass.Subtract(iOperand1, iOperand2)
Console.WriteLine(iResult.ToString)
Console.ReadLine()
End Sub
End Module
Compiling in VB.NET
vbc /r:System.dll MainModule.vb
The code is compiled as follows
To create a multi file assemble, which contains the two modules created previously
namely AddModule and SubtractModule, compile using the following command at the
command prompt
Compiling in C#
csc /System.dll /addModule:AddModule.netmodule
/addModule:SubtractModule.netmodule MainModule.cs
Compiling in VB.NET
Vbc /System.dll /addModule:AddModule.netmodule
/addModule:SubtractModule.netmodule MainModule.vb
This process creates a multi file assembly. This assembly contains the two modules
created previously namely AddModule and SubtractModule. Thus this assembly contains
multiple modules. If ildasm utility is executed on the MainModule assembly, it shows
that the manifest information in the MainModule contains references to the AddModule
and the SubtractModule modules. That is the modules are linked to the main assembly by
the information contained in the main assembly’s manifest information.
3. Private Assemblies
A private assembly is an assembly that is deployed with an application and is available
only for that application. That is, other applications do not share the private assembly.
Private assemblies are installed in a folder of the application's directory structure.
Typically, this is the folder containing the application's executable file.
For most .NET Framework applications, you keep the assemblies that make up an
application in the application's directory, in a subdirectory of the application's directory.
You can override where the CLR looks for an assembly by using the <codeBase>
element in a configuration file.
4. Shared Assemblies
A shared assembly is an assembly available for use by multiple applications on the
computer. To make the assembly global, it has to be put into the Global Assembly Cache.
Each computer where the common language runtime is installed has a machine-wide
code cache called the global assembly cache. The global assembly cache stores
assemblies specifically for sharing by several applications on the computer.
You should share assemblies by installing them into the global assembly cache only
when you need to. As a general guideline, keep assembly dependencies private and locate
assemblies in the application directory unless sharing an assembly is explicitly required.
This is achieved with the help of a global assembly cache tool (gacutil.exe) provided by
the .NET Framework. One can also drag & drop the assemblies into the Global Assembly
Cache directory.
However, when an assembly has to be put into the Global Assembly Cache it needs to be
signed with a strong name. A strong name contains the assembly's identity i.e. it’s text
name, version number, and culture information strengthened by a public key and a digital
signature generated over the assembly. This is because the CLR verifies the strong name
signature when the assembly is placed in the Global Assembly Cache.
5. Application Domains
Introduction
Traditionally when many applications are executed on the same machine, they are
isolated by something known as process. Ideally each application is loaded in its own
process also known as address space. This isolation is need so that these applications do
not tamper with other applications either intentionally or accidentally. Isolating
applications is also important for application security. For example, one can run controls
from several Web applications in a single browser process in such a way that the controls
cannot access each other's data and resources.
There are however many instances in which one would like an application to have the
ability to communicate with other applications. Since these applications are loaded into
different address spaces, there must be some form of context switching needed to allow
one application to communicate with another. Inter process communication has to rely on
operating systems support to manage this context switching and it is generally an
expensive operation. Context switching means saving a process's context, it could also
mean swapping the process out to virtual memory (to the page file stored on disk). If a
single machine has a large number of active processes, the CPU is often reduced to
swapping processes in and out of memory continuously, a phenomenon known as
thrashing.
Application Domains
There should be a method by which the different applications can be executed in isolation
from each other and which would also allow these applications to communicate with each
other in a better way than offered by context switching. Microsoft .NET has introduced
the Application Domain concept for precisely this reason. Application domains provide a
secure and versatile unit of processing that the CLR can use to provide isolation between
applications. Further, one can specify custom security policies on an Application Domain
to ensure that codes run in an extremely strict and controlled app domain. One can run
several application domains in a single process with the same level of isolation that
would exist in separate processes, but without incurring the additional overhead of
context switching between the processes. In Microsoft .NET, code normally passes a
verification process before it can be executed. This code is considered as type-safe code
and this allows CLR to provide a great level of isolation at the process level. Type-safe
codes have less chances of causing memory faults.
Code running in one application should not directly access code or resources from
another application. The CLR enforces this isolation by preventing direct calls between
objects in different application domains. Objects that pass between domains are either
copied or accessed by proxy. If the object is copied, the call to the object is local. That is,
both the caller and the object being referenced are in the same application domain. If the
object is accessed through a proxy, the call to the object is remote. In this case, the caller
and the object being referenced are in different application domains. As such, the
metadata for the object being referenced must be available to both application domains to
allow the method call to be JIT-compiled properly.
Application Domains And Assemblies
Before an assembly can be executed, it must be loaded into an application domain. By
default, the CLR loads an assembly into an application domain containing the code that
references it. In this way the assembly’s data and code are isolated to the application
using it. In case, multiple application domains reference an assembly, the assembly’s
code is shared amongst the different application domains. Such an assembly is said to be
domain-neutral. An assembly is not shared between domains when it is granted a
different set of permissions in each domain. This can occur if the runtime host sets an
application domain-level security policy. Assemblies should not be loaded as domainneutral
if the set of permissions granted to the assembly is to be different in each domain.
Programming with Application Domains
Application domains are normally automatically created and managed by runtime hosts.
However, Microsoft .NET also provides control to application developers to create and
manage their own application domains. This would allow the developers to have control
over loading and unloading the assemblies in different domains for performance reasons
and maintain a high degree of isolation. Note that individual assemblies cannot be
unloaded, the entire app domain has to be unloaded.
If development is being carried out with some code or components downloaded from the
Internet, running it in its own application domain provides an excellent way to isolate the
rest of the applications from this code.
The System namespace contains the class AppDomain. This class contains methods to
create an application domain, to load and unload assemblies in the application domain.
An example will be useful to illustrate how application domains can be created and
assemblies loaded and unloaded into the application domains. Note that only those
assemblies that have been declared as Public can be loaded at runtime.
Copy and paste the following code into Notepad and save it as Display.cs/Display.vb,
depending on the programming language used.
Display.vb
Code Listing in C#
using System;
public class Display
{
public static void Main()
{
Console.WriteLine("This is written by assembly 1");
Console.ReadLine();
}
}
Compiling in C#
Compilation csc /r:System.dll Display.cs
Code Listing in VB.NET
Imports System
Public Module Display
Sub Main()
Console.WriteLine("This is written by assembly 1")
Console.ReadLine()
End Sub
End Module
Compiling in VB.NET
vbc /r:System.dll Display.vb
Similarly, copy and paste the following code into Notepad and save it as
Display2.cs/Display2.vb, depending on the programming language used.
Display2.cs
Code Listing in C#
Imports System
Public Module Display
Sub Main()
Console.WriteLine("This is written by assembly 2")
Console.ReadLine()
End Sub
End Module
Compiling in C#
Compilation csc /r:System.dll Display2.cs
Code Listing in VB.NET
Imports System
Public Module Display
Sub Main()
Console.WriteLine("This is written by assembly 2")
Console.ReadLine()
End Sub
End Module
Compiling in VB.NET
'Compilation vbc /r:System.dll Display2.vb
The following code - CreateAppDomain.cs/CreateAppDomain.vb contains the following
code that shows how to create an application domain programmatically and how to load
assemblies during runtime.
Code Listing in C#
using System;
using System.Reflection;
public class CreateAppDomain
{
AppDomain m_objAppDomain;
public static void Main()
{
String strAppDomainName1 ;
String strAppDomainName2 ;
String strAssemblyToBeExecuted ;
strAppDomainName1 = "TestAppDomain1";
strAppDomainName2 = "TestAppDomain2";
strAssemblyToBeExecuted = "Display.exe";
CreateApplicationDomain(strAppDomainName1, strAssemblyToBeExecuted);
AppDomain.Unload(m_objAppDomain);
strAssemblyToBeExecuted = "Display2.exe" ;
CreateApplicationDomain(strAppDomainName2, strAssemblyToBeExecuted);
AppDomain.Unload(m_objAppDomain);
}
private void CreateApplicationDomain(String p_strAppDomainName , String
p_strAssemblyToBeExecuted)
{
try
{
m_objAppDomain = AppDomain.CreateDomain(p_strAppDomainName);
m_objAppDomain.ExecuteAssembly(p_strAssemblyToBeExecuted);
}
catch(AppDomainUnloadedException objException )
{
Console.WriteLine("Unable to create application domain");
Console.WriteLine("Exception is " + objException.toString());
}
}
}
Compiling in C#
Compilation csc /r:System.dll CreateAppDomain.cs
Code Listing in VB.NET
Imports System
Imports System.Reflection
Module CreateAppDomain
Dim m_objAppDomain As AppDomain
Sub Main()
Dim strAppDomainName1 As String
Dim strAppDomainName2 As String
Dim strAssemblyToBeExecuted As String
strAppDomainName1 = "TestAppDomain1"
strAppDomainName2 = "TestAppDomain2"
strAssemblyToBeExecuted = "Display.exe"
CreateApplicationDomain(strAppDomainName1, strAssemblyToBeExecuted)
AppDomain.Unload(m_objAppDomain)
strAssemblyToBeExecuted = "Display2.exe"
CreateApplicationDomain(strAppDomainName2, strAssemblyToBeExecuted)
AppDomain.Unload(m_objAppDomain)
End Sub
Private Sub CreateApplicationDomain(p_strAppDomainName As String,
p_strAssemblyToBeExecuted As String)
Try
m_objAppDomain = AppDomain.CreateDomain(p_strAppDomainName)
m_objAppDomain.ExecuteAssembly(p_strAssemblyToBeExecuted)
Catch objException As AppDomainUnloadedException
Console.WriteLine("Unable to create application domain")
Console.WriteLine("Exception is " & objException.toString())
End Try
End Sub
End Module
Compiling in VB.NET

No comments:

Post a Comment