Home Random Page


CATEGORIES:

BiologyChemistryConstructionCultureEcologyEconomyElectronicsFinanceGeographyHistoryInformaticsLawMathematicsMechanicsMedicineOtherPedagogyPhilosophyPhysicsPolicyPsychologySociologySportTourism






Nbsp;   Assembly Loading

As you know, when the just-in-time (JIT) compiler compiles the Intermediate Language (IL) for a method, it sees what types are referenced in the IL code. Then at run time, the JIT compiler uses the assembly’s TypeRef and AssemblyRef metadata tables to determine what assembly defines the type being referenced. The AssemblyRef metadata table entry contains all of the parts that make up the strong name of the assembly. The JIT compiler grabs all of these parts—name (without extension or path), version, culture, and public key token—concatenates them into a string, and then attempts to load an assembly matching this identity into the AppDomain (assuming that it’s not already loaded). If the assembly being loaded is weakly named, the identity is just the name of the assembly (no version, culture, or public key token information).

Internally, the CLR attempts to load this assembly by using the System.Reflection.Assembly class’s static Load method. This method is publicly documented, and you can call it to explicitly load an assembly into your AppDomain. This method is the CLR equivalent of Win32’s LoadLibrary function. There are actually several overloaded versions of Assembly’s Load method. Here are the prototypes of the more commonly used overloads.

 

public class Assembly {

public static Assembly Load(AssemblyName assemblyRef); public static Assembly Load(String assemblyString);

// Less commonly used overloads of Load are not shown

}

 

Internally, Load causes the CLR to apply a version-binding redirection policy to the assembly and looks for the assembly in the global assembly cache (GAC), followed by the application’s base direc- tory, private path subdirectories, and codebase locations. If you call Load by passing a weakly named assembly, Load doesn’t apply a version-binding redirection policy to the assembly, and the CLR won’t look in the GAC for the assembly. If Load finds the specified assembly, it returns a reference to an Assembly object that represents the loaded assembly. If Load fails to find the specified assembly, it throws a System.IO.FileNotFoundException.


       
   
 

 

In most dynamically extensible applications, Assembly’s Load method is the preferred way of loading an assembly into an AppDomain. However, it does require that you have all of the pieces that make up an assembly’s identity. Frequently, developers write tools or utilities (such as ILDasm.exe, PE- Verify.exe, CorFlags.exe, GACUtil.exe, SGen.exe, SN.exe, XSD.exe) that perform some kind of process- ing on an assembly. All of these tools take a command-line argument that refers to the path name of an assembly file (including file extension).


To load an assembly specifying a path name, you call Assembly’s LoadFrom method.

 

public class Assembly {

public static Assembly LoadFrom(String path);

// Less commonly used overloads of LoadFrom are not shown

}

 

Internally, LoadFrom first calls System.Reflection.AssemblyName’s static GetAssemblyName method, which opens the specified file, finds the AssemblyDef metadata table’s entry, and extracts the assembly identity information and returns it in a System.Reflection.AssemblyName object (the file is also closed). Then, LoadFrom internally calls Assembly’s Load method, passing it the AssemblyName object. At this point, the CLR applies a version-binding redirection policy and searches the various locations looking for a matching assembly. If Load finds the assembly, it will load it, and an Assembly object that represents the loaded assembly will be returned; LoadFrom returns this value. If Load fails to find an assembly, LoadFrom loads the assembly at the path name specified in LoadFrom’s argument. Of course, if an assembly with the same identity is already loaded, LoadFrom simply returns an Assembly object that represents the already loaded assembly.



By the way, the LoadFrom method allows you to pass a URL as the argument. Here is an example.

 

Assembly a = Assembly.LoadFrom(@"http://Wintellect.com/SomeAssembly.dll");

 

When you pass an Internet location, the CLR downloads the file, installs it into the user’s download cache, and loads the file from there. Note that you must be online or an exception will be thrown.

However, if the file has been downloaded previously, and if Windows Internet Explorer has been set to work offline (see Internet Explorer’s Work Offline menu item in its File menu), the previously down- loaded file will be used, and no exception will be thrown. You can also call UnsafeLoadFrom, which can load a web-downloaded assembly, bypassing some security checks.

       
   
 

 

