Pages

Sunday, October 20, 2013

.NET Versioning and Multi-Targeting - .NET 4.5 is an in-place upgrade to .NET 4.0

Say what you will about the past ridiculousness of .NET Framework versioning, since the confusion of .NET 3.5SP1 they've  been trying to get it right. It's not the magic of Java Version 6 Update 31 (build 1.6.0_31-b05) but it's a start. O_o
Back in July of 2011 I wrote a post on Issues with .NET and Microsoft Product Versioning that got the attention of some folks. I was most concerned about some "platform updates" to .NET 4 and the way they were named. Meetings were had and those small updates now have simpler names versions like NET 4.0.1, etc.
I'm not going to tell you it's not confusing today. I do think that things are getting better and becoming less confusing. .NET 4.5 is a step in the right direction of transparency in versioning.
The .NET Framework can version in two ways. There are "side by side installs" and there are "in place upgrades." A major version means side-by-side and a minor version means in-place.
Side-by-side means that different versions of .NET can live together on the same machine.
Diagram: .NET CLRs can live side by side
In-place upgrade means that the CLR is the same but new libraries are added as well as bug fixes and performance improvements:
Diagram: .NET 4.5 builds on top of .NET 4
There's been some concern about how .NET 4.5 is an "in-place upgrade" of .NET 4. That means .NET 4.5 is still the v4CLR and adds new libraries as well as improvements to the core CLR itself.
Rick Strahl said on his blog:
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.
Rick has a great post with a lot of detail and information. However, respectfully, I don't think .NET 4.5 vs. .NET 4 is as different as Rick implies. In fact .NET 3 and .NET 3.5 both upgraded the system (and CLR) in place as well.
Perhaps if 3 and 3.5 were called .NET 2.5 and .NET 2.8 it would have made more sense. The community is always concerned about breaking changes, much like we are here with .NET 4 and .NET 4.5. Unfortunately reality and marketing names haven't always matched, but going forward I think we all agree that:
  • Major Version = New CLR
  • Minor Version = Bug fixes, new libraries
  • Revision = Bug fixes, no breaking changes, small improvements
.NET 4.5 is not a radically different side-by-side CLR. A new CLR would be a theoretical .NET 5 In my opinion.
Could something break with .NET 4.5? This is why it's in beta now, so now is the time to speak up. It'spossible something could break but unlikely according the .NET Blog. Here are the known .NET 4.5 breaking changes - most are pretty obscure. The kinds of breaking changes I've seen myself in the wild have been primarily when folks are relying on reflection or internal data structures. These internals aren't public contracts so they may have changed. I realize that when a change breaks YOU it feels like a situation when "100% of applications will break....mine did!" situation. It sucks, but in fact there are minimal breaking changes in .NET 4.5.
Can I get .NET 2.0, 3.5, 4 and 4.5 apps all running together on my system? Yes.
Can I develop apps with different versions with Visual Studio 11 Beta? Sure, you can multi-target all these versions and even plugin more targeting packs. I'll do a blog post later this week on Portable Libraries, a new version in .NET 4.5 that makes creating libraries for any CLR (including Xbox, Phone, Mono and others).
Screenshot of the multi-targeting dropdown in Visual Studio

DEVELOPING SAFELY FOR BOTH .NET 4 AND .NET 4.5

It's been implied on blogs that if you install .NET 4.5 on your machine that you can't safely develop for .NET 4. In Rick's post, he compares two DLLs on a .NET 4 machine and again after the .NET 4.5 in place upgrade. How can you target safely against .NET 4 if you've installed .NET 4.5? You don't have those .NET 4 DLLs anymore, right?
Actually you do. They are in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework.
Reference Assemblies
Let's prove it on a machine with Visual Studio 11 Beta. I'll make a DLL and reference System.Web and make use of one of the added types in that assembly. Yes, it's a screenshot of code, but hang in there.
Using the .NET 4.5 ModelBinderDictonary Type
Now I'll change the properties of my project from .NET 4.5 to .NET 4. I won't change anything else. I'll build. Note that the type isn't there, I get a build error and I can't reference the namespace. You will know if you're using new .NET 4.5 functionality. The multi-targeting build system was designed for this and existed as far back as .NET 3.5. Those reference assemblies are there to catch this kind of thing.
Referencing .NET 4 and using a type we don't have will cause a compiler error
So while .NET 4 and .NET 4.5 don't live side by side on your system at runtime, Visual Studio knows about all the different versions of .NET and the compiler will reference different versions when you build.
If you are making a client app, like WinForms, Console, WPF, etc, this is all automatic. Your app.config contains that fact that you need .NET 4.5 and you'll even get a prompt to install it.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>
So if I run my .NET 4.5 Console App on a .NET 4.0 machine now I get a nice dialog.
A dialog that pops up when running .NET 4.5 apps on .NET 4 to prompt an update
Looks like this technique doesn't work on ASP.NET (I would expect a Yellow Screen of Death)...I will talk to the team about that. I think this is a good thing and ASP.NET should respect it also.
UPDATE #2: The system will throw an error when an ASP.NET 4.5 application is deployed to an ASP.NET 4 system. The default templates on for ASP.NET 4.5 applications include the targetFramework attribute set to 4.5 like this:
1
2
3
4
5
<configuration>
    <system.web>
        <compilation debug="true" strict="false" explicit="true" targetFramework="4.5" />
    </system.web>
</configuration>
This will throw a YSOD if you deploy a 4.5 to a 4 machine like this: "The 'targetFramework' attribute currently references a version that is later than the installed version of the .NET Framework."
UPDATE: If you really, really want to detect .NET 4.5 at runtime, don't check versions or build numbers. Check for the existence of the feature you want to use. For example, from this Stackoverflow question byChristian K, here's how to detect .NET 4.5 programmatically.
However, David from the CLR team (in the comments) says that this is not a good idea. He says to check if an important feature is there and use it. Don't cheat and infer .NET versions.
"The IsNet45OrHigher example is not what we'd recommend. By feature detection, we mean 'detecting the presence of a feature before you use that feature', <i>not</i> 'using the presence of a feature to determine what version of .NET you are runnning on."
public static bool IsNet45OrNewer()
{
    // Class "ReflectionContext" exists from .NET 4.5 onwards.
    return Type.GetType("System.Reflection.ReflectionContext", false) != null;
}
Identifying the current operating system is usually not the best way to determine whether a particular operating system feature is present. This is because the operating system may have had new features added in a redistributable DLL. Rather than using GetVersionEx to determine the operating system platform or version number, test for the presence of the feature itself.

No comments:

Post a Comment