FileNotFoundException in ApplicationSettingsBase - c#

When debugging an application I always get the following error when break on exception is enabled in Visual Studio. This is really bugging me, since we work with break on exception. The funny thing is, that it still works when I continue (the StringCollection is loaded).
The Message is:
Could not load file or assembly 'System.XmlSerializers,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or
one of its dependencies. The system cannot find the file specified.
Here is the code that is causing the exception (designer generated)
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.Collections.Specialized.StringCollection Mru {
get {
return ((global::System.Collections.Specialized.StringCollection)(this["Mru"]));
}
set {
this["Mru"] = value;
}
}
I tried to create an empty test application that shows the error, but the exception didn't occur. Our project is huge so it tough to find the cause. Maybe someone on this site has a clue how to solve this.

Just an explanation for why this exception is thrown. You can repro the exception with this sample Windows Forms app. Start by adding a setting named "Setting" of type StringCollection. Click the dots in the Value column and enter a couple of strings. Make the form class code look like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected override void OnFormClosing(FormClosingEventArgs e) {
Properties.Settings.Default.Setting[0] = DateTime.Now.ToString();
Properties.Settings.Default.Save();
base.OnFormClosing(e);
}
}
Debug + Exceptions, tick the Thrown checkbox for CLR exceptions. Run the form and close it, the debugger will stop when the exception is thrown. The top of the call stack looks like this:
mscorlib.dll!System.Reflection.Assembly.nLoad(System.Reflection.AssemblyName fileName, string codeBase, System.Security.Policy.Evidence assemblySecurity, System.Reflection.Assembly locationHint, ref System.Threading.StackCrawlMark stackMark, bool throwOnFileNotFound, bool forIntrospection) + 0x2c bytes
mscorlib.dll!System.Reflection.Assembly.InternalLoad(System.Reflection.AssemblyName assemblyRef, System.Security.Policy.Evidence assemblySecurity, ref System.Threading.StackCrawlMark stackMark, bool forIntrospection) + 0x80 bytes
mscorlib.dll!System.Reflection.Assembly.Load(System.Reflection.AssemblyName assemblyRef) + 0x1d bytes
System.Xml.dll!System.Xml.Serialization.TempAssembly.LoadGeneratedAssembly(System.Type type = {Name = "StringCollection" FullName = "System.Collections.Specialized.StringCollection"}, string defaultNamespace = null, out System.Xml.Serialization.XmlSerializerImplementation contract = null) + 0xcd bytes
System.Xml.dll!System.Xml.Serialization.XmlSerializer.XmlSerializer(System.Type type = {Name = "StringCollection" FullName = "System.Collections.Specialized.StringCollection"}, string defaultNamespace = null) + 0x105 bytes
You can see the XmlSerializer class hunting for an assembly that contains the XML serializer for the StringCollection class. The LoadGeneratedAssembly method looks like this with the boring bits removed:
internal static Assembly LoadGeneratedAssembly(Type type, string defaultNamespace, out XmlSerializerImplementation contract)
{
...
AssemblyName parent = GetName(type.Assembly, true);
partialName = Compiler.GetTempAssemblyName(parent, defaultNamespace);
parent.Name = partialName;
parent.CodeBase = null;
parent.CultureInfo = CultureInfo.InvariantCulture;
try
{
serializer = Assembly.Load(parent); // <=== here
}
catch (Exception exception)
{
...
}
....
}
And Compiler.GetTempAssemblyName():
internal static string GetTempAssemblyName(AssemblyName parent, string ns)
{
return (parent.Name + ".XmlSerializers" + (((ns == null) || (ns.Length == 0)) ? "" : ("." + ns.GetHashCode())));
}
This GetTempAssemblyName is the evil-doer in this case. The StringCollection class lives in the System.dll assembly, the method generates the name "System.XmlSerializers". This method is designed to find the assembly for your own classes, the one generated by Sgen.exe. Like WindowsApplication1.XmlSerializers.dll for your sample program. But StringCollection is a class in the .NET Framework, the assembly name it generates just isn't valid. There isn't actually a "System.XmlSerializers.dll" assembly in the framework.
Feedback reports about this behavior at connect.microsoft.com have all been closed with "By Design". It was, the original designers considered the cost of preventing the exception too high and decided to just catch the exception. Which all works fine, the exception is indeed caught. You just happen to see it because you got the Thrown checkbox turned on in the Debug + Exceptions dialog.
Making the Xml serialization code behave differently here is not an option. It would have been easy enough for them to simply filter out types in the System.dll assembly, but that's a potentially never-ending battle, there are a lot more assemblies in the framework. A workaround is to use your own class to store the setting instead of using a StringCollection.

