+
Creating an assembly
Changing the search path for private assemblies
Creating strongly named assembly
Adding assembly into the global assembly cache
Creating a Delay signed shared assembly
Using Assembly Version Policy
Creating a Publisher Policy Assembly
Getting the types in an assembly
Creating assembly on the fly
Dynamic Binding a Assembly
Serializing using XmlSerializer
Serializing using SoapSerializer
Serializing using BinarSerializer
Creating a Domain
Module MyModule
public sub Main(args() as string)
System.Console.WriteLine("Hello Vb")
end sub
end Module
Using the command-line compiler provided with Visual Studio, such a program can be compiled with the command line directive
c:\> vbc Hello.vb
class CA
{
public static void Main(string[] args)
{
System.Console.WriteLine("Hello World");
}
}
Using the command-line compiler provided with Visual Studio, such a program can be compiled with the command line directive
c:\> csc Hello.cs
c:\> ildasm Hello.exe
Creating an assembly
namespace MathLibrary
{
public class CMath
{
public long AddFun(long x,long y)
{
Console.WriteLine("Addfun");
return x + y;
}
public long SubFun(long x,long y)
{
Console.WriteLine("AubFun");
return x - y;
}
}
}
c:\> csc /t:libary Math.cs
public class CMath
public function AddFun(x as long,y as long) as long
return x + y
end function
end class
How Do I...Change the search path for private assemblies?
Private assemblies are assemblies that are visible to only one application. The .NET Framework enables developers to build applications that are isolated from changes made to the system by other applications. Private assemblies must be deployed in the directory structure of the containing application and are found during runtime through a process called probing, which is simply a mapping from an assembly's identity to a file on disk that contains the manifest.
By default, probing for private assemblies is done in the application base (the root directory of the application) and the subdirectories that follow naming conventions based on assembly name and culture. You can customize this behavior by specifying a privatePath in your application's configuration file. The privatePath is a semi-colon delimited list of directories in which the common language runtime will search for private assemblies. These directory names are relative to the application base - they cannot point outside the application base. The directories on privatePath will be searched after the application base itself. The following configuration file adds a bin directory to the assembly search path:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin"/>
</assemblyBinding>
</runtime>
</configuration>
How Do I...Create an assembly with a strong name?
Assemblies can be assigned a cryptographic signature, called a strong name, which provides name uniqueness for the assembly and prevents someone from taking over the name of your assembly (name spoofing). If you are deploying an assembly that will be shared among many applications on the same machine, it must have a strong name. Even if you only use the assembly within your application, using a strong name ensures that the correct version of the assembly gets loaded
The first step in building an assembly with a strong name is to obtain a cryptographic key pair. The .NET Framework SDK includes a Strong Name tool (Sn.exe) that can be used to generate a key pair. The key pair that is generated by the Strong Name tool can be kept in a file or you can store it in your local machine's Crytographic Service Provider (CSP). The following command uses the Strong Name tool to generate a new key pair and store it in a file called TestKey.snk:
c:\> SN -k TestKey.snk
c:\> SN -tp TestKey.snk
Once you have obtained the key pair, you need to add the proper custom attribute to your source in order for the compiler to emit the assembly with a strong name. Choosing the correct attribute depends on whether the key pair used for the signing is contained in a file or in a key container within the CSP. For keys stored in a file, use System.Reflection.AssemblyKeyFileAttribute. For keys stored in the CSP use System.Reflection.AssemblyKeyNameAttribute
The following example uses AssemblyKeyFileAttribute to specify the name of the file containing the key pair.
using System;
using System.Reflection;
[assembly : AssemblyKeyFile("TestKey.snk ")]
namespace MathLibrary
{
public class CMath
{
public long AddFun(long x,long y)
{
Console.WriteLine("Addfun");
return x + y;
}
public long SubFun(long x,long y)
{
Console.WriteLine("AubFun");
return x - y;
}
}
}
How to add assembly into the global assembly cache ?
The global assembly cache is a machine-wide store used to hold assemblies that are intended to be shared by several applications on the machine. The .NET Framework provides two tools for working with the cache. One is a Windows shell extension that allows you to work with the cache using a Graphical User Interface (GUI). The other is a command line tool, called the Global Assembly tool (Gacutil.exe), that is typically used in build and test scripts. The command line tool is called the Global Assembly Cache tool (Gacutil.exe).
All assemblies in the global cache must have strong names.
Viewing the Contents of the Assembly Cache
Navigate to %winnt%\assembly using the Windows Explorer to activate the shell extension. The default view shows the contents of the assembly cache. You can also view the contents of the cache with the /l option of the Global Assembly Cache tool:
gacutil /l
Installing Assemblies
To install an assembly using the shell extension simply drag and drop the file containing the assembly's manifest into the global assembly cache directory. To install an assembly using the Global Assembly Cache tool, use the /i option:
gacutil /i math.dll
Uninstalling Assemblies
To delete an assembly with the shell extension, right click on it and select Delete. The /u option of the Global Assembly Cache tool can also be used:
gacutil /u math,ver=1.0.0.0
The version of Windows Installer (1.5) that will ship in the Visual Studio .NET timeframe has native support for the assembly cache. When creating an Installer package with the Visual Studio Deployment tool or another setup tool, you can specify which assemblies you'd like installed in the cache. Using the Windows Installer to work with the assembly cache gives you the standard Installer benefits like install-on-demand, advertisement, publishing, and so on.
using System;
using MathLibrary;
class CMain
{
public static void Main(string[] args)
{
long x = long.Parse(args[0]);
long y = long.Parse(args[1]);
CMath obj = new CMath();
long ans = obj.AddFun(x,y);
Console.WriteLine(" {0} + {1} = {2} ", x,y,ans);
}
}
How to create a Delay signed shared assembly ?
Giving an assembly a strong name requires two cryptographic keys: a public key and a private key. This key pair is passed to the compiler at build time. However, the person building the assembly does not always have access to the private key required for strong naming. This is most common in corporations that have a central signing entity closely guards private keys. Only a few select people have access to these keys. Also, the process of assigning a strong name cannot be done after building because the public key is part of the assembly's identity and must be supplied at build time so that clients of the assembly can compile against the full assembly identity.
· 1. Creates a key-pair using sn -K.
· 2. Separates the public key from the private key and stores the public key in its own file.
· 3. Creates a delay signed assembly in either Visual Basic or C#.
· 4. Uses the Strong Name tool to request that signature verification be skipped for the assembly just generated.
· 5. Generates a valid signature using the Strong Name tool. This typically happens just before you ship the assembly.
The .NET Framework offers delay signing, which effectively splits the process of assigning the strong name into two steps:
· 1. At build time, the public key is given to the compiler so it can be recorded in the PublicKey field in the assembly manifest. Also, space is reserved in the file for the signature, although the actual signature is not generated at this time.
· 2. At a later time, the the actual signature is generated and stored in the file. Signature generation is done with the -R switch to the Strong Named tool (Sn.exe).
When you include the System.Reflection.AssemblyDelaySignAttribute in your source code, it indicates to the compiler that the assembly needs to be created with delay signing. You also need to include the public key, using AssemblyKeyFileAttribute. Typically, the signing entity will use the SN -k to generate a key pair and store it in a file. Next, it pulls the public key out of the file using SN -p. The public key can then be given out, with the private key still secret.
sn -k Testkey.snk
sn -p Testkey.snk TestPublicKey.snk
The following example uses AssemblyKeyFileAttribute and AssemblyDelaySignAttribute to create a delay signed assembly.
using System;
using System.Reflection;
[assembly:AssemblyKeyFileAttribute("TestPublicKey.snk")]
[assembly:AssemblyDelaySignAttribute(true)]
Since the assembly in the example does not have a valid signature, the signature validation performed by the common language runtime will fail when you try to install the assembly into the global assembly cache or load it from an application directory. However, the Strong Name tool can be used to disable signature verification of a particular assembly by using the -Vr option:
sn -Vr DelaySign.dll
A valid signature must be generated before the assembly is shipped to customers using sn -R. This is typically done by the company signing entity. You must supply the full key pair to create a valid signature.
sn -R DelaySign.dll Testkey.snk
To create and sign an assembly with a strong name using the Assembly Linker
At the command prompt, type the following command:
al /out:<assembly name> <module name> /keyfile:<file name>
In this command, assembly name is the name of the assembly to sign with a strong name, module name is the name of the code module used to create the assembly, and file name is the name of the container or file that contains the key pair.
The following example signs the assembly MyAssembly.dll with a strong name using the key file sgKey.snk.
al /out:MyAssembly.dll MyModule.netmodule /keyfile:sgKey.snk
How to Use Assembly Version Policy?
A primary goal of the deployment system in the .NET Framework is to eliminate conflicts between applications caused by shared components and shared states (or DLL conflicts). A key solution to this problem is a robust versioning system. The .NET Framework records information about an application's dependencies in the assembly manifest. This dependency information includes a version number that is used at runtime to load the proper version of a dependency.
By default, the common language runtime will load the version of a dependency that is specified in the manifest. This is preferred in the majority of scenarios. However, there are cases where running an application with a different version of a dependency can be useful. In order to accomplish this, version policies can be included in an application's configuration file. For example, the following XML code fragment redirects references to version 5.0.0.0 of a shared assembly called "caclR" up to version 6.0.0.0 of that assembly:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="calcR"
publicKeyToken="a1690a5ea44bab32"
culture=""/>
<bindingRedirect oldVersion="5.0.0.0"
newVersion="6.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
How to Create a Publisher Policy Assembly?
A Publisher policy statement describes the compatibility of an assembly issued by the publisher of that shared assembly. Publisher policy is commonly used in service pack scenarios. For example, a publisher may produce a number of small releases that enhances certain features for a particular customer. For maintenance reasons, the publisher may wish to collect all of these fixes into a single service pack release and have all exsiting customers upgrade to the new service pack.
A publisher policy statement is an XML configuration file wrapped as a separate assembly. There are three reasons that publisher policies are shipped as assemblies. The first is to ensure that the policy statement comes from the author of the assembly that the policy is making the compatibility statement about. This is accomplished by requiring that the policy assembly has a strong name generated with the same key-pair as the original assembly. The second reason is ease of deployment. Publishers or administrators can ship policy statements using the assembly deployment mechansims provided by the .NET Framework, including the Windows Installer and code download. Using the Windows Installer is particularly convenient because all policy assemblies must be installed in the global assembly cache. Finally, assemblies ship policy statements so that they can be versioned. This allows a publisher to ship a subsequent statement if a previous policy is found not to work in some scenarios. In effect, this allows a publisher to change his mind about the compatibility of his assembly independent of when it was shipped. The flexibility enabled by decoupling the compatibility statements from the code makes it much easier to fix broken applications in the .NET Framework. If multiple versions of a given policy assembly are found in the assembly cache, the .NET Framework will use the policy assembly with the highest version number.
In general, there are two steps required to create a publisher policy assembly:
· 1. Create the XML file containing the compatibility statement. You will have to use an XML editor to create this file.
· 2. Use the Assembly Generation tool (Al.exe) to create an assembly containing the XML file.
The format of the xml file, along with rules about how the elements relate, is described in detail in the .NET Framework SDK Guide. Here is an example file:
<configuration>
<runtime>
<assemblyBinding>
<dependentAssembly>
<assemblyIdentity name="myasm"
publicKeyToken="e9b4c4996039ede8"
culture="en-us"/>
<bindingRedirect oldVersion="1.0.0.0-1.0.9.9"
newVersion="2.0.0.0"/>
<codeBase version="2.0.0.0"
href="http://www.foo.com/bar.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
After the xml file is created, use the Assembly Generation tool to create a policy assembly. The following switches to the Assembly Generation tool are required:
1. /link: links the xml file into the assembly.
2. /out: gives the resulting policy assembly a name. Policy assemblies are found in the global assembly cache by naming convention. Therefore, their names must be:
policy.<major number>.<minor number>.<main assembly name>
For example, policy.2.0.myasm
3. /keyfile: The key pair used to give the assembly a strong name (or at least the public key if delay signing is used). As described earlier, this key pair must be the same key pair used to sign the assembly to which this policy statement applies.
4. /version: The version number of the policy assembly.
The following example shows a command line that uses the Assembly Generation tool:
Al /link:publisher.cfg /out:policy.2.0.myasm /keyfile:myasm.snk /version:2.0.0.0
In addition to policies specified at the application level, the .NET Framework also provides two other policy levels: publisher and administrator. A Publisher policy statement describes the compatibility of an assembly issued by the publisher of that shared assembly. Administrator policy is created using the same XML syntax as application level policy. The administrator policy file is called machine.config, and resides in the common language runtime install directory. The three policy levels are evaluated in the following order:
· Application Policy
· Publisher Policy
· Administrator Policy
How Do I...Get the types in an assembly?
using System; Once you have an object reference to the assembly of interest, you can call the GetTypes method on that assembly, which returns an array of all the types in that assembly. You can use control logic to identify the more specific types in that array, and use iterating logic to parse your array, returning the type information to the user if needed. The ability to retrieve type information can be useful for determining alternative types you could use for a given task, or identifying existing elements which could provide you with the functionality you need.
The first thing to learn when retrieving types from a particular assembly is, how to identify an assembly.The first is by identifying a particular object that you want to find the assembly of, and requesting the assembly for the module of that object (remember that a module is a logical grouping of types and code, such as a .dll or .exe). The second is by using the LoadFrom method of the Assembly class to load a specific assembly for a named module (such as myapp.exe).
using System.Reflection;
class CMain
{
static void Main(string[] args)
{
//step 1 load an assembly
Assembly asm = Assembly.LoadFrom("c:\\dotnet\\MathLibrary.dll");
//step 2 get the modules
Module[] modules = asm.GetModules();
foreach(Module mod in modules)
{
Console.WriteLine("module {0}", mod.Name);
//step 3 get types
Type[] types = mod.GetTypes();
foreach(Type t in types)
{
Console.WriteLine("Type {0}", t.Name);
//step 4 get methods
MethodInfo[] methods = t.GetMethods();
foreach(MethodInfo method in methods)
{
Console.WriteLine("method : {0} ",method.Name);
}
FieldInfo[] fields = t.GetFields();
foreach(FieldInfo field in fields)
{
Console.WriteLine("field : {0} ",field.Name);
}
}
}
}
}
How Do I...Create a assembly On the fly?
using System;
using System.Reflection;
using System.Reflection.Emit;
class CMain
{
static void Main(string[] args)
{
//step 0 get domain ref in which asm will be created
AppDomain domain = AppDomain.CurrentDomain;
//step 1 create a name for the asm
AssemblyName asmname = new AssemblyName();
asmname.Name = "MyFirstAssembly";
//step 2 build a asm
AssemblyBuilder asmbuilder =
domain.DefineDynamicAssembly(asmname,AssemblyBuilderAccess.Save);
//step 3 build a module
ModuleBuilder modbuilder =
asmbuilder.DefineDynamicModule("mymodule","mymodule.netmodule");
//step 4 create a type
TypeBuilder typebuilder =
modbuilder.DefineType("CA",TypeAttributes.Public);
//step 5 create a field
FieldBuilder field1 = typebuilder.DefineField
("empno", Type.GetType("System.String"),FieldAttributes.Private);
//step 6 create a method
MethodBuilder method1 = typebuilder.DefineMethod
("fun",MethodAttributes.Public,null,new Type[]{});
//step 7 write code in the method
ILGenerator il = method1.GetILGenerator();
il.Emit(OpCodes.Ret);
//step 8 save
typebuilder.CreateType();
asmbuilder.Save("myasm.dll");
}
}
}
How Do I...Invoke methods?
In many coding scenarios, you know the task that you want to carry out before you want to do it. Therefore, you can specify the methods that you need to invoke, and the parameters you need to pass them. However, there are also situations where you might want to dynamically invoke methods, based upon specific scenarios, or user actions. This capability is available through the Reflection namespace, by using the InvokeMember method on the Type object.
You can also take other actions, such as getting or setting the value of a specified property. These actions are available through the BindingFlags enumeration. The second parameter of InvokeMethod is a combination of the BindingFlags actions you specify. For example, if you want to invoke a static method on a class, you would include the static element in BindingFlags, and the InvokeMethod BindingFlag. The following example demonstrates how to invoke a hypothetical method
// calling a static method, receiving no arguments
// don't forget that we are using object in the reflection namespace...
using System;
using System.Reflection;
public class Invoke {
public static void Main (String [] cmdargs) {
// Declare a type object, used to call our InvokeMember method...
Type t = typeof (TestClass);
// BindingFlags has three bitor'ed elements. Default indicates
// that default binding rules should be applied.
t.InvokeMember ("SayHello",
BindingFlags.Default | BindingFlags.InvokeMethod
| BindingFlags.Static, null,
null, new object [] {});
}
}
Take a quick look at the rest of the parameters that were passed to the Invoke method. The first null argument passed is requesting that the default binder be used to bind the method you are invoking. When you invoke the default binder, include the default BindingFlags. Instead of null as the third parameter, you can specify a Binder object that defines a set of properties and enables binding, which may involve selection of an overloaded method or coercion of argument types. The second null argument is the object on which to invoke the method you chose. Finally, pass an object array of the arguments that the member receives.
Named arguments
You can also use named arguments, in which case you need to use a different overloaded version of the InvokeMember method. Create the array of object arguments as you have been doing so far, and also create a string array of the names of the parameters being passed. The overloaded method you want to use accepts the list of parameter names as the last parameter, and the list of values you want to set as the fifth parameter
// Calling a method using named arguments
// the argument array, and the parameter name array.
// to determine the names of the parameters in advance
object[] argValues = new object [] {"Mouse", "Micky"};
String [] argNames = new String [] {"lastName", "firstName"};
t.InvokeMember ("PrintName",
BindingFlags.Default | BindingFlags.InvokeMethod,
null, null, argValues, null, null, argNames);
The final example uses a slightly different process to invoke a method. Rather than using the Type object directly, create a separate MethodInfo object directly to represent the method you will be invoking. Then, call the Invoke method on your MethodInfo object, passing an instance of the object you need to invoke your method on (if you are invoking an instance method, but null if your method is static). As before, an object array of the parameters is required.
// Invoking a ByRef member
MethodInfo m = t.GetMethod("Swap");
args = new object[2];
args[0] = 1; args[1] = 2;
m.Invoke(new TestClass(),args);
Console.WriteLine ("{0}, {1}", args[0], args[1]);
How do I Serialize using XmlSerializer
Serializes and deserializes objects into and from XML documents. The XmlSerializer enables you to control how objects are encoded into XML. XML serialization is the process of converting an object's public properties and fields to a serial format for storage or transport. Deserialization re-creates the object in its original state from the XML output. You can thus think of serialization as a way of saving the state of an object into a stream or buffer
using System;
using System.IO;
using System.Xml.Serialization;
public class Dept
{
public long m_code;
private string m_name;
public Dept(long code,string name)
{
m_code = code; m_name = name;
}
public void Display()
{
Console.WriteLine("dept code: {0} name: {1} ",m_code,m_name);
}
}
class CMain
{
static void Main ()
{
MainXmlSerialize();
MainXmlDeserialize();
}
static void MainXmlDeserialize ()
{
Dept obj;
//step 1 create a serializer
XmlSerializer sr = new XmlSerializer(typeof(Dept));
//step 2 create a file
StreamReader file = new StreamReader("c:\\dotnet\\abc.xml");
//step 3
obj = (Dept) sr.Deserialize(file);
//step 4 close the file
file.Close();
obj.Display();
}
static void MainXmlSerialize ()
{
Dept obj = new Dept (101,"Purchase");
//step 1 create a serializer
XmlSerializer sr = new XmlSerializer(obj.GetType());
//step 2 create a file
StreamWriter file = new StreamWriter("c:\\dotnet\\abc.xml");
//step 3 serialize
sr.Serialize(file,obj);
//step 4 close the file
file.Close();
}
}
How do I Serialize using SoapSerializer
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;
[Serializable]
public class Dept
{
public long m_code;
private string m_name;
public Dept(long code,string name)
{
m_code = code; m_name = name;
}
public void Display()
{
Console.WriteLine("dept code: {0} name: {1} ",m_code,m_name);
}
}
class CMain
{
static void MainSoapDeserialize()
{
Dept obj;
//step 1 create a serializer
SoapFormatter fm = new SoapFormatter();
//step 2 open a file
FileStream file = File.Open("c:\\dotnet\\abc.xml",FileMode.Open);
//step 3
obj = (Dept) fm.Deserialize(file);
//step 4 close the file
file.Close();
obj.Display();
}
static void MainSoapSerialize()
{
Dept obj = new Emp(101,"Purchase");
//step 1 create a serializer
SoapFormatter fm = new SoapFormatter();
//step 2 create a file
FileStream file = File.Create("c:\\dotnet\\abc.xml");
//step 3
fm.Serialize(file,obj);
//step 4 close the file
file.Close();
}
}
How do I Serialize using BinarSerializer
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;
[Serializable]
public class Dept
{
public long m_code;
private string m_name;
public Dept(long code,string name)
{
m_code = code; m_name = name;
}
public void Display()
{
Console.WriteLine("dept code: {0} name: {1} ",m_code,m_name);
}
}
class CMain
{
static void Main()
{
}
static void MainSoapDeserialize()
{
Dept obj;
BinaryFormatter fm = new BinaryFormatter();
//step 2 open a file
FileStream file = File.Open("c:\\dotnet\\abc.xml",FileMode.Open);
//step 3
obj = (Dept) fm.Deserialize(file);
//step 4 close the file
file.Close();
obj.Display();
}
static void MainBinarySerialize()
{
Dept obj = new Dept (10,"jack",101,"Purchase");
//step 1 create a serializer
BinaryFormatter fm = new BinaryFormatter();
//step 2 create a file
FileStream file = File.Create("c:\\dotnet\\abc.dat");
//step 3
fm.Serialize(file,obj);
//step 4 close the file
file.Close();
}
}
Domain
Historically, process boundaries have been used to isolate applications running on the same computer. Each application is loaded into a separate process, which isolates the application from other applications running on the same computer.
The applications are isolated because memory addresses are process-relative; a memory pointer passed from one process to another cannot be used in any meaningful way in the target process. In addition, you cannot make direct calls between two processes. Instead, you must use proxies, which provide a level of indirection.
Managed code must be passed through a verification process before it can be run. The verification process determines whether the code can attempt to access invalid memory addresses or perform some other action that could cause the process in which it is running to fail to operate properly. Code that passes the verification test is said to be type-safe. The ability to verify code as type-safe enables the common language runtime to provide as great a level of isolation as the process boundary, at a much lower performance cost.
Application domains provide a secure and versatile unit of processing that the common language runtime can use to provide isolation between applications. You 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 making cross-process calls or switching between processes. The ability to run multiple applications within a single process dramatically increases server scalability.
Isolating applications is also important for application security. For example, you 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.
The isolation provided by application domains has the following benefits:
· Faults in one application cannot affect other applications. Because type-safe code cannot cause memory faults, using application domains ensures that code running in one domain cannot affect other applications in the process.
· Individual applications can be stopped without stopping the entire process. Using application domains enables you to unload the code running in a single application.
Note You cannot unload individual assemblies or types. Only a complete domain can be unloaded.
· Code running in one application cannot directly access code or resources from another application. The common language runtime 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.
· The behavior of code is scoped by the application in which it runs. In other words, the application domain provides configuration settings such as application version policies, the location of any remote assemblies it accesses, and information about where to locate assemblies that are loaded into the domain.
· Permissions granted to code can be controlled by the application domain in which the code is running.
All objects created in a remote domain are returned by reference and have to derive from MarshallByRefObject. Objects passed as parameters to a remote method call can be forwarded by value or by reference. The default behavior is pass by value provided the object in question is marked by the custom attribute [serializable]. Additionally, the object could implement the ISerializable interface, which provides flexibility in how the object should be serialized and deserialized. Objects that are not marshal by reference or marshal by value cannot be accessed across domains.
using System;
using System.Runtime.Remoting;
namespace BULibrary
{
[Serializable]
public class CBank
{
public CBank()
{
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
}
public void Credit()
{
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine("credit");
}
}
public class CBankEx : MarshalByRefObject
{
CBank m_bank = new CBank();
public CBankEx()
{
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
}
public void Debit()
{
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine("debit");
}
public CBank GetBank()
{
return m_bank;
}
}
}
While a common language runtime host creates application domains automatically when they are needed, you can create your own application domains and load into them assemblies you want to personally manage. You can also create application domains from which you execute code.You create a new application domain using one of the overloaded CreateDomain methods in the System.AppDomain class. You can give the application domain a name and reference it by that name.
using System;
using System.Reflection;
namespace TestinterDomain
{
class Class1
{
static void Main(string[] args)
{
//step 1 create a domain
AppDomain domain = AppDomain.CreateDomain("MyDomain");
//step 2 load the assembly in the new domain
//step 3 create a instance of CBajnk
//step 4 get a serialized object in current domain
object obj =domain.CreateInstanceAndUnwrap("BULibrary","BULibrary.CBankEx");
//step 5 get the type
Type t = obj.GetType();
//step 6 call the method
t.InvokeMember("Debit",BindingFlags.InvokeMethod,null, obj, null);
//step 7 unload the domain
AppDomain.Unload(domain);
}
}
}
Satellite Assembly
One time in .NET that you need to know about satellite assemblies is when you are dealing with localization. For localizing text, one doesn't hard code text on a page, but uses a key for that text. The text equivalent for the key is retrieved from a file called a resource file. A resource file is essentially a dictionary of associations between the keys and their textual values. You will have this resource file duplicated once for each language that you support. .NET will retrieve values from these multiple language-resource files based on the chosen language context.
String.txt
name=jack
key=value
Step 1: Use resgen to create a .resources file from a .resx file.
Resgen MyText.resx
The above command will create a file called:
MyText.resources
Step 2: Use al.exe to create the satellite assembly:
Al.exe
/t:lib
/embed:MyText.en-gb.Resources,MyApplication.MyText.en-gb.Resources
/culture:hi-gb
/out:MyApplication.resources.dll
There are a couple of things worth noting here:
/t:lib: Says you are interested in a .dll.
/embed:MyText.en-gb.Resources,MyApplication.MyText.en-gb.Resources : Embeds and renames the resource to a target name to match the Visual Studio IDE naming structure.
/culture:hi-gb : Identifies the culture in which you are interested.
/out:MyApplication.resources.dll : Name of the DLL in which you are interested.
The generated .dll has to have that naming convention for .NET to find it. Also notice that you have to specify the culture setting, even though the culture is available in the name of the resource files. So it has to be mentioned in both places.
Place the Satellite Assembly in the Appropriate Directory
Once the satellite assembly is created, physically copy the .dll to the following directory:
\MyApplication\bin\en-gb\MyApplication.Resources.DLL
c:/> resgen string.txt
c:/> al /t:library /embed:string.resource /out:string.resource.dll
using System;
using System.Resources;
namespace testResource
{
class CMain
{
static void Main(string[] args)
{
ResourceManager rm =
ResourceManager.CreateFileBasedResourceManager("mystring","c:\\dotnet",null);
Console.WriteLine(rm.GetString("name"));
}
}
}
Place the Satellite Assembly in the Appropriate Directory
Once the satellite assembly is created, physically copy the .dll to the following directory:
\MyApplication\bin\en-gb\MyApplication.Resources.DLL
This would have been identical if Visual Studio IDE had generated this file. Repeat this process for each languagein which you are interested.
----------------------------------------------------------------DISCLAIMER--------------------------------------------------------- Information transmitted by this EMAIL is proprietary to iGATE Group of Companies and is intended for use only by the individual or entity to whom it is addressed and may contain information that is privileged, confidential, or exempt from disclosure under applicable law. If you are not the intended recipient of this EMAIL immediately notify the sender at iGATE or mailadmin@igate.com and delete this EMAIL including any attachments |
No comments:
Post a Comment