380 likes | 402 Vues
Learn the fundamentals of extensible applications, such as changing program features without recompiling, using reflection for dynamically loaded assemblies, and implementing strong and weak assembly names. Dive into version policies, binding references, and app domain management. Explore how to load add-ins and perform remote calls in a secure and efficient manner.
E N D
Loading Assemblies in Extensible Applications By Avinash R. Prasad
What are extensible applications? • Provide the ability to change the basic features of a program or add new features without recompiling • Provide the ability to load in and execute new code, including code written after program is shipped • Built using reflection, interfaces & dynamically loaded assemblies • Examples: IE 6, Visual Studio .Net 2003, SQL Server
Concepts and Terminology • Assembly names: Strong & Weak (used for locating assemblies) • Binding references: Early Vs Late • Specifying references: Fully Vs Partially • Version policy
Strong & Weak Names • Assembly’s identity consists of 4 parts: • Friendly name : File name without the extension • Version: String with 4 dot-limited numbers, major version, minor version, build number & revision number • Public key: Unique value to map a company or developer, occupies 128 bytes • Culture: Two letter code indicating localization for a particular language, can carry country code
Strong & Weak Assembly Names (Contd.) • Strong name when assigned cryptographic key pair, else weak name (done with compiler or sn.exe) to ensure security • Strong names used when intended to share among several applications • Strong name files have digital signatures embedded in the file containing the manifest • Strong name contains public key used to generate signature • For more info. lookup Applied Microsoft Framework Programming by Jeffrey Richter
Early Vs Late Binding • Early bound references recorded in metadata when assembly is compiled • Late bound references specified on the fly using APIs on System classes • Extensible applications to use both • .assembly extern statement represents early bound reference to an assembly • We shall focus on late binding
Fully and Partially specified references • When all four fields are specified, assembly reference is said to be Fully specified • If any field missing, it is Partially specified, results in looser binding semantics • ASP.NET uses partial binding and weakly named assemblies
Version Policy • CLR uses strict version checking to minimize conflicts between different versions, loads exact version by default • However can be overridden by series of statements called version policy. • Set in XML files • Has 3 levels: • Author of application • Publisher of shared assembly • Machine administrator
Extensible Application’s use of App Domains • Multiple app domains used to isolate add-ins • App domain manager (Ch. 5) created for each app domain to call assembly loading APIs • Add-in assemblies not loaded in default app domain • Communication between app domains limited to app domain managers
Key design issues • Limit volume of communication in terms of number of calls and data passed • Limit number of assemblies involved in calls across app domains (as an assembly must be loaded in both app domains) • Both app domains must be unloaded to completely remove assembly from process
System.Reflection.Assembly • Recall that calling a method on a type in another app domain is a remote call • Types used are marshaled by value and marshaled by reference (derive from System.MarshalByRefObject) • Type used to represent assemblies in .Net is marshaled by value, not by reference!! • So, instance of assembly must be loaded into the app domain where instance resides
Effects of marshal by value • Add-in assembly must be loaded into our default app domain, so can’t unload without terminating entire process • Can also lead to security breaches if policy in that domain is not configured correctly • Complication in deployment when specifying ApplicationBase • CLR tries to load assemblies into app domain never intended
Steps followed when loading a new add-in • Extensible apps made aware of new add-in (thro’ user interface or config file) • App domain is chosen in which to load (eg. all apps from same site in same app domain) • App domain manager in target domain is called to load add-in • App domain manager in target domain loads the add-in
.Net provided methods to load assemblies • AppDomain.Load - load into other app domains • AppDomain.ExecuteAssemblyByName – executes code when called • AppDomain.CreateInstance • AppDomain.CreateInstanceAndUnwrap • Assembly.Load – static method, so can load only in current app-domain • Assembly.LoadWithPartialName – deprecated in 2.0 and will be removed in future versions • Activator.CreateInstance
Ways to specify assembly identities • Specifying assembly identities with strings • Specifying assembly identities with System.Reflection.AssemblyName
Specifying Identities as Strings • “[friendlyName], Version=[number], PublicKeyToken=[token], Culture=[culture]” • friendlyName must come first while others can be in any order • Incorrect assembly names result in FileLoadException • If any of them not specified, then we have Partially Specified Assembly Reference
Specifying Identities using System.Reflection.AssemblyName • Has properties and methods to identify assembly to load • Property Name • Property Version • Property CultureInfo • Method SetPublicKey (byte[]) • Method SetPublicKeyToken (byte[])
How CLR locates assemblies • ApplicationBase – root directory, intended to be private for that domain • Global Assembly Cache (GAC) – CLR looks here first to resolve reference to strongly names assembly • Version Policy – XML configuration file • Codebases – Same config file with <codebase> XML element
Locating assemblies with weak names • Looks for codebase in app config file • Add-in comes with own application configuration file • Not likely to be used often as user will have to modify ConfigurationFile property in own application to use it • Probe for assembly in ApplicationBase or its subdirectories – loaded by name only
Locating assemblies with strong names • Steps to resolve reference • Determine version of assembly to load from the 3 version policy files • Look in GAC for assembly • Look in configuration files for any codebase locations • Probe in ApplicationBase and its sub-directories
Advantages of loading assembly from GAC • Better overall system performance • Loading from same location on disk uses less memory • OS loads DLL’s read-only pages once and shares them among all instances • Efficient verification of strong name • Verification process long and tedious • Only verified when installed into the GAC
Fuslogvw.exe • Logs each step CLR completes when resolving reference to a library • Useful for diagnosing errors and understanding loading process • Has two modes of running • Log every attempt to load an assembly • Log only those attempts that fail
Assembly loading exceptions • System.IO.FileNotFoundException – not found by CLR • System.IO.FileLoadException – when CLR encounters an error when parsing assembly name string passed to one of the APIs • System.BadImageFormatException – when file is not managed code
How CLR resolves partially specified assembly references • Looks in ApplicationBase – if strongly names found in ApplicationBase, then looks in GAC, searches version policy etc. • Public key token checked against assemblies in ApplicationBase, if not then FileLoadException is thrown • If version is specified with friendly name and assembly has weak identity, assembly is loaded nonetheless
Critical issues related to Assembly.LoadFrom • CLR must ensure that assemblies loaded dynamically by filename do not conflict with statically referenced assemblies • So, CLR isolates assemblies loaded statically from those loaded dynamically using binding contexts • Binding contexts are Load Context and LoadFrom Context
Other scenarios • CLR must make sure that types of the same name from different binding contexts are not mistaken for each other as problems occur during typecasting • If two assemblies from different locations but same weak name are attempted to be loaded, only one is loaded
Versioning considerations • Add-in could be built with different version of .Net, so version conflict • All versions of .Net are compatible with previously released versions i.e. backward compatible • Do not load add-ins from newer versions into applications written in previous versions • Loading add-in built in previous version into application in newer version OK
Versioning considerations (Contd.) • Application designer can pick which version of CLR to load into his process • Once CLR selected, consistent set of assemblies will be loaded into process (Unification) • If unification causes problems, override in application config file the choice of CLR to load • ImageRuntimeVersion used to determine version of CLR and .Net used
Unification (Contd.) • Two possible solutions • Load multiple versions of .Net framework libraries into same process • Redirect various references to single version of .Net Framework assemblies • Insufficient testing carried out my Microsoft to support these scenarios • So, CLR redirects all references to assemblies matching the CLR loaded into the process
Summary • All add-in assemblies to be loaded in a late-bound fashion • Use .Net’s API methods for loading • Implement version policy where appropriate • Use provided tools such as fuslogvw.exe for debugging
What’s coming in Version 2.0 • ReflectionOnly APIs - load exact file, no policy, no second-bind • Assembly.ReflectionOnly • Assembly.ReflectionOnlyLoad • Assembly.ReflectionOnlyLoadFrom • AppDomain.ReflectionOnlyGetAssemblies • AppDomain.ApplyPolicy • Type.ReflectionOnlyGetType
References • Customizing The Microsoft .Net Common Language Runtime – Steven Pratschner • Extensible Applications: New features without recompiling – Joe Wirtley http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnhcvs04/html/vs04f1.asp