As this really seems to be part of the normal operation (see also:
XmlSerializer giving FileNotFoundException at constructor), I can only offer two workarounds:
Disable this specific exception: goto Debug/Exceptions, click Add, Type: C++ Exceptions, Name: EEFileLoadException (if this is the exception you're seeing), uncheck the Thrown checkbox for this exception.
Change the type of the setting to string and access it e.g. like so:
var mru = Settings.Default.Mru.Split('|');
Settings.Default.Mru = string.Join("|", mru.ToArray());

You are catching too many exceptions, the System.XmlSerializer will always throw this exception as part of it's normal operation, it is caught and handled by the class itself. Change your debugging options to only catch your exceptions, not exceptions that are caught and handled within the .net farmework classes.

Related

VS2019, C#, "just-my-code", and DLLs that aren't real [duplicate]

When debugging an application I always get the following error when break on exception is enabled in Visual Studio. This is really bugging me, since we work with break on exception. The funny thing is, that it still works when I continue (the StringCollection is loaded).
The Message is:
Could not load file or assembly 'System.XmlSerializers,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or
one of its dependencies. The system cannot find the file specified.
Here is the code that is causing the exception (designer generated)
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.Collections.Specialized.StringCollection Mru {
get {
return ((global::System.Collections.Specialized.StringCollection)(this["Mru"]));
}
set {
this["Mru"] = value;
}
}
I tried to create an empty test application that shows the error, but the exception didn't occur. Our project is huge so it tough to find the cause. Maybe someone on this site has a clue how to solve this.
Just an explanation for why this exception is thrown. You can repro the exception with this sample Windows Forms app. Start by adding a setting named "Setting" of type StringCollection. Click the dots in the Value column and enter a couple of strings. Make the form class code look like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected override void OnFormClosing(FormClosingEventArgs e) {
Properties.Settings.Default.Setting[0] = DateTime.Now.ToString();
Properties.Settings.Default.Save();
base.OnFormClosing(e);
}
}
Debug + Exceptions, tick the Thrown checkbox for CLR exceptions. Run the form and close it, the debugger will stop when the exception is thrown. The top of the call stack looks like this:
mscorlib.dll!System.Reflection.Assembly.nLoad(System.Reflection.AssemblyName fileName, string codeBase, System.Security.Policy.Evidence assemblySecurity, System.Reflection.Assembly locationHint, ref System.Threading.StackCrawlMark stackMark, bool throwOnFileNotFound, bool forIntrospection) + 0x2c bytes
mscorlib.dll!System.Reflection.Assembly.InternalLoad(System.Reflection.AssemblyName assemblyRef, System.Security.Policy.Evidence assemblySecurity, ref System.Threading.StackCrawlMark stackMark, bool forIntrospection) + 0x80 bytes
mscorlib.dll!System.Reflection.Assembly.Load(System.Reflection.AssemblyName assemblyRef) + 0x1d bytes
System.Xml.dll!System.Xml.Serialization.TempAssembly.LoadGeneratedAssembly(System.Type type = {Name = "StringCollection" FullName = "System.Collections.Specialized.StringCollection"}, string defaultNamespace = null, out System.Xml.Serialization.XmlSerializerImplementation contract = null) + 0xcd bytes
System.Xml.dll!System.Xml.Serialization.XmlSerializer.XmlSerializer(System.Type type = {Name = "StringCollection" FullName = "System.Collections.Specialized.StringCollection"}, string defaultNamespace = null) + 0x105 bytes
You can see the XmlSerializer class hunting for an assembly that contains the XML serializer for the StringCollection class. The LoadGeneratedAssembly method looks like this with the boring bits removed:
internal static Assembly LoadGeneratedAssembly(Type type, string defaultNamespace, out XmlSerializerImplementation contract)
{
...
AssemblyName parent = GetName(type.Assembly, true);
partialName = Compiler.GetTempAssemblyName(parent, defaultNamespace);
parent.Name = partialName;
parent.CodeBase = null;
parent.CultureInfo = CultureInfo.InvariantCulture;
try
{
serializer = Assembly.Load(parent); // <=== here
}
catch (Exception exception)
{
...
}
....
}
And Compiler.GetTempAssemblyName():
internal static string GetTempAssemblyName(AssemblyName parent, string ns)
{
return (parent.Name + ".XmlSerializers" + (((ns == null) || (ns.Length == 0)) ? "" : ("." + ns.GetHashCode())));
}
This GetTempAssemblyName is the evil-doer in this case. The StringCollection class lives in the System.dll assembly, the method generates the name "System.XmlSerializers". This method is designed to find the assembly for your own classes, the one generated by Sgen.exe. Like WindowsApplication1.XmlSerializers.dll for your sample program. But StringCollection is a class in the .NET Framework, the assembly name it generates just isn't valid. There isn't actually a "System.XmlSerializers.dll" assembly in the framework.
Feedback reports about this behavior at connect.microsoft.com have all been closed with "By Design". It was, the original designers considered the cost of preventing the exception too high and decided to just catch the exception. Which all works fine, the exception is indeed caught. You just happen to see it because you got the Thrown checkbox turned on in the Debug + Exceptions dialog.
Making the Xml serialization code behave differently here is not an option. It would have been easy enough for them to simply filter out types in the System.dll assembly, but that's a potentially never-ending battle, there are a lot more assemblies in the framework. A workaround is to use your own class to store the setting instead of using a StringCollection.
As this really seems to be part of the normal operation (see also:
XmlSerializer giving FileNotFoundException at constructor), I can only offer two workarounds:
Disable this specific exception: goto Debug/Exceptions, click Add, Type: C++ Exceptions, Name: EEFileLoadException (if this is the exception you're seeing), uncheck the Thrown checkbox for this exception.
Change the type of the setting to string and access it e.g. like so:
var mru = Settings.Default.Mru.Split('|');
Settings.Default.Mru = string.Join("|", mru.ToArray());
You are catching too many exceptions, the System.XmlSerializer will always throw this exception as part of it's normal operation, it is caught and handled by the class itself. Change your debugging options to only catch your exceptions, not exceptions that are caught and handled within the .net farmework classes.

Cross-AppDomain call corrupts the runtime

This was originally a much more lengthy question, but now I have constructed a smaller usable example code, so the original text is no longer relevant.
I have two projects, one containing a single struct with no members, named TestType. This project is referenced by the main project, but the assembly is not included in the executable directory. The main project creates a new app-domain, where it registers the AssemblyResolve event with the name of the included assembly. In the main app-domain, the same event is handled, but it loads the assembly from the project resources, manually.
The new app-domain then constructs its own version of TestType, but with more fields than the original one. The main app-domain uses the dummy version, and the new app-domain uses the generated version.
When calling methods that have TestType in their signature (even simply returning it is sufficient), it appears that it simply destabilizes the runtime and corrupts the memory.
I am using .NET 4.5, running under x86.
DummyAssembly:
using System;
[Serializable]
public struct TestType
{
}
Main project:
using System;
using System.Reflection;
using System.Reflection.Emit;
internal sealed class Program
{
[STAThread]
private static void Main(string[] args)
{
Assembly assemblyCache = null;
AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs rargs)
{
var name = new AssemblyName(rargs.Name);
if(name.Name == "DummyAssembly")
{
return assemblyCache ?? (assemblyCache = TypeSupport.LoadDummyAssembly(name.Name));
}
return null;
};
Start();
}
private static void Start()
{
var server = ServerObject.Create();
//prints 155680
server.TestMethod1("Test");
//prints 0
server.TestMethod2("Test");
}
}
public class ServerObject : MarshalByRefObject
{
public static ServerObject Create()
{
var domain = AppDomain.CreateDomain("TestDomain");
var t = typeof(ServerObject);
return (ServerObject)domain.CreateInstanceAndUnwrap(t.Assembly.FullName, t.FullName);
}
public ServerObject()
{
Assembly genAsm = TypeSupport.GenerateDynamicAssembly("DummyAssembly");
AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs rargs)
{
var name = new AssemblyName(rargs.Name);
if(name.Name == "DummyAssembly")
{
return genAsm;
}
return null;
};
}
public TestType TestMethod1(string v)
{
Console.WriteLine(v.Length);
return default(TestType);
}
public void TestMethod2(string v)
{
Console.WriteLine(v.Length);
}
}
public static class TypeSupport
{
public static Assembly LoadDummyAssembly(string name)
{
var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
if(stream != null)
{
var data = new byte[stream.Length];
stream.Read(data, 0, data.Length);
return Assembly.Load(data);
}
return null;
}
public static Assembly GenerateDynamicAssembly(string name)
{
var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName(name), AssemblyBuilderAccess.Run
);
var mod = ab.DefineDynamicModule(name+".dll");
var tb = GenerateTestType(mod);
tb.CreateType();
return ab;
}
private static TypeBuilder GenerateTestType(ModuleBuilder mod)
{
var tb = mod.DefineType("TestType", TypeAttributes.Public | TypeAttributes.Serializable, typeof(ValueType));
for(int i = 0; i < 3; i++)
{
tb.DefineField("_"+i.ToString(), typeof(int), FieldAttributes.Public);
}
return tb;
}
}
While both TestMethod1 and TestMethod2 should print 4, the first one accesses some weird parts of the memory, and seems to corrupt the call stack well enough to influence the call to the second method. If I remove the call to the first method, everything is fine.
If I run the code under x64, the first method throws NullReferenceException.
The amount of fields of both structs seems to be important. If the second struct is larger in total than the first one (if I generate only one field or none), everything also works fine, same if the struct in DummyAssembly contains more fields. This leads me to believe that the JITter either incorrectly compiles the method (not using the generated assembly), or that the incorrect native version of the method gets called. I have checked that typeof(TestType) returns the correct (generated) version of the type.
All in all, I am not using any unsafe code, so this shouldn't happen.
I was able to reproduce this problem on my machine with newest framework.
I've added check for the version in default appdomain's assembly resolve:
if (name.Name == "DummyAssembly" && name.Version.Major == 1)
And I got following exception:
System.Runtime.Serialization.SerializationException: Cannot find assembly 'DummyAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
Server stack trace:
w System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
w System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name)
w System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, String[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, Object[] typeInformationA, Int32[] memberAssemIds, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo, SizedArray assemIdToAssemblyTable)
w System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record)
w System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum)
w System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
w System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
w System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
w System.Runtime.Remoting.Channels.CrossAppDomainSerializer.DeserializeObject(MemoryStream stm)
w System.Runtime.Remoting.Messaging.SmuggledMethodReturnMessage.FixupForNewAppDomain()
w System.Runtime.Remoting.Channels.CrossAppDomainSink.SyncProcessMessage(IMessage reqMsg)
Exception rethrown at [0]:
w System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
w System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
w ServerObject.TestMethod1(TestType& result, String v)
Binary formatter is used for Marshaling here, and it finds value types of different sizes from different AppDomains. Note that it tries to load your DummyAssembly with version 0.0.0.0 when you call TestMethod1, and you pass it the dummy version 1.0.0.0 you cached earliesr, where TestType has different size.
Because of different sizes of structs, when you return by value from your method, something goes wrong with marshaling between AppDomains and stack gets unbalanced (probably a bug in the runtime?). Returning by reference seems to work without issues (size of reference is always the same).
Making structs equal in size in both assemblies / returning by reference should work around this issue.

