Search This Blog

Thursday 2 June 2016

Regarding .NET Framework and CLR versions


Being primarily a .NET developer, I’ve had the chance to work with several versions of the framework throughout the last couple of years. One major pain for us developers can be to understand to differentiate between the version of the target framework (that you compile against) and the version of the CLR (that is actually used to run your managed assembly). This is usually not a problem in developer environments, but may become a nuisance after deployment, as the system you deploy to might have different framework versions installed (either older or newer). Then a few weeks after deployment you get some dump files from your clients and start scratching your head seeing that the version of the loaded CLR (and also what the !eeversion sos command returns) couldn’t be more different from your target framework version. What’s going on here?

I decided to conduct some research and ended up reading the following references:


Imbued with this knowledge I felt the urge to summarize what I learned in a Q&A manner, so that you (and I) don’t have to read all these resources once again.

How do I find out which .NET Framework version was used to compile an assembly?

This can be a tough one below v4.0. All "solutions" mentioned in forums / articles failed to provide an ultimate approach (including using DUMPBIN / ILDASM / ILSpy / Reflector).
But for v4.0+ things couldn’t be easier. Just load your assembly with ILSpy and look for the TargetFramework attribute. It will show the proper framework version the assembly was compiled against.

How do I find out which CLR version(s) are loaded in a process / dump?

I encourage you to use WinDbg to find this piece of information. Either attach to the process or load the dump file in question and issue the following command:

0:000> lmv m clr
start             end                 module name
00007ff9`1bda0000 00007ff9`1c728000   clr        (deferred)            
    Image path: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
    Image name:       clr.dll
    Timestamp:        Thu Jul 30 01:51:50 2015 (55B96716)
    CheckSum:         00991460
    ImageSize:        00988000
    File version:     4.6.96.0
    Product version:  4.0.30319.0
    File flags:       8 (Mask 3F) Private
    File OS:          4 Unknown Win32
    File type:        2.0 Dll
    File date:        00000000.00000000
    Translations:     0409.04b0
    CompanyName:      Microsoft Corporation
    ProductName:      Microsoft® .NET Framework
    InternalName:     clr.dll
    OriginalFilename: clr.dll
    ProductVersion:   4.6.96.0
    FileVersion:      4.6.96.0 built by: NETFXREL2STAGE
    PrivateBuild:     DDBLD032A
    FileDescription:  Microsoft .NET Runtime Common Language Runtime - WorkStation
    LegalCopyright:   © Microsoft Corporation.  All rights reserved.
    Comments:         Flavor=Retail

If it gives you no results but you know you’re using .NET then try:

0:005> lmv m mscorwks
start             end                 module name
000007fe`f5090000 000007fe`f5a2e000   mscorwks   (deferred)            
    Image path: C:\Windows\Microsoft.NET\Framework64\v2.0.50727\mscorwks.dll
    Image name:       mscorwks.dll
    Timestamp:        Wed Jun 18 07:02:36 2014 (53A11D6C)
    CheckSum:         0098CBB7
    ImageSize:        0099E000
    File version:     2.0.50727.5485
    Product version:  2.0.50727.5485
    File flags:       0 (Mask 3F)
    File OS:          4 Unknown Win32
    File type:        2.0 Dll
    File date:        00000000.00000000
    Translations:     0409.04b0
    CompanyName:      Microsoft Corporation
    ProductName:      Microsoft® .NET Framework
    InternalName:     mscorwks.dll
    OriginalFilename: mscorwks.dll
    ProductVersion:   2.0.50727.5485
    FileVersion:      2.0.50727.5485 (Win7SP1GDR.050727-5400)
    FileDescription:  Microsoft .NET Runtime Common Language Runtime - WorkStation
    LegalCopyright:   © Microsoft Corporation.  All rights reserved.
    Comments:         Flavor=Retail

Silverlight applications depend on a separate Common Language Runtime that can be loaded side-by-side with the .NET CLR. It uses coreclr.dll, so here’s an output for that as well:

0:000> lmv m coreclr
start             end                 module name
00000000`62520000 00000000`6288b000   coreclr    (deferred)            
    Image path: c:\Program Files (x86)\Microsoft Silverlight\5.1.30514.0\coreclr.dll
    Image name:       coreclr.dll
    Timestamp:        Wed May 14 07:30:20 2014 (5372FF6C)
    CheckSum:         0036CD46
    ImageSize:        0036B000
    File version:     5.1.30514.0
    Product version:  5.1.30514.0
    File flags:       8 (Mask 3F) Private
    File OS:          4 Unknown Win32
    File type:        2.0 Dll
    File date:        00000000.00000000
    Translations:     0409.04b0
    CompanyName:      Microsoft Corporation
    ProductName:      Microsoft® Silverlight
    InternalName:     coreclr.dll
    OriginalFilename: coreclr.dll
    ProductVersion:   5.1.30514.0
    FileVersion:      5.1.30514.0 built by: SL_V5_SVC
    PrivateBuild:     DDBLD388E
    FileDescription:  Microsoft .NET Runtime Common Language Runtime - WorkStation
    LegalCopyright:   © Microsoft Corporation.  All rights reserved.
    Comments:         Flavor=Retail

A side note for the sake of completeness: with some limitations, it is possible to run multiple versions of the .NET CLR in a single process. This is referred to as In-Process Side-by-Side Execution.

Where do I find the .NET Framework assemblies on my computer?

