With the betas for .NET 4.5 and Visual Studio 11 and Windows 8 shipping many people will be installing .NET 4.5 and hacking away on it. There are a number of great enhancements that are fairly transparent, but it's important to understand what .NET 4.5 actually is in terms of the CLR running on your machine.
When .NET 4.5 is installed it effectively replaces .NET 4.0 on the machine. .NET 4.0 gets overwritten by a new version of .NET 4.5 which - according to Microsoft - is supposed to be 100% backwards compatible. While 100% backwards compatible sounds great, we all know that 100% is a hard number to hit, and even the aforementioned blog post at the Microsoft site acknowledges this. But there's so much more than backwards compatibility that makes this awkward at best and confusing at worst.
What does ‘Replacement’ mean?
When you install .NET 4.5 your .NET 4.0 assemblies in the \Windows\.NET Framework\V4.0.30319 are overwritten with a new set of assemblies. You end up with overwritten assemblies as well as a bunch of new ones (like the new System.Net.Http assemblies for example). The following screen shot demonstrates system.dll on my test machine (left) running .NET 4.5 on the right and my production laptop running stock .NET 4.0 (right):
Clearly they are different files with a difference in file sizes (interesting that the 4.5 version is actually smaller).
That’s not all. If you actually query the runtime version when .NET 4.5 is installed with with Environment.Version you still get:
4.0.30319
If you open the properties of System.dll assembly in .NET 4.5 you'll also see:
Notice that the file version is also left at 4.0.xxx.
There are differences in build numbers: .NET 4.0 shows 261 and the current .NET 4.5 beta build is 17379. I suppose you can use assume a build number greater than 17000 is .NET 4.5, but that's pretty hokey to say the least.
There’s no easy or obvious way to tell whether you are running on 4.0 or 4.5 – to the application they appear to be the same runtime version. And that is what Microsoft intends here. .NET 4.5 is intended as an in-place upgrade.
Compile to 4.5 run on 4.0 – not quite!
You can compile an application for .NET 4.5 and run it on the 4.0 runtime – that is until you hit a new feature that doesn’t exist on 4.0. At which point the app bombs at runtime. Say you write some code that is mostly .NET 4.0, but only has a few of the new features of .NET 4.5 like aync/await buried deep in the bowels of the application where it only fires occasionally. .NET will happily start your application and run everything 4.0 fine, until it hits that 4.5 code – and then crash unceremoniously at runtime. Oh joy!
You can .NET 4.0 applications on .NET 4.5 of course and that should work without much fanfare.
Version Detection
If you're building a .NET 4.5 application you do have some control over the runtime via YourApp.exe.config file options. Specifically you can specify that the app requires .NET 4.5 like this (thanks for Scott Hanselman pointing this out in the comments):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0"
sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
This works to ensure that the app will refuse to start on .NET 4.0 with an error on startup rather than waiting for something to blow up at runtime.
Likewise .NET 4.5 Web applications can use the targetFramework element on the <compilation> element:
<configuration>
<system.web>
<compilation debug="true"
strict="false"
explicit="true"
targetFramework="4.5" />
</system.web>
</configuration>
This works fine for standalone applications and server, but it there's no solution for assemblies that are added to other projects. To a 4.0 project a .NET 4.5 assembly just looks like another 4.0 assembly.
For developers - especially component developers - this is also problematic since there's no built in way to determine whether you're running .NET 4.5. Environment.Version returns 4.0.
The following code block (dumped into the awsome LinqPad):
void Main()
{
Environment.Version.ToString().Dump();
Environment.Version.Build.Dump();
Environment.Version.Revision.Dump();
Environment.Version.Major.Dump();
}
On .NET 4.0 it results in:
4.0.30319.269
30319
269
4
On .NET 4.5 it results in:
4.0.30319.17379
30319
17379
4
Pretty close, eh? Note however that the Revision number is high on .NET 4.5 - 17379 on the current build, while the .NET 4.0 revision number is 261. So if you really have to check specifically for .NET 4.5 you can use code like this:
// Define other methods and classes here
public static bool IsDotNet45()
{
return Environment.Version.Major == 4 &&
Environment.Version.Revision > 17000;
}
Others have commented (on Hanselman's post), that it's better to do feature detection for a new feature of .NET 4.5. The code Scott used uses a new class for .NET 4.5 plus some Reflection code to check for it:
public static bool IsNet45OrNewer()
{
// Class "ReflectionContext" exists from .NET 4.5 onwards.
return Type.GetType("System.Reflection.ReflectionContext", false) != null;
}
One advantage of this approach is that you're checking for a feature rather than a specific version, so in the future this code will continue to work so you effectively can future proof code.
Still it's pretty telling that we'll have to resort to this sort of chicanery just to figure out freaking version compatibility.
Different than .NET 3.0/3.5
Note that this in-place replacement is very different from the side by side installs of .NET 2.0 and 3.0/3.5 which all ran on the 2.0 version of the CLR. The two 3.x versions were basically library enhancements on top of the core .NET 2.0 runtime. Both versions ran under the .NET 2.0 runtime which wasn’t changed (other than for security patches and bug fixes) for the whole 3.x cycle. The 4.5 update instead completely replaces the .NET 4.0 runtime and leaves the actual version number set at v4.0.30319.
When you build a new project with Visual Studio 2011, you can still target .NET 4.0 or you can target .NET 4.5. But you are in effect referencing the same set of assemblies for both regardless which version you use. What's different is the compiler used to compile and link your code so compiling with .NET 4.0 gives you just the subset of the functionality that is available in .NET 4.0, but when you use the 4.5 compiler you get the full functionality of what’s actually available in the assemblies and extra libraries. It doesn’t look like you will be able to use Visual Studio 2010 to develop .NET 4.5 applications.
Good news – Bad news
Microsoft is trying hard to experiment with every possible permutation of releasing new versions of the .NET framework apparently. No two updates have been the same. Clearly updating to a full new version of .NET (ie. .NET 2.0, 4.0 and at some point 5.0 runtimes) has its own set of challenges, but doing an in-place update of the runtime and then not even providing a good way to tell which version is installed is pretty whacky even by Microsoft’s standards. Especially given that .NET 4.5 includes a fairly significant update with all the aysnc functionality baked into the runtime. Most of the IO APIs have been updated to support task based async operation which significantly affects many existing APIs.
To make things worse .NET 4.5 will be the initial version of .NET that ships with Windows 8 so it will be with us for a long time to come unless Microsoft finally decides to push .NET versions onto Windows machines as part of system upgrades (which currently doesn’t happen). This is the same story we had when Vista launched with .NET 3.0 which was a minor version that quickly was replaced by 3.5 which was more long lived and practical.
People had enough problems dealing with the confusing versioning of the 3.x versions which ran on .NET 2.0. I can’t count the amount support calls and questions I’ve fielded because people couldn’t find a .NET 3.5 entry in the IIS version dialog. The same is likely to happen with .NET 4.5. It’s all well and good when we know that .NET 4.5 is an in-place replacement, but administrators and IT folks not intimately familiar with .NET are unlikely to understand this nuance and end up thoroughly confused which version is installed.
It’s hard for me to see any upside to an in-place update and I haven’t really seen a good explanation of why this approach was decided on. Sure if the version stays the same existing assembly bindings don’t break so applications can stay running through an update. I suppose this is useful for some component vendors and strongly signed assemblies in corporate environments. But seriously, if you are going to throw .NET 4.5 into the mix, who won’t be recompiling all code and thoroughly test that code to work on .NET 4.5? A recompile requirement doesn’t seem that serious in light of a major version upgrade.
Resources
Other Posts you might also like