| By Brian Berry | Article Rating: |
|
| November 8, 2004 12:00 AM EST | Reads: |
20,651 |
When I first read that .NET assemblies could be "redirected" at runtime, I was stunned and a little bit suspicious. After all, in the COM world the intricacies of component interaction had baffled me, but I knew enough to know that dynamic redirection just wasn't possible. To be honest, I relied on Visual Basic's Binary Compatibility mode to do the job and hoped for the best. But most of the time I found myself having to rebuild VB6 executables simply because I had changed the implementation of a method they referenced in a library. The process of fixing the mistake was infuriating; as far as I was concerned, code reuse was a nice-sounding concept, but not something with which to be overly preoccupied.
But things have changed now that Microsoft has unveiled the Common Language Runtime (CLR), which promises side-by-side execution and the holy grail of assembly binding redirection. How assembly binding redirection really works cannot be understood without some context, because there are some fundamental differences between COM and .NET. The most important difference is in how each implements intracomponent communication. COM binds to methods physically at design time by locating memory locations and binding to method address offsets. .NET achieves the same objective in a completely different manner. Through a process called "virtualization," it binds method calls logically at design time by writing appropriate metadata to each assembly. .NET postpones physical binding until runtime, delegating this responsibility to the CLR's Assembly Loader. Without Intermediate Language and just-in-time compilation this would not be technically possible. If you would like further information regarding this, I recommend Don Box's Essential .NET, Vol. 1: The Common Language Runtime.
As a consequence of virtualization, method implementations can be switched on demand and applications can receive an assembly upgrade in much the same way that hardware receives upgraded components time and again. This is why I like to refer to .NET binding as "plug-and-play" assemblies.
The linchpin of plug-and-play is the collaboration between an organization's public/private key pair and the sn.exe tool; you cannot plug and play assemblies that have not been strongly named. In fact, an assembly intended to represent an upgraded version of another assembly must be signed with the same key pair as its predecessor in order for the CLR to recognize the version relationship between them. If this isn't done, the two assemblies will be treated as two separate and distinct assemblies. Based on what we know of the CLR's late binding of assemblies, this makes sense. If the new version of the assembly has an identical interface and the same key pair as the old, then the signature will match and the assembly will be eligible to be loaded and hooked up for method calls within the app domain. I see it as a sort of "type safety" for code.
Every assembly hosted by the CLR can be configured just in time by the CLR's Assembly Loader. In other words, an administrator can, without touching any code, swap one assembly version for another by editing the .config file associated with the executable and restarting the executable.
Trust, but Verify
Of course all of the theory in the world wasn't going to convince me about the reliability of assembly binding redirection. Seeing is believing, so I created a simple example to test the functionality and clear up any lingering doubts I had. I'm happy to say that I am now convinced. Here's how I went about proving the viability of assembly binding redirection.
First, I created three folders in which to place three distinct assemblies, each a different version of another. I placed them beneath an application folder and called them Version 1, Version 2, and Version 3.
Next, I started a new class library project named "SimpleSharedComponent". The assembly defines a constructor and a single method named GetAssemblyFullName, which returns a string identifying itself (see Listing 1).
Before compiling the library, I generated a public/private key pair called SimpleKey.snk. Those familiar with this process know that you must place an attribute in the AssemblyInfo file of SimpleSharedComponent that refers the compiler to your key file. Also in the AssemblyInfo file, I explicitly established a version for this assembly called Version 1.0.0.0 (see Listing 2).
Version 1.0.0.0 belongs in the folder Version 1, so I set the Project Properties for SimpleSharedComponent to build to this directory. I then built the SimpleSharedComponent and used gacutil.exe to install it in the Global Assembly Cache.
Next, I created a second project in the solution, a console application named "SimpleClient". This application does one thing: it calls the SimpleSharedComponent's GetAssemblyFullName and outputs the response to the console (see Listing 3). Then I created a project reference to SimpleSharedComponent in SimpleClient. To be sure that I was loading from the GAC, I set the "Copy Local" reference property to False.
Now I was ready to build the solution. Running the console application yielded the expected results.
Then I pretended three months had passed and the business rules had changed. I needed to quickly replace SimpleSharedComponent with a new version. For simplicity's sake, I needed to change only the assembly version to 2.0.0.0. Finally, in order to preserve Version 1, I edited the project's Output Path property to build this to the folder named "Version 2."
In order to redirect SimpleClient to bind to Version 2 at runtime, I needed only to create a configuration file with a binding redirection node (see Listing 5). Notice that both assemblies are named strongly and share the same public key.
Depending on your specific needs, there are a number of ways to achieve this binding redirection. For example, you can also set the configuration file to load a particular version of an assembly in lieu of a range of versions (see Listing 6). Or, if you decide that you want all calls for Version 1.0.0.0 redirected to 2.0.0.0, you can use the Microsoft .NET Framework 1.1 Configuration Tool, typically found under Administrative Tools. This tool will help you edit the machine. config file safely.
Running SimpleClient.exe again, I achieved a very different result. I know what you're thinking; I didn't change any code, so how do I know the runtime didn't simply swap metadata between two assemblies? While this is highly doubtful, I ruled this out by changing the nature of the implementation, just to be sure. You still must return a string from the method call, but to keep things clear, I returned my own custom string this time (see Listing 7). I also edited the Version Number to 3.0.0.0 and set the Output Path to "Version 3".
After the application was built, I edited the configuration file for SimpleClient.exe (see Listing 8). When I was finished, I saw the custom string.
Implications for Object-Oriented Design
So my test proved to me that the CLR works as advertised: it truly removes the final obstacle to reusable code, permitting any .NET application to dynamically load shared code on demand, at runtime, with no recompiling necessary. The ability to plug and play assemblies would be a good solution for many scenarios, e.g., an architect dealing with a solution whose requirements shift due to forces beyond the organization's control.
Here is an example: a university would like to provide a portal for its incoming freshmen, current students, and alumni. One of the components of the portal will be a module that allows students to view their tuition balance with the university. Calculating this balance is very complicated because elements of the calculation can change as federal regulations change, e.g., Stafford Loans. For instance, new government-backed student loan packages are proposed nearly every four years, just before November elections.
As a systems architect facing this problem, I may choose to implement the Strategy Pattern here. The Strategy Pattern, as defined in Design Patterns by Gamma, Helm, Johnson, and Vlissides, is a pattern designed to "define a family of algorithms, encapsulate each one, and make them interchangeable." To do this, I could choose to design an assembly that defines a base class for LoanCalculator, which exposes methods for calculating balances, interest to date, etc., for a client. I may then decide to derive various implementations for this LoanCalculator (a, for example). I could even include in the assembly a LoanCalculator Factory for producing the correct LoanCalculator on demand.
When it comes time to render the tuition balance calculation, the client calling the CalculateBalance method of LoanCalculator, perhaps a simple XSLT transformation, is not only unaware of which LoanCalculation it is calling, but also unaware that, when the calculation changed, I seamlessly changed Version 1 for Version 2. Granted, a recycling of HttpApplication objects will occur when the change takes place. However, the application downtime is substantially decreased, and no recompiling of the user interface code or any other code in the system is required. To the users of the system, the application is highly available and the information is accurate; the portal becomes a reliable source of information.
Fulfillment of Promise
I believe that assembly binding redirection is possibly the most exciting feature of .NET. It makes the principles of object-oriented design far easier to implement and commit to early in the design phase and frees architects from having to over-plan their designs. However, many developers may not be aware of this aspect of .NET. Those that are will realize that we finally have a tool that gives us the flexibility and reusability that we've been waiting for.
Published November 8, 2004 Reads 20,651
Copyright © 2004 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Brian Berry
Brian Berry is a senior consultant with Tallán, Inc., a professional services firm providing customized technology solutions to Global 2000 and brand-name firms. Brian is a Microsoft Certified Solution Developer for .NET. Since 1985 Tallán has been building intelligent technology systems that help clients achieve critical business goals. The company is based in Glastonbury, CT, with offices in Irvine, CA; Chicago; Boston; New York; and Washington, D.C.
![]() |
Larry DuBois 11/21/04 11:52:10 AM EST | |||
Very good. How about the same issue of versions, but with web services. |
||||
- Kindle 2 vs Nook
- Practical Approaches for Optimizing Website Performance
- SQL Anywhere Server and AJAX
- PowerBuilder Top Feature Picks
- The Difference Between Web Hosting and Cloud Computing
- PowerBuilder 12 and .NET
- Contrary Opinion: Why Silverlight is Good for Adobe
- Ajax in RichFaces 3.3, JSF 2 and RichFaces 4
- Wave on Ulitzer: Confessions of a Google Wave Fanboy
- Cloud Computing Best Practices
- AJAX World RIA Conference & Expo Kicks Off in New York City
- Rich Content Rotator for ASP.NET
- RIAs for Web 3.0 Using the Microsoft Platform
- Kindle 2 vs Nook
- Practical Approaches for Optimizing Website Performance
- Social Media Terrorists
- SQL Anywhere Server and AJAX
- SYS-CON's Cloud Expo Adds Two New Tracks
- PowerBuilder Top Feature Picks
- The Difference Between Web Hosting and Cloud Computing
- Google Maps and ASP.NET
- Crystal Reports XI & How It Has Changed
- Converting VB6 to VB.NET, Part I
- Creating Controls for.NET Compact Framework in Visual Studio 2005
- Where Are RIA Technologies Headed in 2008?
- How to Write High-Performance C# Code
- AJAX World RIA Conference & Expo Kicks Off in New York City
- Implementing Tab Navigation with ASP.NET 2.0
- i-Technology Photo Exclusive: Bill Gates & Steve Jobs In "Nerds"
- .NET Archives: Getting Reacquainted with the Father of C#




































