| Understanding .Net Assemblies and References |
|
Page 1 of 5 An introduction to the nuances of .Net assemblies and references for anyone who's be bewildered by their intricacies. Originally published on Jan 6, 2006.
Assembly Manifest Every .Net assembly contains a manifest that contains descriptive information about the assembly, including the assembly identity information (name, etc, see below), what files make up the assembly, what types or functionality can be called from a different assembly, and what other assemblies it depends upon. You can view the assembly manifest by opening it with the ildasm tool. Run ildasm.exe from the .Net Command Line. The assembly manifest doesn’t store the paths used when you add a reference through the IDE – it only stores information about the assemblies being referenced. Before I continue, here are a number of .Net references for further reading.
IDE ReferencesIn order to write code that uses the functionality of a different component, the development environment needs to know what that component is capable of doing and how to call its functionality. In Visual Studio, you make your application aware of other components by “adding references” to them. When a reference to an assembly is added, the IDE will inspect the manifest of the referenced assembly to see what it can do and how it should be used. You can add File, Project, COM, .Net, Web, and dynamic references to Visual Studio projects. I’ll discuss File and Project references in more detail, and the others below, plus a bit about VB6 references as they relate to .Net. In this context, references are for the IDE and build process, not for application execution. Project References: When you use a project reference (preferred, if at all possible), then you’re telling a project that it depends upon the output of another project in the same solution. When the solution builds, the IDE builds the dependencies first, then finds the output DLLs in the output paths associated with the current configuration. (If you’re in Debug configuration, it’ll find that output file in the referenced project’s Debug bin, and if you’re in Release configuration, it’ll find it in its Release bin.) Once found, the file is copied into the obj directory of the application, then to the bin directory when the build is complete. (The obj directory is basically a temporary working folder that the IDE uses during builds.) This is all pretty handy, and that’s why it’s preferred. If a dependency can’t be built, the IDE will (by default) keep going down its list of builds and you’ll probably get an error when the referencing assembly tries to build and the file can’t be found. Project references can only be exchanged among projects in the same solution. (Projects, by the way, are perfectly happy existing in more than one solution at a time.) File References: When you use a file reference, you actually specify the exact path that the IDE will use to find the referenced assembly so it can examine its manifest and learn how it works. If the referenced file is not in the GAC and not a framework component, then the Copy Local property of the reference will default to True, meaning that during build, the IDE will follow the reference path, fetch the file, and copy it into the obj and bin directories so it can be found and used at run time (see below). This can have unfortunate side effects, though, if more than one version of the same file name is referenced along the dependency chain. (The file system knows nothing about assembly names or assembly versions and only considers file names when copying a file from one place to another.) For this reason, it’s a good idea to disable "Copy Local" in these cases. For example, if
Other reference types: Here’s a brief overview of the other types of references:
VB6 References: Because VB6 knew nothing about .Net when it was born, it wouldn’t know what to do with an Assembly if it were given one. Because of this, Microsoft created a way for .Net assemblies to masquerade as COM objects and a tool that generates a type library from an assembly (tlbexp.exe). A type library is the ActiveX equivalent of an assembly manifest – it contains lots of interface information but no code. Once the functionality of an ActiveX object is discovered using a type library, it’s up to the consuming application to actually find the file that contains the code. It does this by way of the system registry. First it looks up the fully qualified name of the class being instantiated (e.g. MyCompany.MyTechnology.MyClass) in H_KEY_CLASSES_ROOT. It finds that class’ ID (CLSID, a GUID), and then looks up that class ID in H_KEY_CLASSES_ROOT/CLSID. From there it inspects that key’s InprocServer32 key. The default value of this key contains the path of the application that will be run. In the case of .Net assemblies, this is always mscoree.dll, which serves as a shim, managing the differences between .Net and COM. The other properties of this key tell mscoree.dll how to find the actual .Net assembly that should be treated as a COM component. This may (but not necessarily) include a codebase path to the assembly. |
||||||||||||||||||||||||
| Last Updated ( Saturday, 26 July 2008 20:32 ) | ||||||||||||||||||||||||









