Thursday, 6 September 2012

Iterator blocks, missing methods, and .NET 4.5

We had some fun a while ago where we had a flurry of MissingMethodException occurring on some boxes, in particular, complaining that Environment.CurrentManagedThreadId was missing. And sure enough, this is a 4.5 method, and the affected servers were 4.0 – so it was kinda valid, but completely unexpected. At the time, our most pragmatic option was just: deploy 4.5, but we’ve finally had time to go back and understand it!

This happened after we upgraded our build server to 4.5, for some initial 4.5 usage – but all our core projects were still 4.0 at the time.

Fix first:

MAKE SURE YOUR BUILD SERVER HAS THE REFERENCE ASSEMBLIES FOR 4.0!

These are typically somewhere like:

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0

Now, the full story:

fact 1: 4.5 is an in-place over-the-top install on top of 4.0, in the GAC; once you have installed 4.5, 4.0 runs with the 4.5 assemblies

fact 2: if your build server doesn’t have the reference assemblies, it looks in the GAC – so… once you’ve installed 4.5, it will get 4.5 even if you asked (in your project) for 4.0

fact 3: the c# compiler has a detail relating to iterator blocks (aka "yield return" and "yield break") that involves threading, i.e. "which thread am I?"

fact 4: the implementation for this changes between 4.0 and 4.5; in 4.0, it uses (in the generated iterator-type’s constructor) Thread.CurrentThread.ManagedThreadId – but in 4.5 it uses Environment.CurrentManagedThreadId; it makes this decision based on the framework version it finds it has loaded (taking into account targeting etc)

Put these pieces together, and you can get a scenario where a 4.0 project that uses 4.0-only methods, seems to build successfully, but builds in a way that will only work on 4.5; it will never work on 4.0.

Fun fun fun!

12 comments:

Anonymous said...

How do I get the reference assemblies for 4.0 installed? Is it as simple as installing .NET 4.0 runtime first? Or do I need the Windows 7 SDK? Or do I need the whole of VS2010?

Marc Gravell said...

You should already have those folders on your dev box. Copy them from there...

Jon Skeet said...

Yikes! Have you reported this to the C# team? I suspect they'd at least want to document it, if not fix it in a service pack...

Atul said...
This comment has been removed by a blog administrator.
Marc Gravell said...

@Jon I've spoken about it behind the scenes, yes - and I understand more about it etc. It seems just an unfortunate consequence of what may be an all-too-common configuration / setup, however.

Stephen Fourie said...

Thank you Thank you Thank you!!!

Andrea said...

@Marc
I have installed VS2012 and NET4.5
The reference ASsemblies from 4.0 are in the C:\program files\... folder.

But if I target them (4.0) from the VS project, it still uses the Runtime assemblies in the GAC!

How can I force VS to use the old 4.0 assemblies?

PS: I have a production server with only 4.0 installed. Should I copy the assemblies from there?

PPS: This post of mine here: http://stackoverflow.com/q/16936965/1012244 has all the details

Thank you

Marc Gravell said...

@Andrea in truth, I don't know; the asp.net build is quite a bit different to regular csc build, and I can't claim to be an expert in getting that to target a very specific framework version from the reference-assemblies. Sorry.

Andrea said...

Thanks, after struggling three days after it I'm disinstalling Net4.5 and repairing VS 2010... Hope this helps!

Anonymous said...

I'm having the same issue with a website that throws this exact error. It runs fine locally where I have .net 4.5 installed but fails on the server that doesn't.

The whole project is running .net 4.0 and all the assemblies are referenced to the 4.0.0.0 but it still fails on the server.

I'm now trying removing .net 4.5 on my development machine and compile the site again to see if it makes any difference when the project is then deployed to the server.

Otherwise I just have to see if I can convince the hosting partner that they should install .net 4.5 on the live-server..

Lamar Hays said...

This is a good explanation about Iterator blocks, missing methods, and .NET 4.5 which really helps any .NET development in their development work.

Jesper, delebarn.dk said...

Hi.

First. Thank you!!

Then. Do you know of ANY way to deploy an MVC 5 app to a shared hosting service with only 4.0.3 installed ?

Cheers /Jesper Petersen