Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: Iurii от 08-10-2017, 11:26:32

Название: Ошибка при десериализации в ACAD
Отправлено: Iurii от 08-10-2017, 11:26:32
Доброе время суток!
Почти год изучаю программирование на С# но это первое обращение за помощью.
Проблема в следующем - в Windows Form вводятся данные и выполняются расчёты, которые сохраняются (сериализуются) в бинарном файле.
Сами данные - реализация класса многоуровнего, со встроенными списками и т.д. оформленного в отдельный DLL (EE_LigtingVarDLL)
Загрузке данного бинарного файла обратно в Windows Form для редактирования проходит без проблем.
При попытке загрузить из ACAD (для вывода собственно в графическом виде), выходит исключение:
{"Не удалось найти сборку \"EE_LigtingVarDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\"."}.
Немного походив по форумам процедуру чтения-записи оформил тоже в DLL (MyIO)
Но ничего не изменилось.
текст DLL (MyIO):

Код - C# [Выбрать]
  1. using EE_LightingVarDLL;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.IO.Compression;
  6. using System.Linq;
  7. using System.Runtime.Serialization.Formatters.Binary;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10.  
  11. namespace MyIO
  12. {
  13.     public class My_IO_DLL
  14.     {
  15.         public LightingVar LoadConfiguration(string filename)//Процедура считывания из файла
  16.         {
  17.             LightingVar serLv = null;
  18.             try
  19.             {
  20.                 using (Stream stream = File.Open(filename, FileMode.Open))
  21.                 {
  22.                     BinaryFormatter bformatter = new BinaryFormatter();
  23.                     serLv = (LightingVar)bformatter.Deserialize(stream);
  24.                     stream.Close();
  25.                 }
  26.                 serLv.errorIO = false;
  27.             }
  28.             catch (Exception ex)
  29.             {
  30.  
  31.             }
  32.             return serLv;
  33.         }
  34.  
  35.         public string SaveConfiguration(string filename, LightingVar lv)//Процедура сохранения в файл
  36.         {
  37.             try
  38.             {
  39.                 using (Stream stream = File.Open(filename, FileMode.Create))
  40.                 {
  41.                     BinaryFormatter bformatter = new BinaryFormatter();
  42.                     bformatter.Serialize(stream, lv);
  43.                     stream.Close();
  44.                 }
  45.                 return "OK";
  46.             }
  47.             catch (Exception ex)
  48.             {
  49.                 return ex.Message;
  50.             }
  51.         }
  52.     }
  53. }