Microsoft Visual Studio’s UI designers and other tools typically use Assembly’s LoadFile method. This method can load an assembly from any path and can be used to load an assembly with the same identity multiple times into a single AppDomain. This can happen as changes to an application’s UI are made in the designer/tool and the user rebuilds the assembly. When loading an assembly via LoadFile, the CLR will not resolve any dependencies automatically; your code must register with AppDomain’s AssemblyResolve event and have your event callback method explicitly load any dependent assemblies.

If you are building a tool that simply analyzes an assembly’s metadata via reflection (as discussed

later in this chapter), and you want to ensure that none of the code contained inside the assembly


executes, the best way for you to load an assembly is to use Assembly’s ReflectionOnlyLoadFrom method, or in some rarer cases, Assembly’s ReflectionOnlyLoad method. Here are the prototypes of both methods.

 

public class Assembly {

public static Assembly ReflectionOnlyLoadFrom(String assemblyFile); public static Assembly ReflectionOnlyLoad(String assemblyString);

// Less commonly used overload of ReflectionOnlyLoad is not shown

}

 

The ReflectionOnlyLoadFrom method will load the file specified by the path; the strong- name identity of the file is not obtained, and the file is not searched for in the GAC or elsewhere. The ReflectionOnlyLoad method will search for the specified assembly looking in the GAC, application base directory, private paths, and codebases. However, unlike the Load method, the ReflectionOnlyLoad method does not apply versioning policies, so you will get the exact version

that you specify. If you want to apply versioning policy yourself to an assembly identity, you can pass the string into AppDomain’s ApplyPolicy method.

When an assembly is loaded with ReflectionOnlyLoadFrom or ReflectionOnlyLoad, the CLR forbids any code in the assembly from executing; any attempt to execute code in an assembly loaded with either of these methods causes the CLR to throw an InvalidOperationException. These methods allow a tool to load an assembly that was delay-signed, would normally require security permissions that prevent it from loading, or was created for a different CPU architecture.

Frequently, when using reflection to analyze an assembly loaded with one of these two methods, the code will have to register a callback method with AppDomain’s ReflectionOnlyAssembly­ Resolve event to manually load any referenced assemblies (calling AppDomain’s ApplyPolicy method, if desired); the CLR doesn’t do it automatically for you. When the callback method is invoked, it must call Assembly’s ReflectionOnlyLoadFrom or ReflectionOnlyLoad method to explicitly load a referenced assembly and return a reference to this assembly.

       
   
 
 


Many applications consist of an EXE file that depends on many DLL files. When deploying this ap- plication, all the files must be deployed. However, there is a technique that you can use to deploy just a single EXE file. First, identify all the DLL files that your EXE file depends on that do not ship as part of the Microsoft .NET Framework itself. Then add these DLLs to your Visual Studio project. For each DLL file you add, display its properties and change its Build Action to Embedded Resource. This causes the C# compiler to embed the DLL file(s) into your EXE file, and you can deploy this one EXE file.

At run time, the CLR won’t be able to find the dependent DLL assemblies, which is a problem. To fix this, when your application initializes, register a callback method with the AppDomain’s Resolve­ Assembly event. The callback method’s code should look something like the following.

 

private static Assembly ResolveEventHandler(Object sender, ResolveEventArgs args) { String dllName = new AssemblyName(args.Name).Name + ".dll";

 

var assem = Assembly.GetExecutingAssembly();

String resourceName = assem.GetManifestResourceNames().FirstOrDefault(rn => rn.EndsWith(dllName));

if (resourceName == null) return null; // Not found, maybe another handler will find it using (var stream = assem.GetManifestResourceStream(resourceName)) {

Byte[] assemblyData = new Byte[stream.Length]; stream.Read(assemblyData, 0, assemblyData.Length); return Assembly.Load(assemblyData);

}

}

 

Now, the first time a thread calls a method that references a type in a dependent DLL file, the AssemblyResolve event will be raised and the preceding callback code will find the embedded DLL resource desired and load it by calling an overload of Assembly’s Load method that takes a Byte[] as an argument. Although I love the technique of embedding dependent DLLs inside another assem- bly, you should be aware that this does increase the memory used by your application at run time.

 

 


Date: 2016-03-03; view: 786


<== previous page | next page ==>
Nbsp;   Advanced Host Control | Nbsp;   Using Reflection to Build a Dynamically Extensible Application
doclecture.net - lectures - 2014-2024 year. Copyright infringement or personal data (0.007 sec.)