The .NET Framework v3.0 and v3.5 both broke some versioning rules, and I suppose there was good reason. Version 3.0 was just version 2.0 plus a few new DLLs for WPF, WCF, WF, and CardSpace. But those new technologies were huge, huge enough to give the .NET Framework a new version number. Meanwhile, though, the C# language and .NET Framework 3.5 forked off cosistency again, in a way that was unnecessary, and with double the damage. C# 3.0 runs on .NET 3.5 -- that is way too confusing. C# 3.0 compiles to the .NET 2.0 CLR. That is way too confusing, too. .NET Framework 3.5 builds on top of .NET Framework 3.0 and 2.0. That would make sense, except that v3.0 and v2.0 are sort of seperate entities.
If you open up C:\Windows\Microsoft.NET\Framework, you'll find each of these .NET Framework versions deployed in their own directory..
08/29/2007 12:30 AM <DIR> v1.0.3705
08/29/2007 01:01 AM <DIR> v1.1.4322
12/15/2007 03:13 PM <DIR> v2.0.50727
11/02/2006 08:15 AM <DIR> v3.0
11/19/2007 09:49 PM <DIR> v3.5
08/28/2007 05:22 PM <DIR> VJSharp
Incidentally, notice that v3.0 and v3.5 don't have build numbers, while the others do. Refer back to my rant about inconsistency. (Personally, I never liked the build numbers being there anyway.) Meanwhile, VJSharp is completely unversioned.
Then there are tons of utility files that do not belong in this directory at all, and Microsoft allowed a mess to be made in here:
08/29/2007 05:39 AM <DIR> 1028
08/29/2007 06:58 AM <DIR> 1030
08/29/2007 02:57 AM <DIR> 1031
08/29/2007 03:10 AM <DIR> 1035
08/29/2007 04:13 AM <DIR> 1036
08/29/2007 06:05 AM <DIR> 1040
08/29/2007 03:55 AM <DIR> 1042
08/29/2007 07:27 AM <DIR> 1043
08/29/2007 06:31 AM <DIR> 1044
08/29/2007 05:16 AM <DIR> 1046
08/29/2007 03:39 AM <DIR> 1049
08/29/2007 03:23 AM <DIR> 1053
08/29/2007 04:33 AM <DIR> 2052
08/29/2007 04:53 AM <DIR> 3082
11/01/2006 11:33 PM 72,704 NETFXSBS10.exe
02/20/2003 06:44 PM 36,354 NETFXSBS10.hkf
09/18/2006 02:32 PM 41,392 netfxsbs12.hkf
11/19/2007 09:09 PM 16,896 sbscmp10.dll
11/19/2007 09:09 PM 16,896 sbscmp20_mscorwks.dll
11/19/2007 09:09 PM 16,896 sbscmp20_perfcounter.dll
11/01/2006 11:33 PM 5,120 sbs_diasymreader.dll
11/01/2006 11:33 PM 5,120 sbs_iehost.dll
11/01/2006 11:33 PM 5,120 sbs_microsoft.jscript.dll
11/01/2006 11:33 PM 5,632 sbs_microsoft.vsa.vb.codedomprocessor.dll
11/01/2006 11:33 PM 5,120 sbs_mscordbi.dll
11/01/2006 11:33 PM 5,120 sbs_mscorrc.dll
11/01/2006 11:33 PM 5,120 sbs_mscorsec.dll
11/01/2006 11:33 PM 5,120 sbs_system.configuration.install.dll
11/01/2006 11:33 PM 5,120 sbs_system.data.dll
11/01/2006 11:33 PM 5,120 sbs_system.enterpriseservices.dll
11/01/2006 11:33 PM 5,120 sbs_VsaVb7rt.dll
11/01/2006 11:33 PM 5,120 sbs_wminet_utils.dll
11/19/2007 09:09 PM 16,896 SharedReg12.dll
Now we're one step closer to looking like the infamous Windows Registry. Each Microsoft employee or department gets to put his own file or entry wherever he wants, see? I wonder how many Microsoft employees have decided to move their office desks to the middle of the front lobby, besides the nice front desk lady(ies).
Anyway, the reason why I posted here is because, ironically, the .NET Framework does not appear in the PATH for some strange reason. I've always had to manually add "DOTNET", pointing to C:\Windows\Microsoft.NET\Framework\v1.1.4322 or ...\v2.0.50727 to my environment variables, then add %DOTNET% to my PATH. I used this regularly for tools like my own AssemblyLister so I could easily pre-JIT my assemblies for faster boot time (even if the trade-off is slower runtime performance). But this broke with v3.0 and it is still broken in v3.5, because there is no CLR and Framework directory that runs .NET Framework v3.5. .NET Framework v3.5, like v3.0, is just some add-on assemblies to v2.0. But if I were to reference only the v2.0 directory, I would only have the v2.0 framework (plus the GAC, which, fortunately, contains the v3.0 and v3.5 DLL assemblies, but not their utilities).
Fortunately, you can cascade the .NET versions in the PATH. I don't know why I didn't do this a long time ago, but the PATH environment variable, which is a semi-colon delimited list of directories in which to search for files in the file system shell without referencing their complete paths, is already a cascading list. In other words, when searching for a file using the PATH, the first directory listed is scanned first, then the second, and so on.
One thing I like about the .NET Framework versioning that Microsoft claimed that they are committed to when they were working on v2 was that the .NET Framework will try to be forwards-compatible and will always be backwards-compatible to assemblies targeting different versions of the CLR. This means that a v1.1 assembly can be run in a v2.0 CLR, and a v2.0 assembly might be able to run in a v1.1 CLR. In the end, it's just MSIL that the CLR breaks down into machine code at runtime (unless it's pre-JITted).
So as long as you're using an environment (such as cmd.exe or PowerShell) that splits the PATH string into multiple directores, recursively finding more %variables%, and scans them one by one in cascading order, you can effectively use a single environment variable to reference all of your .NET Framework directories at the same time, with the newer .NET Framework files taking priority over the older files. To do this, just add each .NET Framework version, starting with v3.5, then v3.0, then v2, then v1.1 (if v1.1 is installed), into a DOTNET environment variable, and then add %DOTNET% to your path.
DOTNET = C:\Windows\Microsoft.NET\Framework\v3.5; C:\Windows\Microsoft.NET\Framework\v3.0; C:\Windows\Microsoft.NET\Framework\v2.0.50727; C:\Windows\Microsoft.NET\Framework\v1.1.4322; C:\Windows\Microsoft.NET\Framework\v1.0.3705
PATH (virtually on %PATH%, not literally) = %PATH%;%DOTNET%
By "virtually on %PATH%, above, all I mean is that you would replace %PATH% with what it already is, then append ";%DOTNET%".
If I wanted to use the 64-bit versions of the .NET Framework, I could do the same, using C:\Windows\Microsft.NET\Framework64\, but meanwhile also adding the x86 paths for compatibility.
C:\Windows\Microsoft.NET\Framework64\v3.5; C:\Windows\Microsoft.NET\Framework64\v3.0; C:\Windows\Microsoft.NET\Framework64\v2.0.50727; C:\Windows\Microsoft.NET\Framework\v3.5; C:\Windows\Microsoft.NET\Framework\v3.0; C:\Windows\Microsoft.NET\Framework\v2.0.50727; C:\Windows\Microsoft.NET\Framework\v1.1.4322; C:\Windows\Microsoft.NET\Framework\v1.0.3705
- or -
C:\Windows\Microsoft.NET\Framework64\v3.5; C:\Windows\Microsoft.NET\Framework64\v3.0; C:\Windows\Microsoft.NET\Framework64\v2.0.50727; %DOTNET%
PATH = %PATH%;%DOTNETX64%
Unfortunately, though, this brings another issue into the mix. Which one do you want in your PATH, %DOTNET% or %DOTNETX64%? This is an important question. I do ASP.NET development in 32-bit and I debug my apps in explicit x86 CPU build mode (because Visual Studio doesn't let me perform edit-and-continue tasks in 64-bit, which is already the default environment for the "Any CPU" build mode). But without compiling to 64-bit, CLR assemblies can hit the RAM registry space ceiling, quickly running out of RAM (OutOfMemoryException or something similar), and this has happened to me already while building a search engine server based on Lucene.NET.
To be honest, I'm still not sure. I'm going to try using the 64-bit path variable (%DOTNETX64%) for now and see if it brings me any problems. I think Windows is defaulting to that one already. Meanwhile, though, I can still continue to target x86 CPUs in my builds.
So to test this out, I try where in Vista to see the cascading effect. (Note that any time you change the PATH environment variable, or any environment variable(s), you must close the command shell window and restart it before the variables will propogate. They will not propogate into the GUI shell until you log out and log back in.)
So it seems to work, which is nice.
Meanwhile, I still need an environment variable to single directory for my primary CLR, which contains ngen.exe and csc.exe and other CLR essentials.
There's one last change I need to make, though. It might make more sense to change the environment variable %DOTNET% to %NETFXX86%, and then change %DOTNETX64% to %NETFX%. This way, apps that target a %NETFX% environment variable can properly target the environment's complete and CPU-targeted environment rather than just focus solely on x86 compatibility.
So, here's what I have in the end:
NETFX = %NETFXX64%; %NETFXX86%
DOTNET = %NETFX%
CLRDIR = C:\Windows\Microsoft.NET\Framework64\v2.0.50727
C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin; %SystemRoot%\system32; %SystemRoot%; %SystemRoot%\System32\Wbem; %SYSTEMROOT%\System32\WindowsPowerShell\v1.0\; C:\Program Files (x86)\Microsoft SQL Server\90\Tools\binn\; C:\Program Files (x86)\Microsoft SQL Server\80\Tools\Binn\; C:\Program Files\Microsoft SQL Server\90\DTS\Binn\; C:\Program Files\Microsoft SQL Server\90\Tools\binn\; C:\Program Files (x86)\Microsoft SQL Server\90\DTS\Binn\; C:\Program Files (x86)\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\; C:\Program Files (x86)\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies\; C:\Program Files (x86)\QuickTime\QTSystem\; C:\Program Files (x86)\Common Files\Adobe\AGL; C:\Windows\SUA\common\; C:\Windows\SUA\usr\lib\; C:\Program Files\Microsoft Network Monitor 3\; E:\filez\dev\IronPython-1.1; C:\Program Files (x86)\GnuWin32\bin; C:\ruby\bin; C:\MinGW\bin; C:\cygwin\bin;
Now I can use "native" .NET apps like csc.exe or ngen.exe, and have all tools and assemblies on hand, without manually loading the SDK command shell.
I created an EXE to auto-configure this: SetNetFxEnvVars.exe [source] Note that it will require an immediate reboot. Note also that if you're using Internet Explorer, in order to run the EXE you must download it and then unblock it (right-click it, choose Properties, then click Unblock).