x86: %windir%\Microsoft.NET\Framework\
x64: %windir%\Microsoft.NET\Framework64\
These assemblies are also copied to the Global Assembly Cache (GAC) at install time.
GAC folder for .NET Framework assemblies: %windir%\Microsoft.NET\assembly
(note: this GAC folder differs from the one that stores native images, i.e. %windir%\assembly –> this latter path is where NGEN-ed framework dlls end up)

Where do I find the .NET Framework reference assemblies on my computer?

x86 OS: %ProgramFiles%\Reference Assemblies\Microsoft\Framework\.NETFramework
x64 OS: %ProgramFiles(x86)%\Reference Assemblies\Microsoft\Framework\.NETFramework
These guys play a very important role when compiling against a certain Framework version. They contain only public / internal / protected stuff, but all method bodies are empty. This results in relatively small file sizes while making it possible for the compiler to validate your code against the public surface of the target assemblies.

From v4.0 and above, can two framework versions live side-by-side?

No. Versions 4.5+ are in-place updates, so the original files are lost after installing a newer framework version. However, the reference assemblies remain intact, so you can compile against any of the installed versions.

From v4.5 and above, is the CLR itself updated?

It’s hard to tell. One thing is for sure though. The Framework API Environment.Version returns 4.0.30319 no matter which framework you compile against / is installed (v4.0 and above).
Also, it seems that clr.dll itself gets a different file version for each framework as explained by Rodney Viana in Identifying the .NET version you are running.
So my assumption is, there are at least some minor changes in the CLR as well, though Microsoft seems to refer to these CLR versions simply as version "4".

Update #1: in a 4.5.1 environment I noticed that 64-bit managed assemblies get loaded twice in the virtual address space of the running process. This behaviour is gone in 4.6.1 w/o recompiling the problematic application, so now I can say for sure that the CLR itself is also updated from time-to-time.

How do .NET Framework and CLR versions correlate?

.NET Framework
CLR version included
1.0
1.0
1.1
1.1
2.0
2.0
3.0
2.0
3.5
2.0
4.0
4
4.5
4
4.5.1
4
4.5.2
4
4.6
4
4.6.1
4
4.6.2
4
4.7
4

How do I detect which .NET Framework versions are installed on my computer?

Microsoft recommends to check the registry to reliably detect the installed versions. Generally speaking, from 4.5 and above the previous versions are included (down to 4.0), so for instance, installing 4.6.2 includes (4.6.1 & 4.6 & … & 4.0).
With other words if you have only 4.0 installed and want to update to the most recent version then you only need to install that one and gain access to all the features of all framework versions in-between.

How do I detect what CLR versions are installed on my computer?

Use the clrver tool. If you ever wondered why the application pool settings in IIS manager show only .NET Framework v4.0.30319 and no 4.5 or higher entries, then you should understand it by now.

Can I run my .NET 4.0 application on a system, where .NET Framework 4.5 or higher is installed?

Usually yes. Backwards compatibility is taken very seriously at Microsoft, so you shouldn’t have any issues with this.

Can I run my .NET 4.5 or higher application on a system, where only a previous version (e.g.: .NET Framework 4.0) is installed?

Only if you’re not using any version-specific features of the framework. Fortunately, you can specify the supported runtime version in your application configuration file, so that the framework can warn you if the required version is unavailable. In many VS project templates this setting is added to your app.config automatically and gets updated properly when playing around with the target framework version.
It would be possible to detect such scenarios in code and check for the presence of the required feature(s), but I find it more robust to go for the app.config way.

Ok, this configuration stuff is great, but what if you forget to deploy it and use functionality that is unavailable on your target system? Well, I was able to generate a MissingMethodException by using .NET 4.5.1 functionality on a system where only pure 4.0 was installed. But after deploying the aforementioned configuration file, a nice dialog warned me about the version mismatch and offered me a link where I could download the required framework.

For ASP.NET applications I couldn’t find a documented way to do this - as of yet. The <compilation> element in the web.config file does not seem to be a reliable approach for framework versions 4.5 and higher, although the ASP.NET Web Application project template does include <compilation debug="true" targetFramework="4.5.1" /> when targeting 4.5.1.

What is a .NET Framework Client Profile?

According to msdn:
"The .NET Client Profile is a subset of the .NET Framework, which was provided with .NET Framework 4 and earlier versions and was optimized for client applications. The .NET Framework 4 and earlier versions provided two deployment options: the full .NET Framework and the Client Profile. The Client Profile enabled faster deployment and smaller app installation packages than the full .NET Framework. Starting with the .NET Framework 4.5, the Client Profile has been discontinued and only the full redistributable package is available. Optimizations provided by the .NET Framework 4.5, such as smaller download size and faster deployment, have eliminated the need for a separate deployment package."
See the same link for a complete list of included / excluded features for specific Client Profile versions.

What is a .NET Framework (Multi-) Targeting Pack?

The target audience :-) for Targeting Packs are mainly developers. Without these, it would not be possible to target (i.e. compile against) any framework version. Installing e.g. the 4.5.1 Targeting Pack will deploy the necessary reference assemblies and makes it possible to create managed assemblies that target it in Visual Studio.

Update #1: it seems that updating to 4.6.1 (via the Developer Pack) from 4.5.1 does not give you all the reference assemblies in-between, only the assemblies for 4.6.1. You did not expect anything else, did ya? ;-)

What is the .NET Framework SDK?

Developer packs typically ship with this, but it's also part of the Windows SDK, that you can opt-out during installation. It includes reference assemblies and tools targeting the appropriate .NET Framework version. Typical install folder pattern:
%ProgramFiles(x86)%\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools\
%ProgramFiles(x86)%\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2

4 comments: