Reputation: 3821
We use XmlSerializer
to serialize objects from a small class hierarchy, which looks like this:
Request
|- Request<T>
|- BarRequest : Request<Bar>
|- FooRequest : Request<Foo>
Request
is an abstract class which is adorned with the necessary annotations to make XmlSerializer find the subclasses:
[XmlInclude(typeof(BarRequest))]
[XmlInclude(typeof(FooRequest))]
Serializing and deserializing requests in this way works nicely in a few projects already. However, as soon as we add the XmlInclude
for FooRequest
in the current project, we get exceptions when trying to serialize BarRequest
(and probably any request object from the hierarchy). We don't even serialize any FooRequest
s yet. Adding the XmlInclude
is enough.
FooRequest
can be reduced to a fairly unassuming little class while still triggering the error:
public class FooRequest: Request<Foo>
{
protected override Foo Perform()
{
throw new NotImplementedException();
}
}
In fact, its only interesting feature is that it references Foo
, which happens to be located in the assembly FooUI
. I reduced Foo
itself to an empty public class without changing the error.
However, FooUI is already successfully loaded into my AppDomain at this point - I verified this with fuslogvw.exe:
*** Protokolleintrag für Assembly-Binder (20.04.2015 @ 16:14:06) ***
Der Vorgang wurde durchgeführt.
Ergebnis der Bindung: hr = 0x0. Der Vorgang wurde erfolgreich beendet.
Der Assemblymanager wurde geladen aus: C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
Als EXE-Datei ausgeführt. C:\Chem32\CORE\ChemMain.exe
--- Ein detailliertes Fehlerprotokoll folgt.
=== Zustandsinformationen vor Bindung ===
LOG: Benutzer = <user>
LOG: DisplayName = FooUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///C:/Chem32/CORE/
LOG: Ursprünglicher PrivatePath = NULL
LOG: DynamicBase = NULL
LOG: CacheBase = NULL
LOG: AppName = NULL
Aufruf von Assembly : FooDriver, Version=5.0.0.1245, Culture=neutral, PublicKeyToken=null.
===
LOG: Diese Bindung startet im LoadFrom-Load-Kontext.
WRN: Das systemeigene Abbild wird nicht im LoadFrom-Kontext durchsucht. Das systemeigene Abbild wird nur im Standard-Load-Kontext durchsucht, z.B. Assembly.Load().
LOG: Die Anwendungskonfigurationsdatei wird verwendet: C:\Chem32\CORE\ChemMain.exe.Config
LOG: Die Computerkonfigurationsdatei von C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config wird verwendet.
LOG: Die Richtlinie wird derzeit nicht auf den Verweis angewendet (private, benutzerdefinierte, teilweise oder pfadbasierte Assemblybindung)
LOG: Download von neuem URL file:///C:/Chem32/CORE/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/FooUI/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/Plugins/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/Plugins/FooUI/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/LCDrivers/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/LCDrivers/FooUI/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/GCDrivers/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/GCDrivers/FooUI/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/FooUI/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/Plugins/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/Plugins/FooUI/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/LCDrivers/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/LCDrivers/FooUI/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/GCDrivers/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/GCDrivers/FooUI/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/FooDriver/FooUI.DLL.
LOG: Der Assembly-Download wurde durchgeführt. Datei-Setup wird begonnen: C:\Chem32\CORE\FooDriver\FooUI.dll.
LOG: Die von der Quelle ausgeführte Setup-Phase beginnt.
LOG: Der Assemblyname ist: FooUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
LOG: Codebasis mit where-ref-Bindung stimmt nicht mit dem überein, was im Standardkontext gefunden wurde. Ergebnis im LoadFrom-Kontext behalten.
LOG: Die Bindung war erfolgreich. Assembly wird zurückgegeben von C:\Chem32\CORE\FooDriver\FooUI.dll.
LOG: Die Assembly wird im LoadFrom-Load-Kontext geladen.
At this point, I should probably note the locations of the various interesting bits:
C:\Chem32\CORE\ChemMain.exe - Main executable
C:\Chem32\CORE\FooDriver\FooDriver.dll - Plugin loaded by ChemMain.exe
C:\Chem32\CORE\FooDriver\FooUI.dll - Assembly containing class Foo
As you can see above, the assembly was found in the FooDriver subfolder and loaded correctly. However, once the program tries to serialize BarRequest, I get the following exception:
System.InvalidOperationException: Beim Generieren des XML-Dokuments ist ein Fehler aufgetreten. ---> System.IO.FileNotFoundException: Die Datei oder Assembly "FooUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.
Dateiname: "FooUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterRequest.Write27_Request(String n, String ns, Request o, Boolean isNullable, Boolean needType)
bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterRequest.Write28_Request(Object o)
=== Zustandsinformationen vor Bindung ===
LOG: Benutzer = <user>
LOG: DisplayName = FooUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///C:/Chem32/CORE/
LOG: Ursprünglicher PrivatePath = NULL
Aufruf von Assembly : (Unknown).
===
LOG: Diese Bindung startet im default-Load-Kontext.
LOG: Die Anwendungskonfigurationsdatei wird verwendet: C:\Chem32\CORE\ChemMain.exe.Config
LOG: Die Computerkonfigurationsdatei von C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config wird verwendet.
LOG: Die Richtlinie wird derzeit nicht auf den Verweis angewendet (private, benutzerdefinierte, teilweise oder pfadbasierte Assemblybindung)
LOG: Download von neuem URL file:///C:/Chem32/CORE/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/FooUI/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/Plugins/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/Plugins/FooUI/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/LCDrivers/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/LCDrivers/FooUI/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/GCDrivers/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/GCDrivers/FooUI/FooUI.DLL.
LOG: Download von neuem URL file:///C:/Chem32/CORE/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/FooUI/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/Plugins/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/Plugins/FooUI/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/LCDrivers/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/LCDrivers/FooUI/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/GCDrivers/FooUI.EXE.
LOG: Download von neuem URL file:///C:/Chem32/CORE/GCDrivers/FooUI/FooUI.EXE.
--- Ende der internen Ausnahmestapelüberwachung ---
Server stack trace:
bei System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
bei System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o)
The exception text of the InvalidOperationException
is equivalent to "There was an error generating the XML document.", and the FileNotFoundException
says "Could not load file or
assembly 'X' or one of its dependencies."
As you can see, it tries loading the same assembly that is already loaded, but doesn't attempt to look into the FooDriver subdirectory. Also interesting is that it shows the calling assembly as "(Unknown)".
Now here is a very interesting and confusing bit: If I move Foo
into a different external assembly located in the same folder, things suddenly work. I have no idea what makes this other assembly different.
Any pointers for new directions to look into are appreciated.
Upvotes: 0
Views: 887
Reputation: 2512
How are you loading your plugins? There are various load contexts in .Net. See here: https://msdn.microsoft.com/en-us/library/dd153782%28v=vs.110%29.aspx
Assemblies can be loaded into different contexts which will cause such binding resolution problems. It sounds like you are maybe doing a LoadFile in your plugin directory. Using Assembly.LoadFrom and acquiring an AssemblyName should rectify the problem.
Upvotes: 1