AssemblyResolve Event and VJSharpCodeProvider

This one kept me up late the other night.  We had an issue where ASP.NET was recompiling a page and we were getting an exception:

System.Exception:

Error loading VJSharpCodeProvider, Version=2.0.0.0, Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a

This was interesting for two reasons:

  1. The application does not use J#.
  2. This is more subtle but nagged the back of my mind - Why is this thrown as a System.Exception and not a System.IO.FileNotFoundException or something more explicit since the framework typically throws specific exceptions.

Some additional background - this problem was only occurring during acceptance testing and did not occur in dev.  They were able to load up the page and successfully run through the application.  Then after stressing the application they would eventually start getting these J# errors and other Dynamic compilation errors from ASP.NET.  This continued until they restarted IIS and cleared the Temporary ASP.NET folder.

They did not have the J# Runtime installed on the system in dev or test and this was completely excepted because they were not using J#.  I got a look at the application and verified this.

Side Note - I have been doing product support for all 6 years that I have been working at Microsoft.  For those of you out there doing similar stuff I am sure you know this and if not take heed - always verify things when working to resolve issues like this.  It is not that anyone out there is intentionally hiding things but people frequently are unaware and when you ask, "Is such and such the case?" they may very well answer incorrectly.  So verify and double check.  Part of having someone from support come in is to bring a fresh perspective that analyzes the problem from the outside and that can frequently be invaluable.

So there is no J#.....Then why is this even trying to load?

I am glad you would ask that because I have an answer.  Deep in the bowels of the ASP.NET compile engine and the Code DOM we enumerate all of the "Code Providers" and see if they are valid.  Part of this test is done by trying to load the assemblies.  So the default code providers are:

  • C#
  • VB.NET
  • JavaScript
  • J#
  • MC++

You can actually see these defaults documented in the machine.config.comments file in your %windir%\Microsoft.net\framework\v2.0.50727\config folder:

<compilers>
    <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <compiler language="js;jscript;javascript" extension=".js" type="Microsoft.JScript.JScriptCodeProvider, Microsoft.JScript, Version=8.0.1100.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <compiler language="vj#;vjs;vjsharp" extension=".jsl;.java" type="Microsoft.VJSharp.VJSharpCodeProvider, VJSharpCodeProvider, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <compiler language="c++;mc;cpp" extension=".h" type="Microsoft.VisualC.CppCodeProvider, CppCodeProvider, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</compilers>

Those are the 5 that will get searched by default and you can add additional code providers in your config file (you cannot remove from these 5 defaults ones as far as I can tell).

All of this said it would seem that every application that does a dynamic compile must be looking for this J# provider.  So I went to do a quick test.  I created a simple ASPX page that did a dynamic compile.  Before I ran the page I when to the Fusion Log Viewer (https://msdn2.microsoft.com/en-us/library/e74a18c4(VS.80).aspx).  This tool will allow me to see what happens.  I clicked "Settings..." and checked "Log Binding Failures to Disk" and exited the application.  Then I did an IIS Reset to make sure that the setting was picked up and then I browsed to my page.  After the page came up I reopen the Fusion Log Viewer and sure enough there was a bind failure for the VJSharpCodeProvider.  If you do these same steps assuming you do not have the J# runtime installed you should see the same. 

I am seeing the same failure to load the VJSharpCodeProvider but I did not any errors and the dynamic compilation did not fail.  This however is similar to what they see - It works at first and then later breaks...Reviewing briefly - We know that the VJSharpCodeProvider is not on their system but the failure to load this file is normal so why does it start becoming a problem?

Well this is where their ResolveEventHandler (https://msdn2.microsoft.com/en-us/library/system.resolveeventhandler.aspx) comes in.  We found in one event log entry where they log the callstack that a ResolveEventHanlder was on top where they subscribed to the AssemblyResolve Event - https://msdn2.microsoft.com/en-us/library/system.appdomain.assemblyresolve.aspx.  From their we began looking into the code. 

First off for some background - The AssemblyResolve Event is part of the Assembly loading that .NET does.  After it has searched for and failed to find an assembly it will raise this event.  The application can then explicitly load (typically using LoadFrom or something) the assembly and return a reference to the assembly.  This is essentially a way to redirect the application to an assembly.  Once we go the code we found that they filtered out a couple of specific exceptions and then on any that they did not have a location for they just threw a System.Exception.  Ahhhhh, that explains the nagging question about why the exception type was System.Exception and not something else.

We took a look back at the AssemblyResolve Event and the docs have a glaring oversight - What do you do when you receive a request of an assembly that you do not know where it is?  The answer turns out to be - Return Null.  I verified this internally and some in the community has been nice enough to add this note in the "Community Content" section of the docs -https://msdn2.microsoft.com/en-us/library/system.appdomain.assemblyresolve.aspx

In conclusion, when the application is first launched their code has not executed yet therefore the ResolveEventHandler has not been hooked up to the AssemblyResolve event.  However later in the run of the application when a recompile occurs and we reprobe for the VJSharpCodeProvider the exception is thrown and the ASP.NET Compile code is not expecting and exception do this leads to other errors.

Once we fixed up the handler to return NULL the application worked.  It sailed through testing and I got to go to bed!!  I hope that this helps someone else out.

Thanks,
Zach