ExecutionEngineException in ASP.NET MVC when mixing .NET Framework and .NET Standard assemblies
TL;DR: If you mix .NET Standard assemblies that depend on the System.Net.Http NuGet package into your .NET Framework ASP.NET MVC app, you are likely to encounter runtime crashes when your AppDomain unloads and reloads. The solution involves a binding redirect and a project build time setting.
This one was fun to figure out. I’m working on a project, where I really, really wanted to use Microsoft’s SpaServices package to enable server-side rendering for a Node frontend app. Fortunately, it only takes a little bit of glue to make them stick to an ASP.NET MVC 5 app, and you’re off to the races.
Unfortunately, it also comes with a nasty side effect of periodically crashing your app during development.
It took me a while to recognize the pattern, but after a dozen or so crashes, I finally figured out, that the exception always occurred after I had either edited the Web.config file or rebuilt the binaries — that is, whenever the AppDomain was unloaded and the app restarted.
The problem was initially triggered by ASP.NET Web Api’s
EnsureInitialized call, but the culprit at the top of the stack was actually
RuntimeAssembly.GetTypes() — so when I managed to trick Web Api into not triggering the problem, it was pushed forward to something Glimpse did. When I removed Glimpse, it moved to something that the ASP.NET MVC infrastructure did, and so on.
The actual problem is a combination of different issues: when running on the desktop framework, the System.Net.Http version you’re supposed to use is the one shipped in the framework. However, that version has some weird versioning quirks due to the fact that it isn’t just a .NET assembly, it’s also a Windows component. This leads to it having a version number that is smaller than the NuGet counterpart, which, in some edge cases, leads to the wrong assembly ending up in your process. I’m not sure where the memory corruption comes into play (and I’m not sure I want to know 😛), but fortunately the fix is simple.
You need to add a binding redirect for System.Net.Http and set ImplicitlyExpandNETStandardFacades to false in your project, as described in this GitHub comment.
Ah, System.Net.Http. Since it began shipping out-of-band, it’s just the gift that keeps on giving…
I’m not bringing much new information to the table, but I hope this post at least helps someone else find the solution to the same issue without spending hours diagnosing it.