Hallo zuammen,
Jetzt ist es soweit und ich muss mich hilfesuchend an euch wenden. Bisher konnte ich alle Probleme über dieses Forum und Google suchen lösen, aber bei dem hier beiß ich mir gerade die Zähne aus.
Ich habe ein Programm entwickelt das Plugins in Form von DLL-Dateien nutz. Die Plugins führen verschiedene Berechnungen durch und benötigen Parameter für genauere Einstellungen. Jedes Plugin verfügt über eine Klasse die die die einzelnen Parameter enthält, da sie von Plugin zu Plugin unterschiedlich sein können.
Da ich die Einstellungen speichern will um sie später wieder zuverwenden, speicher ich diese im Programm als Object. Wenn ich die Parameter später brauche, caste ich sie dann direkt im Plugin zurück.
Das Serialisieren klappt soweit ohne Probleme. Was mir jetzt allerdings Kopfzerbrechen bereitet, ist das ich beim Deserialisieren eine Fehlermeldung bekomme:
Datei konnte nicht geladen werden.
Die Assembly Delta, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null kann nicht gefunden werden.
(Delta ist hier der Namespace des Plugins)
Kann es sein, das er beim Deserialisieren erst versucht das Objekt in die entsprechende Klasse zu casten und es erst danach in Object steckt? Wenn das so ist, wie könnte man das umgehen?
Ich hoffe ich konnte mein Problem verständlich erläutern.
EDIT: Sorry ganz vergessen das hier zu posten:
private void ofd_ProjektOeffnen_FileOk(object sender, CancelEventArgs e)
{
BinaryFormatter bf = new BinaryFormatter();
FileStream fsGlobVar = new FileStream(ofd_ProjektOeffnen.FileName, FileMode.Open, FileAccess.Read);
try
{
globVar = (GlobalClass)bf.Deserialize(fsGlobVar); // Hier kommt die Exception
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Datei konnte nicht geladen werden.");
}
finally
{
fsGlobVar.Close();
}
}
[...]
EDIT2: Man bin ich vergesslich, hier noch kurz wie die GlobalClass in etwa aufgebaut ist:
[Serializable]
public class GlobalClass
{
// [...] viele Variablen, konnte den Fehler bei denen aber ausschließen
private List<PluginVar> pluginVarList = new List<PluginVar>(); // in PluginVar befindet sich das Objekt
// [...] Methoden usw.
}
[Serializable]
public class PluginVar
{
// [...] noch ein paar andere Variablen die ich aber auch ausschließen konnte
private Object pluginParameter; // Die Parameter als Object
// [...] Methoden usw.
}
Und hier noch ein Beispiel für die Klasse mit den Parametern
[Serializable]
public class DeltaOptions
{
private string resultTableName = "";
private int columnTableOne = 0;
private int columnTableTwo = 0;
private int deltaOption = 0;
public string ResultTableName { get { return this.resultTableName; } set { this.resultTableName = value; } }
public int ColumnTableOne { get { return this.columnTableOne; } set { this.columnTableOne = value; } }
public int ColumnTableTwo { get { return this.columnTableTwo; } set { this.columnTableTwo = value; } }
public int DeltaOption { get { return this.deltaOption; } set { this.deltaOption = value; } }
public DeltaOptions()
{ }
}
So, ich hoffe ich hab jetzt nicht noch etwas vergessen.
Schau mal ob Dich das hier weiterbringt:
http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/e5f0c371-b900-41d8-9a5b-1052739f2521/ (Deserialize - unable to find an Assembly .....)
Btw.: "Unbekannt" und deserialisieren passt nicht.
Ihr seid mal wieder die Besten 😃
Dank der Links konnte ich das Problem jetzt lösen.
Hier kurz wie das Problem gelöst werden konnte:
public class Binder : System.Runtime.Serialization.SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type tyType = null;
string sShortAssemblyName = assemblyName.Split(',')[0];
System.Reflection.Assembly[] ayAssemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (System.Reflection.Assembly ayAssembly in ayAssemblies)
{
if (sShortAssemblyName == ayAssembly.FullName.Split(',')[0])
{
tyType = ayAssembly.GetType(typeName);
break;
}
}
return tyType;
}
}
und
private void ofd_ProjektOeffnen_FileOk(object sender, CancelEventArgs e)
{
BinaryFormatter bf = new BinaryFormatter();
// Die Lösung des Problems
bf.Binder = new Binder(); // Die obrige Klasse verwenden
Global.Plugins.FindPlugins(@"\Plugins\"); // Alle Plugins Laden
FileStream fsGlobVar = new FileStream(ofd_ProjektOeffnen.FileName, FileMode.Open, FileAccess.Read);
try
{
globVar = (GlobalClass)bf.Deserialize(fsGlobVar); // Hier kommt die Exception
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Datei konnte nicht geladen werden.");
}
finally
{
fsGlobVar.Close();
}
}
Danach hat es ohne Probleme Funktioniert.
Danke für den Hinweis mit dem Titel, ich hab den nochmal geändert
Korrigiert mich, wenn ich falsch liege, aber würde nicht folgender Code schon reichen?
public override Type BindToType(string assemblyName, string typeName)
{
Assembly ass = Assembly.Load(assemblyName); //CLR stellt sicher, dass Assembly nureinmal geladen wird.
return ass.GetType(typeName);
}
Hintergrund ist der, dass die CLR sicherstellt, dass eine Assembly in der jeweiligen aktuellen AppDomain nur einmal geladen wird, ansonsten einfach die bereits geladene Assembly zurückgibt.
@KeramikStar
Dein Laden der Assembly würde beispielsweise nicht die korrekte Versionsnummer, Kultur und PublicToken beachten. Sowas könnte schwere Auswirkungen haben.
Edit: Eine Prüfung auf null und eine entsprechende Exception wären auch nicht verkehrt.
@kleines_eichhoernchen
Danke für den Hinweis, mir ging im Moment in erster Linie darum, dass ich die Datei wieder Deserialisieren kann, so das ich das in dem Moment garnicht bedacht habe.
Ich werd mich gleich mal daran setzen und die Stelle in meinen Code nochmal überarbeiten 😄.