Исключение выходит на строке:
serLv = (LightingVar)bformatter.Deserialize(stream);
конкретно при прохождении stream
Несколько дней сижу с этой проблемой, не знаю что делать. Сам я чертёжник, пишу для оптимизации своего труда, коллеги ничего в программировании не смыслят.
Заранее спасибо.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Пекшев aka Modis от 08-10-2017, 12:11:01
Попробуйте свою библиотеку, которая не находится,  предварительно загрузить с помощью Assembly.LoadFrom()
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Ривилис от 08-10-2017, 13:45:48
Iurii
Приветствую на форуме!
1. Прочитайте у меня в подписи о том, как следует форматировать код на форуме.
2. Серилизация класса .NET в базу чертежа AutoCAD (http://adn-cis.org/serilizacziya-klassa-.net-v-bazu-chertezha-autocad.html)
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Дмитрий Загорулькин от 08-10-2017, 17:03:34
Положите EE_LigtingVarDLL рядом с основной DLL. Возможно, надо просто поставить её свойство "copy local" в "true".
(https://s1.postimg.org/3qxo1w29mj/Copy.png) (https://postimg.org/image/3qxo1w29mj/)
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Ривилис от 08-10-2017, 17:12:36
Положите EE_LigtingVarDLL рядом с основной DLL
А вот это как раз чаще всего и не срабатывает. В отличие от exe-файла, для которого его dll-файлы ищутся в том числе и в этой же директории, для dll-файла поиск рядом (т.е. в его каталоге) не осуществлется. Поэтому или прямая загрузка или вот такой фортель:
http://adndevblog.typepad.com/autocad/2014/01/pnp3dobjectsmgd-not-found-exception.html
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Дмитрий Загорулькин от 08-10-2017, 17:25:46
А вот это как раз чаще всего и не срабатывает.
Странно это. Я всегда так делал: сборку в референсы и клал рядом - подгружает её без проблем. А в статье по ссылке, как я понял, рассказывается о том, что плантовскую dll положили во вложенную папку и acad.exe её не находит из-за этого. Если бы рядом лежала  - проблем не было бы.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Ривилис от 08-10-2017, 17:45:36
Я всегда так делал: сборку в референсы и клал рядом - подгружает её без проблем.
Тогда ещё одна статья: http://adndevblog.typepad.com/autocad/2012/04/load-additional-dlls.html
То как работает у тебя это или из-за того, что используется механизм автозагрузки или эти dll-файлы в путях доступа AutoCAD.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Дмитрий Загорулькин от 08-10-2017, 17:58:13
То как работает у тебя это или из-за того, что используется механизм автозагрузки или эти dll-файлы в путях доступа AutoCAD.
Ни то, ни другое! Уже не вспомню, с каких пор я так делаю и как к этому пришёл. Но мне это казалось настолько очевидным, что я даже сейчас в некотором недоумении.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Ривилис от 08-10-2017, 18:02:33
Уже не вспомню, с каких пор я так делаю и как к этому пришёл.
Кстати в разных версиях AutoCAD это работает по-разному.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Iurii от 08-10-2017, 18:39:59
Спасибо всем!
Итак:
1. предварительно загрузить с помощью Assembly.LoadFrom() - не помогло(никаких изменений)
2. Возможно, надо просто поставить её свойство "copy local" в "true" - так вроде (по крайней мере у меня) и так автоматически ставиться в это положение. Это AutoCAD DLL надо вручную отключать. Я специально чистил референсы, все подключаемые DLL после перекомпиляции в нужных местах.
3. С англоязычными кейсами буду разбираться.
4. Не написал сразу, на более раннем этапе, сериализовал  только список (List<>), он без проблем работал и в Form и в ACAD, без общих DLL, просто одинаковый код. После этого переосмыслил схему обработки информации и сделал Class со структурой списков и спокойно писал в Form собственно ввод и обработку данных. Вот здесь и случился затык - понабилось оформлять в результаты в ACAD, а этот Class в ACAD не дессиаризуется.
5. ACAD 2015
Спасибо.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Дмитрий Загорулькин от 08-10-2017, 18:45:26
Вам бы сперва разобраться с чем бороться: то ли с реализацией сериализации, то ли с поиском вспомогательных сборок...
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Iurii от 08-10-2017, 18:55:12
Так они сами расставляются - вроде как-то так
(https://s1.postimg.org/31t1mwvzp7/image.png) (https://postimg.org/image/31t1mwvzp7/)
или я не правильно понимаю, в Forms все работает идеально
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Дмитрий Загорулькин от 08-10-2017, 18:57:22
Если всё в одну сборку поместить - работает?
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Ривилис от 08-10-2017, 19:26:43
Если всё в одну сборку поместить - работает?
Очень правильный вопрос!
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Iurii от 08-10-2017, 19:31:38
Сделал всё в одной сборке, но ситуация не поменялась.
То есть, при десериализации он пишет:
{"Не удалось найти сборку \"EE_LigtingVarDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\"."}
хотя сам находится в этой сборке.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Iurii от 08-10-2017, 19:38:00
Файл, который не может считаться создан и считывается без проблем в Forms
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Дмитрий Загорулькин от 08-10-2017, 19:43:16
Сделал всё в одной сборке, но ситуация не поменялась.
То есть, при десериализации он пишет:
{"Не удалось найти сборку \"EE_LigtingVarDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\"."}
хотя сам находится в этой сборке.
Такого не должно быть. Если все методы внутри сборки, она не должна искать что-то вне себя. Либо где-то в референсах осталась ссылка на эту DLL, либо вообще грузится какой-то не тот файл. Разбирайтесь.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Iurii от 08-10-2017, 19:44:38
Хорошо,буду разбираться.
Спасибо.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Iurii от 08-10-2017, 19:47:35
А, кстати, когда делаю точку останова, и пошаговое выполнение, то он заходит в нужную сборку.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Дмитрий Загорулькин от 08-10-2017, 19:54:23
Ну раз так, то что вызывает ошибку? Явно она уже не в момент захода "в нужную сборку" выскакивает.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Iurii от 10-10-2017, 18:49:14
Я не знаю,что делать
переписал всё максимально упрощённо, создал другие проекты
вот DLL:
Код - C# [Выбрать]
  1. using System;
  2. namespace Test_DLL
  3. {
  4.     [Serializable]
  5.     public class LightingVar
  6.     {
  7.         public int light = 2;
  8.     }
  9. }
  10.  
Вот приложение под Forms:
Код - C# [Выбрать]
  1. using System;
  2. using System.IO;
  3. using System.Runtime.Serialization.Formatters.Binary;
  4. using System.Windows.Forms;
  5. using Test_DLL;
  6. namespace TestWin
  7. {
  8.     public partial class Form1 : Form
  9.     {
  10.         public LightingVar lv = new LightingVar();
  11.         public string filename;
  12.         public Form1()
  13.         {
  14.             InitializeComponent();
  15.             textBox1.Text = "" + lv.light;
  16.         }
  17.         private void button2_Click(object sender, EventArgs e) // Чтение
  18.         {
  19.             openFileDialog1 .Filter = "Bin files(*.bin)|*.bin|All files(*.*)|*.*";
  20.             if (openFileDialog1.ShowDialog() == DialogResult.Cancel)
  21.                 return;
  22.             string filename = openFileDialog1.FileName;
  23.             LoadConfiguration(filename);
  24.             textBox1.Text = "" + lv.light;
  25.         }
  26.         public int LoadConfiguration(string filename)//Процедура с читывания из файла
  27.         {
  28.             LightingVar ser = null;
  29.             try
  30.             {
  31.                 using (Stream stream = File.Open(filename, FileMode.Open))
  32.                 {
  33.                     BinaryFormatter bformatter = new BinaryFormatter();
  34.                     ser = (LightingVar)bformatter.Deserialize(stream);
  35.                     stream.Close();
  36.                 }
  37.                 lv = ser;
  38.             }
  39.             catch (Exception ex) { }
  40.             return 0;
  41.         }
  42.  
  43.         private void button1_Click(object sender, EventArgs e) // Запись
  44.         {
  45.             lv.light++;
  46.             saveFileDialog1.Filter = "Bin files(*.bin)|*.bin|All files(*.*)|*.*";
  47.             if (saveFileDialog1.ShowDialog() == DialogResult.Cancel)
  48.                 return;
  49.             string filename = saveFileDialog1.FileName;
  50.             SaveConfiguration(filename);
  51.         }
  52.         internal int SaveConfiguration(string Filename)//Процедура сохранения в файл
  53.         {
  54.             try
  55.             {
  56.                 using (Stream stream = File.Open(Filename, FileMode.Create))
  57.                 {
  58.                     BinaryFormatter bformatter = new BinaryFormatter();
  59.                     bformatter.Serialize(stream, lv);
  60.                     stream.Close();
  61.                 }
  62.             }
  63.             catch (Exception ex) { }
  64.             return 0;
  65.         }
  66.     }
  67. }
Всё работает отлично, сохраняю, при загрузке этого же файла значение в текстбоксе увеличивается на 1
При загрузке в ACAD, вылетает исключение, что не может найти сборку Test_DLL, и это скомпилированной программы, где класс LightingVar выделяется как опознанный
вот программа для ACAD:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.Runtime;
  2. using System.IO;
  3. using System.Runtime.Serialization.Formatters.Binary;
  4. using Test_DLL;
  5.  
  6. namespace TestACAD
  7. {
  8.     public class Class1
  9.     {
  10.         [CommandMethod ("zz")]
  11.         public void cad()
  12.         {
  13.             string filename = @"C:\test\3.bin";
  14.             LightingVar lv = new LightingVar();
  15.             LightingVar ser = null;
  16.             try
  17.             {
  18.                 using (Stream stream = File.Open(filename, FileMode.Open))
  19.                 {
  20.                     BinaryFormatter bformatter = new BinaryFormatter();
  21.                     ser = (LightingVar)bformatter.Deserialize(stream); // ВОТ ЗДЕСЬ ВЫХОДИТ В CATCH
  22.                     stream.Close();
  23.                 }
  24.                 lv = ser;
  25.             }
  26.             catch (System.Exception ex) { }
  27.         }
  28.     }
  29. }
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Пекшев aka Modis от 10-10-2017, 18:56:40
Приложите решение (проекты) для тестов
И используйте форматирование кода в ваших ответах
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Iurii от 10-10-2017, 18:59:50
Добрый вечер!
Высылаю.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Ривилис от 10-10-2017, 20:06:22
Iurii
Второй (и последний) раз предупреждаю о правиле форматирования кода на форуме. Читай у меня в подписи.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Iurii от 10-10-2017, 21:23:36
Насчёт форматирования кода - приношу извинения, разобрался, больше не буду.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Пекшев aka Modis от 10-10-2017, 22:34:09

(https://s1.postimg.org/1flhfm852z/lc3f46.jpg) (https://postimg.org/image/1flhfm852z/)

Код - C# [Выбрать]
  1. using System;
  2. using Autodesk.AutoCAD.Runtime;
  3. using System.IO;
  4. using System.Runtime.Serialization.Formatters.Binary;
  5. using Test_DLL;
  6.  
  7. namespace TestACAD
  8. {
  9.     public class MyApp : IExtensionApplication
  10.     {
  11.         public void Initialize()
  12.         {
  13.             AppDomain currentDomain = AppDomain.CurrentDomain;
  14.             currentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
  15.         }
  16.  
  17.         public void Terminate()
  18.         {
  19.             //nothing
  20.         }
  21.         private System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
  22.         {
  23.             System.Reflection.Assembly[] asms = AppDomain.CurrentDomain.GetAssemblies();
  24.             for (int i = 0; i < asms.Length; ++i)
  25.             {
  26.                 if (asms[i].FullName == args.Name)
  27.                     return asms[i];
  28.             }
  29.             return null;
  30.         }
  31.     }
  32.     public class Class1
  33.     {
  34.         [CommandMethod ("zz")]
  35.         public void cad()
  36.         {
  37.             string filename = @"C:\test\3.bin";
  38.             LightingVar lv = new LightingVar();
  39.             LightingVar ser = null;
  40.             try
  41.             {
  42.                 using (Stream stream = File.Open(filename, FileMode.Open))
  43.                 {
  44.                     BinaryFormatter bformatter = new BinaryFormatter();
  45.                     ser = (LightingVar)bformatter.Deserialize(stream);
  46.                     stream.Close();
  47.                 }
  48.                 lv = ser;
  49.                 Autodesk.AutoCAD.ApplicationServices.Core.Application.DocumentManager.MdiActiveDocument.Editor
  50.                     .WriteMessage("!!!!!!");
  51.             }
  52.             catch (System.Exception ex)
  53.             {
  54.                 Autodesk.AutoCAD.ApplicationServices.Core.Application
  55.                     .DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.Message);
  56.             }
  57.         }
  58.     }
  59. }

На вопрос "Почему" ответа не дам. Это просто магия )))
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Ривилис от 10-10-2017, 23:03:40
На вопрос "Почему" ответа не дам. Это просто магия )))
Я что-то пропустил или сборка действительно без AssemblyResolve не грузилась?
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Пекшев aka Modis от 10-10-2017, 23:08:31
Я что-то пропустил или сборка действительно без AssemblyResolve не грузилась?
Нет, тут проблема не в этом и с автокадом не связана.
Проблема с сериализацией в бинарный формат, когда работа происходит в разных приложениях. Ответ (и точно такую-же проблему) нашёл тут (https://rsdn.org/forum/dotnet/2900485.all)
Смахивает на косяк в .Net framework, хотя может проблема в чем-то особенном
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Ривилис от 10-10-2017, 23:27:52
Нет, тут проблема не в этом и с автокадом не связана.
Александр Пекшев aka Modis
Я где-то про AutoCAD писал??? Фактически подписка на AssemblyResolve перенаправляла все LoadFrom на обработчик события и давала возможность явной подстановки нужной сборки. Важно только чтобы эта сборка уже была загружена в AppDomain.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Пекшев aka Modis от 10-10-2017, 23:42:49
Я где-то про AutoCAD писал???
Я не имел ввиду, что вы про это говорили) Я имел ввиду, что речь идет в общем контексте работы в автокаде

