Динамически подключенная Dll и десериализация

  • Автор темы Vitone
  • Дата начала
V

Vitone

У меня такая проблемма. Существует иеархия классов, при чем базовый класс и большое множество производных от него классов раскиданы по разным dll-кам (в одной - сколько угодно производных классов). И мне необходимо сохранять состояние классов (использую SOAP сериализацию). Так вот, если эти dll-ки подключаю статически, то все нормально, но когда динамически - возникает ошибка при попытке десериализировать, при чем на этапе разбора элементов XML файла.

Сериализация:
[codebox] SoapFormatter formatter = new SoapFormatter();
FileStream stream = File.Open(fileName, FileMode.Create);
FbdProgram tmp=new FbdProgram();
formatter.Serialize(stream, tmp);
stream.Close();
[/codebox]

Десериализация:
[codebox] Stream stream = File.Open(fileName, FileMode.Open);
SoapFormatter formatter = new SoapFormatter();
FbdProgram tmp=new FbdProgram();
tmp = (FbdProgram)formatter.Deserialize(stream);
stream.Close();
[/codebox]

Фрагмент сохраненного XML файла:
<a2:MUL_INT id="ref-10" xmlns:a2="http://schemas.microsoft.com/clr/nsassem/FBDVisualBlocks.VisualBlocks/FBDVisualBlocks%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Db98b95bcb02affd6">

Ошибка происходит при десериализации на строчке:
tmp = (FbdProgram)formatter.Deserialize(stream);

При этом она имеет следующий вид:

An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in System.Runtime.Serialization.Formatters.Soap.dll

Additional information: Parse Error, no assembly associated with Xml key a2:http://schemas.microsoft.com/clr/nsassem/FBDVisualBlocks.VisualBlocks/FBDVisualBlocks%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Db98b95bcb02affd6 MUL_INT

Большое спасибо!
 
V

Vitone

Библиотеки подключаются так: ищутся все dll-ки в заданном каталоги и с заданным атрибутом:

Вот привожу код:
[codebox] public void LoadDlls(string path)
{
DirectoryInfo Dir = new DirectoryInfo(path);
FileInfo[] files = Dir.GetFiles("*.dll");
foreach (FileInfo file in files)
{
a = Assembly.LoadFrom(Application.StartupPath + "\\" + path+"\\"+file.Name/*.Substring(0, file.Name.Length - 4)*/);
_types = a.GetTypes();
foreach (Type type in _types)
{
ListOfTypes.Add(type);
}
}

}
[/codebox]
 
P

Pasha

Vitone
Похоже, SoapFormatter не заморачивается с поиском библиотек, и тупо сам загружает их через Assembly.Load. А тот, в свою очередь, тупо отвечает что не может загрузить, т.к. не может найти файл на диске и сверить с уже загруженным. Пропиши в конфиге configuration/runtime
/assemblyBinding/probing/@privatePath к папке с длл-ками. Или просто помогай рантайму их резолвить, примерно так:
Код:
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Soap;

namespace ConsoleApplication2
{
class Program
{
private static Assembly sampleAssembly;

static void Main(string[] args)
{
sampleAssembly = Assembly.LoadFrom(@"D:\Projects\sl1\ClassLibrary1\bin\Debug\ClassLibrary1.dll");

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

Stream stream = File.Open(@"D:\temp.txt", FileMode.Open);
SoapFormatter formatter = new SoapFormatter();
object tmp = formatter.Deserialize(stream); 
stream.Close();
}

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name == sampleAssembly.FullName)
{
return sampleAssembly;
}
else
{
return null;
}
}
}
}
Звиняй, код на коленке написан.
ЗЫ. И еще, в десериализации ты зачем-то объект создаешь лишний раз:
Код:
			FbdProgram tmp=new FbdProgram();
tmp = (FbdProgram)formatter.Deserialize(stream);
 
V

Vitone

Пропиши в конфиге configuration/runtime
/assemblyBinding/probing/@privatePath к папке с длл-ками.

А можно об этом поподробней? Никогда раньше не рограмил с использованием dll-ок. А за помощь спасибо, сейчас проверю!

Похоже, SoapFormatter не заморачивается с поиском библиотек, и тупо сам загружает их через Assembly.Load
Твоя правда, Pasha, SoapFormatter не ищет dll-ки в моей папке, а ищет в той, где сам ехе-шник. Но мне очень желательно, чтоб эти dll-ки были в отдельной папке, поскольку предполагается, что их количество будет расти, и, возможно писть их будет кто-то другой.
 
P

Pasha

А можно об этом поподробней? Никогда раньше не рограмил с использованием dll-ок.
Это секция конфига приложения, в которой можно прописать доп. пути для поиска сборок:
, и дальше по ссылками "How the Runtime Locates Assemblies"
 
V

Vitone

Создал конфигурационный файл Program.exe.config и поместил в папку с экзешником (bin\Debug), прописал в нем такие строчки:

<?xml version="1.0"?>
<configuration>
<runtime>
<assemblyBinding>
<probing privatePath="Blocks;"/>
</assemblyBinding>
</runtime>
</configuration>

Но SoapFormatter все равно не находит сборки, только в папке экзешника.
Что я не так сделал?
 
V

Vitone

Всё, разобрался, спасибо. Вот это мне помогло:

:)
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!