Untrappable COMException with GetRefTypeInfo

I have a function whose role is to return the name of a COM type; it works fine on x64, but crashes in the middle of iterating the COM types in the Excel type library (and MS-Project too, ..and probably other ones I'm not aware of), and I can't seem to be able to do anything to catch the exception it's throwing.
System.Reflection.TargetInvocationException was unhandled
Message: An unhandled exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll
Additional information: Exception has been thrown by the target of an invocation.
This results in an AccessViolationException, which results in sudden death for the EXCEL.EXE host process.
I was able to add some debug output and identify exactly which member was blowing up:
Querying AsTypeName for member SheetPivotTableBeforeDiscardChanges
Member EXCEL.EXE;Excel.IAppEvents.SheetPivotTableBeforeDiscardChanges
(Object) added successfully
Querying AsTypeName for parameter Sh
Parameter EXCEL.EXE;Excel.IAppEvents.Sh (Object) added successfully
Querying AsTypeName for parameter TargetPivotTable
When the Excel type library starts loading, the entire VBA type library has successfully loaded. If I run my process in a MS-Word host, everything runs fine, so it looks like there's something about the type of the TargetPivotTable parameter of IAppEvents.SheetPivotTableBeforeDiscardChanges that doesn't like what I've written to query it.
case VarEnum.VT_USERDEFINED:
int href;
unchecked
{
if (Marshal.SizeOf(typeof (IntPtr)) == sizeof (long))
{
href = (int) desc.lpValue.ToInt64();
}
else
{
href = desc.lpValue.ToInt32();
}
}
ITypeInfo refTypeInfo;
info.GetRefTypeInfo(href, out refTypeInfo); // <~ boom
return GetTypeName(refTypeInfo);
Here's the relevant part of the stack trace a contributor was able to get from a MS-Project host:
System.Runtime.InteropServices.COMException (0x80004005): Error HRESULT E_FAIL has been returned from a call to a COM component.
at System.Runtime.InteropServices.ComTypes.ITypeInfo.GetRefTypeInfo(Int32 hRef, ITypeInfo& ppTI)
at Rubberduck.Parsing.Symbols.ReferencedDeclarationsCollector.GetTypeName(TYPEDESC desc, ITypeInfo info) in c:\Users\Andrew\Documents\GitHub\Rubberduck\Rubberduck.Parsing\Symbols\ReferencedDeclarationsCollector.cs:line 95
at Rubberduck.Parsing.Symbols.ReferencedDeclarationsCollector.GetTypeName(TYPEDESC desc, ITypeInfo info) in c:\Users\Andrew\Documents\GitHub\Rubberduck\Rubberduck.Parsing\Symbols\ReferencedDeclarationsCollector.cs:line 89
at Rubberduck.Parsing.Symbols.ReferencedDeclarationsCollector.CreateFieldDeclaration(ITypeInfo info, Int32 fieldIndex, DeclarationType typeDeclarationType, QualifiedModuleName typeQualifiedModuleName, Declaration moduleDeclaration)
The code gets a VT_PTR, so it gets a TYPEDESC out of that pointer (line 89), and then recurses; the same code then gets a VT_USERDEFINED, so it gets an ITypeInfo out of the lpValue of the TYPEDESC (line 95), and normally I get that ITypeInfo and fetch the type's name. For some reason in a 32-bit context GetRefTypeInfo refuses to cooperate and sends everything into flames.
For full context, here's the entire relevant code:
private string GetTypeName(TYPEDESC desc, ITypeInfo info)
{
var vt = (VarEnum)desc.vt;
TYPEDESC tdesc;
switch (vt)
{
case VarEnum.VT_PTR:
tdesc = (TYPEDESC)Marshal.PtrToStructure(desc.lpValue, typeof(TYPEDESC));
return GetTypeName(tdesc, info);
case VarEnum.VT_USERDEFINED:
int href;
unchecked
{
if (Marshal.SizeOf(typeof (IntPtr)) == sizeof (long))
{
href = (int) desc.lpValue.ToInt64();
}
else
{
href = desc.lpValue.ToInt32();
}
}
ITypeInfo refTypeInfo;
info.GetRefTypeInfo(href, out refTypeInfo);
return GetTypeName(refTypeInfo);
case VarEnum.VT_CARRAY:
tdesc = (TYPEDESC)Marshal.PtrToStructure(desc.lpValue, typeof(TYPEDESC));
return GetTypeName(tdesc, info) + "()";
default:
string result;
if (TypeNames.TryGetValue(vt, out result))
{
return result;
}
break;
}
return "Object";
}
private string GetTypeName(ITypeInfo info)
{
string typeName;
string docString; // todo: put the docString to good use?
int helpContext;
string helpFile;
info.GetDocumentation(-1, out typeName, out docString, out helpContext, out helpFile);
return typeName;
}
Is there anything in that switch block that looks like it's waiting to blow up in a 32-bit context?

MyAssembly.XmlSerializers.dll cannot be loaded while debugging (FileNotFound) [duplicate]

When debugging an application I always get the following error when break on exception is enabled in Visual Studio. This is really bugging me, since we work with break on exception. The funny thing is, that it still works when I continue (the StringCollection is loaded).
The Message is:
Could not load file or assembly 'System.XmlSerializers,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or
one of its dependencies. The system cannot find the file specified.
Here is the code that is causing the exception (designer generated)
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.Collections.Specialized.StringCollection Mru {
get {
return ((global::System.Collections.Specialized.StringCollection)(this["Mru"]));
}
set {
this["Mru"] = value;
}
}
I tried to create an empty test application that shows the error, but the exception didn't occur. Our project is huge so it tough to find the cause. Maybe someone on this site has a clue how to solve this.
Just an explanation for why this exception is thrown. You can repro the exception with this sample Windows Forms app. Start by adding a setting named "Setting" of type StringCollection. Click the dots in the Value column and enter a couple of strings. Make the form class code look like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected override void OnFormClosing(FormClosingEventArgs e) {
Properties.Settings.Default.Setting[0] = DateTime.Now.ToString();
Properties.Settings.Default.Save();
base.OnFormClosing(e);
}
}
Debug + Exceptions, tick the Thrown checkbox for CLR exceptions. Run the form and close it, the debugger will stop when the exception is thrown. The top of the call stack looks like this:
mscorlib.dll!System.Reflection.Assembly.nLoad(System.Reflection.AssemblyName fileName, string codeBase, System.Security.Policy.Evidence assemblySecurity, System.Reflection.Assembly locationHint, ref System.Threading.StackCrawlMark stackMark, bool throwOnFileNotFound, bool forIntrospection) + 0x2c bytes
mscorlib.dll!System.Reflection.Assembly.InternalLoad(System.Reflection.AssemblyName assemblyRef, System.Security.Policy.Evidence assemblySecurity, ref System.Threading.StackCrawlMark stackMark, bool forIntrospection) + 0x80 bytes
mscorlib.dll!System.Reflection.Assembly.Load(System.Reflection.AssemblyName assemblyRef) + 0x1d bytes
System.Xml.dll!System.Xml.Serialization.TempAssembly.LoadGeneratedAssembly(System.Type type = {Name = "StringCollection" FullName = "System.Collections.Specialized.StringCollection"}, string defaultNamespace = null, out System.Xml.Serialization.XmlSerializerImplementation contract = null) + 0xcd bytes
System.Xml.dll!System.Xml.Serialization.XmlSerializer.XmlSerializer(System.Type type = {Name = "StringCollection" FullName = "System.Collections.Specialized.StringCollection"}, string defaultNamespace = null) + 0x105 bytes
You can see the XmlSerializer class hunting for an assembly that contains the XML serializer for the StringCollection class. The LoadGeneratedAssembly method looks like this with the boring bits removed:
internal static Assembly LoadGeneratedAssembly(Type type, string defaultNamespace, out XmlSerializerImplementation contract)
{
...
AssemblyName parent = GetName(type.Assembly, true);
partialName = Compiler.GetTempAssemblyName(parent, defaultNamespace);
parent.Name = partialName;
parent.CodeBase = null;
parent.CultureInfo = CultureInfo.InvariantCulture;
try
{
serializer = Assembly.Load(parent); // <=== here
}
catch (Exception exception)
{
...
}
....
}
And Compiler.GetTempAssemblyName():
internal static string GetTempAssemblyName(AssemblyName parent, string ns)
{
return (parent.Name + ".XmlSerializers" + (((ns == null) || (ns.Length == 0)) ? "" : ("." + ns.GetHashCode())));
}
This GetTempAssemblyName is the evil-doer in this case. The StringCollection class lives in the System.dll assembly, the method generates the name "System.XmlSerializers". This method is designed to find the assembly for your own classes, the one generated by Sgen.exe. Like WindowsApplication1.XmlSerializers.dll for your sample program. But StringCollection is a class in the .NET Framework, the assembly name it generates just isn't valid. There isn't actually a "System.XmlSerializers.dll" assembly in the framework.
Feedback reports about this behavior at connect.microsoft.com have all been closed with "By Design". It was, the original designers considered the cost of preventing the exception too high and decided to just catch the exception. Which all works fine, the exception is indeed caught. You just happen to see it because you got the Thrown checkbox turned on in the Debug + Exceptions dialog.
Making the Xml serialization code behave differently here is not an option. It would have been easy enough for them to simply filter out types in the System.dll assembly, but that's a potentially never-ending battle, there are a lot more assemblies in the framework. A workaround is to use your own class to store the setting instead of using a StringCollection.
As this really seems to be part of the normal operation (see also:
XmlSerializer giving FileNotFoundException at constructor), I can only offer two workarounds:
Disable this specific exception: goto Debug/Exceptions, click Add, Type: C++ Exceptions, Name: EEFileLoadException (if this is the exception you're seeing), uncheck the Thrown checkbox for this exception.
Change the type of the setting to string and access it e.g. like so:
var mru = Settings.Default.Mru.Split('|');
Settings.Default.Mru = string.Join("|", mru.ToArray());
You are catching too many exceptions, the System.XmlSerializer will always throw this exception as part of it's normal operation, it is caught and handled by the class itself. Change your debugging options to only catch your exceptions, not exceptions that are caught and handled within the .net farmework classes.

Why return BAD IL FORMAT to load assembly from wcf service?

I want to load this Class library :
namespace ClassLibrary1
{
public class Class1
{
public Class1()
{
}
public static int Sum(int a, int b)
{
return a + b;
}
}
}
I have a wcf service which returns to me a byte[] array (ClassLibrary1) i can not load this assembly
static void Main(string[] args)
{
FileTransferService.ApplicationHostServiceClient client = new FileTransferService.ApplicationHostServiceClient();
FileTransferService.AssemblyPackage[] asmbs = client.GetFile();
//var newDomain = AppDomain.CreateDomain("FooBar", null, null);
foreach (FileTransferService.AssemblyPackage item in asmbs)
{
byte[] mybuffer = item.Buffer;
new AssemblyLoader().LoadAndCall(mybuffer);
}
}
public class AssemblyLoader : MarshalByRefObject
{
public void LoadAndCall(byte[] binary)
{
Assembly loadedAssembly = AppDomain.CurrentDomain.Load(binary);
object[] tt = { 3, 6 };
Type typ = loadedAssembly.GetType("ClassLibrary1.Class1");
MethodInfo minfo = typ.GetMethod("Sum", BindingFlags.Public);
int x = (int)minfo.Invoke(null, tt);
Console.WriteLine(x);
}
}
Error return to me in this method : Assembly loadedAssembly = AppDomain.CurrentDomain.Load(binary);
ERROR:
BADIMAGEFORMAT EXCEPTION
Could not load file or assembly '4096 bytes loaded from Client2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An attempt was made to load a program with an incorrect format.
EXCEPTION :
Bad IL format
i have googling this kind of error but no exact solution. i want to load my assembly using AppDomain.
The first thing to check in this scenario is that the byte[] you received is exactly identical to the original, as there are many ways of making a mess of handing a chunk of binary. Perhaps write the file to disk (File.WriteAllBytes) and your favourite file compare tool, or use something like base-64 or a sha-1 hash to validate the contents. I strongly suspect you'll find it isn't the same.
Since this is one of the first results when googling Bad IL format I thought I'd explain what that means.
BadImageFormatException is thrown when the Intermediate Language of the assembly is invalid. In the case of this question it was due to WCF truncating it, in my case a .Net Framework dll was corrupted by a failing harddrive.
So in general the problem will exist at the byte level, for this problem in general I'd debug it with these steps:
Recompile everything possible
Run sfc on the system
Run chkdsk
Compare the byte streams of assemblies (do this first if you're loading an assembly from a byte stream)

Categories