Кстати, правильный ответ и ссылку Вы дали еще в начале обсуждения )
А вот это как раз чаще всего и не срабатывает. В отличие от exe-файла, для которого его dll-файлы ищутся в том числе и в этой же директории, для dll-файла поиск рядом (т.е. в его каталоге) не осуществлется. Поэтому или прямая загрузка или вот такой фортель:
http://adndevblog.typepad.com/autocad/2014/01/pnp3dobjectsmgd-not-found-exception.html
Точнее - там что-то похожее. Вариант, который я нашел короче и проще
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Iurii от 11-10-2017, 04:49:30
Ура!
Всё заработало!
Как тестовый вариант, так и тот, что был (с вынесенной в отдельный DLL процедурой чтения-записи).
Спасибо всем, встал сегодня пораньше, чтобы посмотреть ответы.
Всем до свидания, может быть ещё возникнут "нерешаемые" проблемы.
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Ривилис от 11-10-2017, 12:40:35
Кстати, правильный ответ и ссылку Вы дали еще в начале обсуждения )
Ну и кто же меня сразу слушать будет? ;)
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Александр Ривилис от 11-10-2017, 12:52:30
Ура!
Всё заработало!
Всем до свидания, может быть ещё возникнут "нерешаемые" проблемы.
И кто будет отмечать Решение (как написано у меня в подписи)? Я уже это сделал и на первый раз прощаю! :)
Название: Re: Ошибка при десериализации в ACAD
Отправлено: Iurii от 11-10-2017, 18:15:32
Больше так не буду. Спасибо.