Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

App crashing when converting to .NET 4 (also binding for XML assembly failing)

I have a solution that I'm trying to convert to .NET 4 from .NET 2. There are multiple projects in this solution, some of which are in C# and some of which are in VB. Most of them use system.xml for XML creation and parsing.

I've re-targeted all of the projects to .NET 4, and it compiles. When I try to run, though, I almost immediately get a System.FieldAccessException, saying "If the access level of a field in a class library has changed, recompile any assemblies that reference that library.". I did recompile the entire solution before this (and tried again after, which no change).

I then used the Assembly Binding Log Viewer to see if any bindings were failing, since this was happening when it referenced a different dll in the project. And sure enough, there are failures in there. They're in two different VB projects, and they both look like this:


The operation failed. 
Bind result: hr = 0x80070002. The system cannot find the file specified.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll 
Running under executable  <path to my exe>
--- A detailed error log follows. 

=== Pre-bind state information === 
LOG: DisplayName = <projname>.XmlSerializers, Version=2013.20.0.0, Culture=neutral, PublicKeyToken=null, processorArchitecture=MSIL  (Fully-specified) 
LOG: Appbase = <projectpath> 
LOG: Initial PrivatePath = NULL 
LOG: Dynamic Base = NULL 
LOG: Cache Base = NULL 
LOG: AppName = <projname>.vshost.exe Calling assembly : System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
=== LOG: This bind starts in default load context. 
LOG: Using application configuration file: <project path\config file> 
LOG: Using host configuration file:  
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config. 
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind). 
LOG: Attempting download of new URL file:///<project path>/<projname>.XmlSerializers.DLL. 
LOG: Attempting download of new URL file:///<project path>/<projname>.XmlSerializers/CMG.XmlSerializers.DLL. 
LOG: Attempting download of new URL file:///<project path>/<projname>.XmlSerializers.EXE. 
LOG: Attempting download of new URL file:///<project path>/<projname>.XmlSerializers.EXE. 
LOG: All probing URLs attempted and failed.

Sure enough, there is no such file as any of those in my obj folder. But there wasn't before, either, and it worked fine. (Note: these binding errors are only showing up for the two VB projects that use XML, not the C# ones.) I removed and re-added the reference to system.xml, cleaned the solution, and rebuilt - still nothing.

I checked and system.xml v4 is in the GAC, and the public key is the same as what it's looking for here. I've seen references to a project option called "Generate serialization assembly" on the build tab. In the VB projects it's under Compile > Advanced options. It was set to Auto. I tried turning it on, rebuilt, and no change. I'm not sure where to look next - this was all new territory to me as it is. So where should this file be coming from, and why isn't it there, and why did it work in v2 without it? Or is all this xml stuff a red herring and nothing to do with the original issue? I'm starting to fear that, but can't be sure either way just yet. Any guidance would be highly appreciated.

ETA: If I run this outside of VS, the error log is showing the crash as an event 1000, with "Faulting module name: kernelbase.dll". The searching I've done so far on this indicates an issue with 32-bit apps running on 64-bit OSs, but I already have the entire thing set to compile as Any CPU. Turns out I'm also seeing the same binding errors when I run the .NET 2 version, even though it runs fine there. I'm starting to think more and more that the XML thing is a red herring.

Further ETA: XML thing was indeed a red herring. Added solution as an answer below.

like image 498
teleute00 Avatar asked Aug 09 '13 21:08

teleute00


1 Answers

So it was the security after all. As per http://msdn.microsoft.com/en-us/library/stfy7tfc.aspx:

A member is security-critical if it has the SecurityCriticalAttribute, if it belongs to a type that has the SecurityCriticalAttribute, or if it is in a security-critical assembly. Beginning with the .NET Framework 4, the rules for accessing security-critical members are as follows:

Transparent code cannot use reflection to access security-critical members, even if the code is fully trusted. A MethodAccessException, FieldAccessException, or TypeAccessException is thrown.

Code that is running with partial trust is treated as transparent.

Reading further, I found that with this change in .NET 4, they actually introduced 2 levels for these rules - level 2 is these new rules, and level 1 is the .NET 2 rules, for backwards compatibility. I set the assembly that was not accessible to use the level 1 rules, by adding:

<Assembly: System.Security.SecurityRules(System.Security.SecurityRuleSet.Level1)> 

To the AssemblyInfo.vb file (and adding system.security as a reference). Everything now works fine. Obviously, the ideal will be to change it to use level 2 rules, but that's down the road. This at least not only fixes the problem for the time being, but tells me exactly what the problem is. Thanks, everyone!

like image 179
teleute00 Avatar answered Nov 15 '22 06:11

teleute00