Chapter 8. Customizing How Assemblies Are Loaded


In Chapter 7, I describe the CLR default behavior for locating and loading assemblies. This default deployment model works well for common application scenarios ranging from rich client executables to Web applications to controls embedded in Web pages. Part of the reason the default deployment model has gained such broad acceptance is that it promotes concepts that address problems (most notably DLL Hell) that were prevalent in the native Microsoft Windows programming model. The CLR encourages a private deployment model that helps keep applications isolated and makes them easier to install, uninstall, and replicate. In addition, the CLR provides a hierarchical version policy system that gives application developers, administrators, and component vendors a say in which version of an assembly is loaded.

Although the characteristics of the default deployment model are positive, the CLR implementation of this model has three fundamental assumptions that sometimes make it difficult to realize these benefits in other application scenarios. First, the CLR assumes that all assemblies are contained in files stored on disk. Assumptions are even made about the extensions of these files in some cases. For example, all dependent assemblies stored in an application's directory must have a .dll extension. Second, the CLR assumes that all assemblies for an application are stored either in the application's base directory, in the global assembly cache (GAC), or at locations identified in the application's configuration file. Finally, the CLR assumes that the hierarchy of version policies applies equally in all scenarios. A prime example of how these built-in assumptions make it hard to adapt the CLR deployment model to a new application environment is Microsoft SQL Server 2005. SQL Server 2005 has some deployment requirements that are at odds with how the CLR works by default. For example, SQL Server stores all assemblies directly in the databasenot as individual files in the file system. Second, the level of control over which versions of assemblies get loaded as part of a SQL Server application differs quite dramatically from other scenarios, such as rich client or Web applications. Specifically, SQL Server would like to disable the ability to run a different version of an assembly than the one that was originally installed with the application. This requirement arises from the fact that SQL Server can persist instances of managed objects as data stored in the database. This occurs, for example, if a user defines a database column whose type is a class written in managed code (that is, a user-defined database type, in SQL Server terminology). In these cases, the data is persisted by serializing the object instance directly into the table. If, later, a different version of the type were used to deserialize the object, a mismatch of fields might occur and the type would not load. Similar issues occur if managed objects are used as part of the definition of a database index. If one version of a type is used to create the index and another version is used to read it, there's a chance that the index might be invalid, resulting in dramatically decreased performance. In a production environment that requires a nearly perfect degree of reliability and consistent performance, the chance of failure introduced by loading a new version of an assembly cannot be tolerated. So SQL Server requires that the assemblies defined as part of the application are exactly the ones used when the application is run.

I can imagine many other scenarios in which you'd like to store assemblies somewhere other than in a standard portable executable file (PE file) on disk, search for them in a location the CLR normally wouldn't look, or customize the way the default version policy system works. For example, instead of storing assemblies on disk, you might need to generate assemblies dynamically using the classes in the System.Reflection.Emit namespace. You might also want to load assemblies out of a "container" file such as a .cab or a .jar file. Furthermore, you might need to implement a new mechanism for locating assemblies. You can find this useful if you're moving an existing application model from a different platform to Microsoft .NET Framework, for example.

You can take two approaches to customize the CLR default deployment model to accommodate the scenarios I've described. First, you can use some of the events and methods on the System.AppDomain and System.Reflection.Assembly classes (namely, the AppDomain.Load(byte[]...), Assembly.Load(byte[]...) methods, and the AppDomain.AssemblyResolve() event). Although this approach enables you to customize the CLR entirely from within managed code, you can control only certain aspects of the assembly loading process. The second way you can customize the default deployment model is to use the CLR hosting APIs to write a host that implements an assembly loading manager. This approach requires you to write unmanaged code and requires more effort, but you can customize the CLR to a much greater extent because you are integrating with the CLR at a much lower level. In fact, the amount of customization available when writing an assembly loading manager is so extensive that you can completely replace the CLR assembly loading implementation. This is the approach that SQL Server has taken to implement its custom deployment model.

The goal of this chapter is to describe these two approaches in enough detail that you can decide which approach best fits your scenario.



    Customizing the Microsoft  .NET Framework Common Language Runtime
    Customizing the Microsoft .NET Framework Common Language Runtime
    ISBN: 735619883
    EAN: N/A
    Year: 2005
    Pages: 119

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net