Because there are now two versions of the .NET Framework out there (there will be three by 2005), .NET developers should be concerned with making sure their applications use the proper version of the Framework at runtime. Most of the time, Web applications compiled with VS.NET 2002 will run on 1.1-enabled Web servers without having to make any changes at all. Microsoft did an outstanding job ensuring that there were as few code-breaking changes between 1.0 and 1.1 as possible.
Web application compatibility
There are certain steps you can take, however, to ensure that your application will gracefully use the version of the Framework you want. Simply add Listing A to the Web.config file.
Now, as long as your app doesn't try to do anything specific to any one version of the Framework, it will run smoothly.
Word of warning
If you need to change the bindings to additional assemblies, such as System.Data.dll, copy one of the existing binding redirects and change the assembly name. Although the public key will always be the same for Framework assemblies, be sure to check the version number, because some assemblies are versioned 7.x.xxxx instead of 1.x.xxxx.
If you're using VS.NET 2003, the IDE will add this information for you automatically. Right-click on the project title in the Solution Explorer, and then click Properties. In the window that follows, select the Build option, and then click the Compatibility button. A dialog box will appear asking you if you want to support 1.1 only, or both 1.0 and 1.1. If you select the second option, the IDE will add a very long list of <assemblyBinding> tags to your Web.config file. This ensures that your app will try to run no matter what.
If you have physical access to the server, you can also use the ASP.NET Version Switcher. This tool reroutes the IIS server mapping for each Web on an individual basis. This is very handy in instances where different apps are compiled against different versions of the .NET Framework running on the same server. The benefit of this method is that you don't have to make any modifications to the application's source files.
Windows application compatibility
The same procedures for Web applications apply to Windows applications. The only difference is that the settings belong in the ApplicationName.config file instead of the Web.config file.
Server control compatibility
Currently, there is no graceful way to handle .NET Framework compatibility issues in server controls and other components that don't utilize a configuration file. There are, however, a few workarounds, and a few more are currently in development. In the sections that follow, I will illustrate for you three such solutions, and discuss their pros and cons.
Option 1: Dual code bases, dual deliverables
While some of you may balk at the idea of maintaining two separate code bases, hear me out before you rush to judgment. Because I sell the source code to many of my components, I use the code as an opportunity to document the ins and outs of working with whatever solution I am attempting to tackle.
Take my GenX.NET component for example. This component takes information from any ADO.NET data source, and exports the data into various formats. For my 1.0-compatible version, GenX.NET uses the Oracle ADO.NET Data provider add-on, which is a separate install and resides in the Microsoft.Data.OracleClient namespace. For my 1.1-compatible version, the Oracle provider is built in, and resides in the System.Data.OracleClient namespace. This one difference alone requires me to maintain two separate versions.
I used this to my advantage and rewrote parts of the code to use new 1.1-specific features, such as declaring variables within cycle operations. This way, when developers buy the source code along with the product (which accounts for 85 percent of my overall sales), they can see how the code makes the best use of the available feature set.
However, there are some pitfalls to this approach. Two code bases require you to be more diligent when bugs come up. It also requires the end user to know which version of the .NET Framework they will be developing against. They must select the right version during the development and deployment process.
You can give users the option of downloading only the version they need, or you can include both versions in the same distribution. You can also take advantage of the assembly naming attributes in the AssemblyInfo file to differentiate between the versions. And you could also give the assembly a different physical name to make it easier to tell the difference.
Option 2: Single code base, dual deliverables
This option comes courtesy of Paul Alexander of Xheo.com. It is possible to maintain a single code base for different versions of the Framework. The secret is to use a Conditional Compilation Constant in your VS.NET 2003 project. You'll still have to maintain two separate project files, but you will have one physical file with all of your code.
Start out by creating your solution and project files. You can keep them in the same directories; just make sure they have different names, like YourSolutionName—2002.sln and YourSolutionName—2003.sln. Now, right-click the VS.NET 2003 project and select Properties. Go to Configuration Options | Build, and then enter the information as shown in Figure A.
|Single code base configuration|
Make sure you only set this in your VS.NET 2003 project. You can use the code below to separate the .NET Framework versions 1.1 and 1.0, like so:
#If NET11 Then
'..do something specific to .NET 1.1
'..do something specific to .NET 1.0
This is a great solution, but it may not always keep your code files unified. Depending on how you organize your projects in your source code repository, you may still end up needing to have a file for each version.
Option 3: Manually reference .NET 1.0 in the IDE
The next option requires a little less work, but completely negates the advantages of using VS.NET 2003 and .NET 1.1. In your project, you can manually remove the references to the 1.1 versions of the Framework assemblies (1.0.5000) and replace them with the 1.0 versions (1.0.3705). Your assembly will still be compiled with 1.1, but there is no guarantee that it will work 100 percent of the time. In fact, you will still have issues if the component is used on Windows Server 2003, on which 1.1 is installed by default.
I feel that this is the least acceptable option, as do others in the .NET community. It has not been tested in all situations and has the possibility of creating some headaches, but it is an option. This option comes courtesy of Frans Bourma, creator of the LLBLGen Data Access Layer generator component. If you take some time and read Frans’ blog entry and the related posts, you'll see how intense the debate was.
Option 4: Dynamically reference Framework assemblies
This one requires some actual coding and might make your code just a tad bit more difficult to read (and write), but it is an option nonetheless. Instead of using the IDE to specify your dependencies, you can load them programmatically, based on what version of the .NET Framework is running the application.
However, dynamically loading .NET Framework assemblies is a catch-22, because you can't use Reflection to dynamically load the System.dll assembly which contains the System.Reflection namespace.
I've given you several options for dealing with different versions of the .NET Framework in your applications. You can bet that this system will continue to improve in future versions of the .NET Framework, and that this methodology will continue to evolve. For now, just make sure that, whatever option you choose, you keep it consistent across your entire code base. There is nothing worse than inconsistent code.
For more information on the .NET Framework versions 1.0 and 1.1, check out these links:
- GotDotNet: Breaking Changes Between .NET 1.0 and 1.1
- Early & Adopter: What's New in .NET 1.1 & VS.NET 2003
- Early & Adopter: Side-By-Side Framework Execution
- Robert McLaws: Upgrade Issues with VS.NET 2003 and .NET 1.1
- Robert McLaws: Ride the Platform Wave: .NET 1.1