I'm getting a FileLoadException when attempting to deserialize a type using the NetDataContractSerializer:
The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)
This error does not have to do with the serializer specifically; attempting to load a type at runtime by its Assembly Qualified Name results in the same failure.
I've attached a listener to the AssemblyResolve event to see what's happening:
ResolveEventHandler reh = (o, e) =>
{
var tryGet = AppDomain.CurrentDomain.GetAssemblies()
.Where(x => x.FullName == e.Name).FirstOrDefault();
if (tryGet != null)
return tryGet;
//EDIT: Crap, the following line is a stupid bug STUPID! Ignore!
return Type.GetType(e.Name).Assembly;
};
using (var stream = System.IO.File.OpenRead(serializedObjectFilename))
{
try
{
AppDomain.CurrentDomain.AssemblyResolve += reh;
var ser = new NetDataContractSerializer();
return ser.Deserialize(stream) as MyType;
}
finally
{
AppDomain.CurrentDomain.AssemblyResolve -= reh;
}
}
The titular "odd behavior" can be seen by debugging through the handler. While tryGet
is never null
(the required assembly, in this case, is always loaded into the AppDomain), the operation always fails if left to itself. In other words, calling Edit: I was conflating the strong name of the assembly with the assembly qualified name of a type; please ignore that bug. Ironically, it doesn't throw a different error, so I didn't catch this before asking this question.Type.GetType(e.Name).Assembly
would result in the FileLoadException being thrown.
Another bit of information: Assembly.Load(e.Name)
always returns the valid assembly. I'm not sure why that works whereas the method used behind the scenes during deserialization fails.
Fusion Log reports that the loader is attempting to load the correct assembly, but since the assembly isn't found within the private path of the executable, it fails.
Why is the attempt to load the assembly being made when the assembly is already loaded in the AppDomain??
More details on fusion logging...
I've captured all assembly loading before and during the method call that causes the exception to be thrown. Here are the relevant logs, in order of creation:
AFAICT, Visual Studio loads the assembly into the solution's AppDomain (ffs I wish Fusion Log captured the AppDomain where the load was attempted; it records the calling assembly, after all).
After this point, I make my deserialization call. The result is a single log in Fusion:
Bind result: hr = 0x80070002. The system cannot find the file specified.
Again, Fusion is attempting to load from the executable's application base by its strong name. One good thing; it attempts to load from the GAC, so once deployed I may not have the same issue. But I'm still clueless as to why the assembly cannot be located in the appdomain.
Further interesting stuff...
This throws on the call to Deserialize:
MyType test = new MyType ();
var serialized = Serializer.ToXml(test);
// the following line fails with a FileLoadException
var deserialized = Serializer.FromXml<MyType>(serialized);
where ToXml and FromXml both use the NetDataContractSerializer and Write/ReadObject. The assembly is loaded early in execution from the package's installation directory, but the NDCS, for some reason, doesn't want to use the assembly as it is found in the AppDomain. This test shows that it can't be an issue with versioning.
One thing I find odd in your code is that here:
GetAssemblies().Where(x => x.FullName == e.Name)
e
is used as the name of an assembly, since it would match Assembly.Name
, so would not have the name of a class/type in it, then here:
return Type.GetType(e.Name).Assembly;
e
is used as a fully assembly qualified type name, which I would think would contain both the class/type name plus the assembly name.
Is this intentional?
Edit:
Sorry, I posted this reply just as you edited your post and caught the mistake yourself...
User contributions licensed under CC BY-SA 3.0