Доступ к Revit из внешнего приложения

Автор Тема: Доступ к Revit из внешнего приложения  (Прочитано 13408 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн Александр РивилисАвтор темы

  • Administrator
  • *****
  • Сообщений: 13871
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Пара риторических вопросов к размышлению:

1. Что произойдёт, если клиент отправляет запрос, но при этом на хостовой машине будет запущено сразу несколько экземпляров приложений Revit, в каждом из которых, в свою очередь, будет работать указанная служба?

2. Каким образом, в обозначенном выше решении, внешнее приложение сможет адресовать свой запрос конкретному процессу, если присутствует ситуация, обозначенная в п.1?

Я не специалист в WCF, поэтому наверняка некоторые вещи можно сделать более грамотно, чем мне это видится сейчас. На мой взгляд, в обозначенном решении, между клиентом и сервисом, хостящимся в Revit не хватает посредника - дополнительной службы, работающей либо под управлением диспетчера служб Windows, либо хостящейся в некотором стороннем процессе. Клиент должен обращаться не напрямую к службе, хостящейся в Revit, но к службе-посреднику, указывая в составе своего запроса идентификатор того процесса, которому он хотел бы адресовать этот запрос. Посредник же, в свою очередь, выполняет переадресацию запроса нужному экземпляру службы. Этот же посредник может управлять временем жизни экземпляров процессов Revit, создавая\закрывая их по мере необходимости.

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 694
  • Карма: 111
  • Skype: chekalin-v
1. Что произойдёт, если клиент отправляет запрос, но при этом на хостовой машине будет запущено сразу несколько экземпляров приложений Revit, в каждом из которых, в свою очередь, будет работать указанная служба?
В данной реализации WCF сервис просто не запустится при запуске второго экземпляра Revit, а вернее вылетет с exception.

2. Каким образом, в обозначенном выше решении, внешнее приложение сможет адресовать свой запрос конкретному процессу, если присутствует ситуация, обозначенная в п.1?
В каждом экземпляре приложения нужно будет создавать отдельный экземпляр WCF сервиса с прослушкой разных портов (если речь идет о tcp протоколе). Клиент должен адресовать свой запрос конкретному WCF сервису, а значит и конретному процессу Revit.

Правда тут сложность в том, как определить какой экземпляр WCF сервиса соответствует определенному процессу Revit.

Это можно будет реализовать в том числе и предложенным вами способом, с помощью посредника.

Все зависит от задачи конечно. В статье приводится лишь идея и пример простой реализации.

В той задаче, где я применял на практике подобный подход, мне совершенно не требовался запуск нескольких экземпляров Revit, а следовательно лишние усложенния архитектуры (создание посредника, определение конкретного процесса) были совершенно ни к чему.

Оффлайн Ярослав

  • ADN OPEN
  • **
  • Сообщений: 82
  • Карма: 1
Добрый день.
Подскажите пожалуйста с выходом новых версий ничего не поменялось с подключением к Ревит из другого приложения?

Оффлайн Александр РивилисАвтор темы

  • Administrator
  • *****
  • Сообщений: 13871
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Нет. И не думаю, что что-то в дальнейшем может измениться в этом плане.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Ярослав

  • ADN OPEN
  • **
  • Сообщений: 82
  • Карма: 1
Добрый день. Подскажите пожалуйста, было приложение где через WCF сервис выполнялось подключение к Ревит 2017.
С установкой Ревита 2019, совершенно не могу подключится к серверу WCF. Сервис создается без проблем, а вот обращение к нему не выполняется, говорит что прошло время запроса.
Это что то перекрыли в Ревите или проблемы с Фраемворком 4.7?

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78

Оффлайн Ярослав

  • ADN OPEN
  • **
  • Сообщений: 82
  • Карма: 1
Не очень радостная новость. Но в интернете встречал что у некоторых людей(не Revit API) возникали проблемы при переходах с NET 4,6 на 4,7. Но решений не предоставлялось.

Оффлайн Александр РивилисАвтор темы

  • Administrator
  • *****
  • Сообщений: 13871
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
С .NET Framework 4.7 проблемы у многих программ Autodesk (и не только Autodesk). Часть из них решена в обновлении .NET Framework 4.7.1
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Ярослав

  • ADN OPEN
  • **
  • Сообщений: 82
  • Карма: 1
и  .NET Framework 4.7.1 не помог.
Клиент как бы хочет обратится к серверу, но тот его не пускает причем Ревит при этом виснет(курсор-часики) до бесконечности.

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Доступ к Revit из внешнего приложения
« Ответ #10 : 26-04-2018, 12:40:40 »
Клиент как бы хочет обратится к серверу, но тот его не пускает причем Ревит при этом виснет(курсор-часики) до бесконечности.
На консольном "Hello World" пробовал, работает?

Оффлайн Ярослав

  • ADN OPEN
  • **
  • Сообщений: 82
  • Карма: 1
Re: Доступ к Revit из внешнего приложения
« Ответ #11 : 26-04-2018, 14:12:12 »
На консольном "Hello World" пробовал, работает?
в смысле приложение "Hello World" или подключится к "Hello World"?
Другие приложения работают без проблем. но вот с  WCF сервисом никак.

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Доступ к Revit из внешнего приложения
« Ответ #12 : 26-04-2018, 14:16:54 »
в смысле приложение "Hello World" или подключится к "Hello World"?
Другие приложения работают без проблем. но вот с  WCF сервисом никак.
Создать два простых консольных приложения - один клиент, а др. - являющийся хостом для твоего WCF-сервиса. Отправить клиентом запрос сервису и получить обратно ответ. Чтобы исключить Ревит из уравнения и понять, работает ли твой код в др. ситуациях.

Оффлайн Ярослав

  • ADN OPEN
  • **
  • Сообщений: 82
  • Карма: 1
Re: Доступ к Revit из внешнего приложения
« Ответ #13 : 26-04-2018, 14:34:09 »
так еще не делал, но пробовал приложение собранное на  .NET Framework 4.7.1 запускать на Ревите 17 то сервис работает, а как только 19 то ... в ответ тишина.

Оффлайн Ярослав

  • ADN OPEN
  • **
  • Сообщений: 82
  • Карма: 1
Re: Доступ к Revit из внешнего приложения
« Ответ #14 : 27-04-2018, 08:52:58 »
Если попытаться "пройтись" по http://adn-cis.org/dostup-k-revit-iz-vneshnego-prilozheniya.html, приложение заходит на сервис, на lock (_locker)
            {
                TaskContainer.Instance.EnqueueTask(GetDocumentPath);
 
                // Ждем завершение задачи
                Monitor.Wait(_locker, WAIT_TIMEOUT);
            }

заходит в Instance, потом заходит в EnqueueTask а вот в GetDocumentPath не заходит.
 и дальше на себе спокойно на Monitor.Wait(_locker, WAIT_TIMEOUT);. и все.
А знаний у меня маловато и...

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Re: Доступ к Revit из внешнего приложения
« Ответ #15 : 02-05-2018, 16:26:38 »
Добрый день, коллеги.

Я честно говоря, не знаю, с чем именно связано изменение поведения кода в Revit 2019, полагаю, что дело всё же в реализации ServiceHost самим фреймворком. Дело в том, что исходный код полагается на то, что методы сервиса и обработчик события OnIdling вызываются более-менее независимо, т.е. в методе сервиса (упрощенно) запускается:
Код - C# [Выбрать]
  1. lock (Locker)
  2.             {
  3.                 TaskContainer.Instance.EnqueueTask(GetDocumentPath); // <- здесь запуск задачи GetDocumentPath
  4.  
  5.                 Monitor.Wait(Locker, WaitTimeout);// <- вот здесь ожидается, что где-то кто-то за отведенный промежуток времени вызовет Monitor.Pulse(Locker);
  6.             }
  7.  
  8.             return currentDocumentPath;
  9.  

Соответственно в обработчике событий вызывается Monitor.Pulse:
Код - C# [Выбрать]
  1.         private void GetDocumentPath(UIApplication uiapp)
  2.         {
  3.             try
  4.             {
  5.                 currentDocumentPath = uiapp.ActiveUIDocument.Document.PathName;
  6.             }
  7.             finally
  8.             {
  9.                 lock (Locker)
  10.                 {
  11.                     Monitor.Pulse(Locker); //<- ТЫЦ!
  12.                 }
  13.             }
  14.         }

Ну а сам этот код фактически вызывается из обработчика события OnIdling, который дергает сам Revit.

Всё вроде бы хорошо, но фактически событие OnIdling вызываться перестает, останавливаемся на строке
Код - C# [Выбрать]
  1. Monitor.Wait(Locker, WaitTimeout);
По таймауту сервис отваливается, а затем код успешно выполняется из обработчика события

Окей, так пусть же serviceHost открывается в отдельном потоке:
Код - C# [Выбрать]
  1.         private const string ServiceUrlHttp = "http://localhost:9001/RevitExternalService";
  2.         private const string ServiceUrlTcp = "net.tcp://localhost:9002/RevitExternalService";
Код - C# [Выбрать]
  1.         public Result OnStartup(UIControlledApplication application)
  2.         {
  3.             application.Idling += OnIdling;
  4.            
  5.             try
  6.             {
  7.                 Task.Factory.StartNew(() =>
  8.                 {
  9.                     var serviceHost = new ServiceHost(typeof(RevitExternalService), new Uri(ServiceUrlHttp), new Uri(ServiceUrlTcp));
  10.  
  11.                     serviceHost.Description.Behaviors.Add(new ServiceMetadataBehavior());
  12.                     serviceHost.AddServiceEndpoint(typeof(IRevitExternalService), new BasicHttpBinding(), ServiceUrlHttp);
  13.                     serviceHost.AddServiceEndpoint(typeof(IRevitExternalService), new NetTcpBinding(), ServiceUrlTcp);
  14.                     serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
  15.                     serviceHost.Open();
  16.                 }, TaskCreationOptions.LongRunning);
  17.                
  18.             }
  19.             catch (Exception ex)
  20.             {
  21. //....
  22.             }
  23.  
  24.             return Result.Succeeded;
  25.         }

Ну и собственно, теперь снова всё работает

Оффлайн Ярослав

  • ADN OPEN
  • **
  • Сообщений: 82
  • Карма: 1
Re: Доступ к Revit из внешнего приложения
« Ответ #16 : 03-05-2018, 09:14:20 »
Добрый день.
Спасибо, но теперь вообще не может подключится к сервису.
Так как адрес у меня в клиенте
            "net.pipe://localhost/"
 и клиент говорит что: прослушивание по net.pipe://localhost/ не выполняла ни одна конечная точка которая могла бы принять сообщение.
Или теперь нужно другой адрес вбивать?

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Re: Доступ к Revit из внешнего приложения
« Ответ #17 : 03-05-2018, 09:58:30 »
Попробуйте другой адрес/порт, у меня, вообще говоря, в журнале была ошибка, что-то связанное с тем, что не удалось на этом адресе развернуть сервис, поскольку он уже кем-то используется. Сейчас не смогу полный текст привести, тут на работе Revit 2018, 19-ый только дома есть

Оффлайн Ярослав

  • ADN OPEN
  • **
  • Сообщений: 82
  • Карма: 1
Re: Доступ к Revit из внешнего приложения
« Ответ #18 : 03-05-2018, 10:27:24 »
А какой адрес задавать? При попытках задать адрес типа
       "http://localhost:9001/RevitExternalService";
        "net.tcp://localhost:9002/RevitExternalService";
клиент говорит что ему нужен net.pipe адрес.

А теперь вообще не хочет создавать сервер говорит : недопустимый URI в 
var serviceHost = new ServiceHost(typeof(RevitExternalService), new Uri(ServiceUrlHttp), new Uri(ServiceUrlTcp));

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Re: Доступ к Revit из внешнего приложения
« Ответ #19 : 03-05-2018, 10:43:57 »
Ну странно вообще говоря, у меня завелось всё, единственное, нужно либо прописать в системе права на создание wcf-сервиса по данному адресу, либо запускать Revit от администратора. А клиент, да, ему нужно указать правильный конфиг/биндинг, либо использовать SvcUtil, чтобы сгенерировать код и конфиг-файл...

Адреса ServiceUrlHttp и ServiceUrlTcp взяли такие?
Код - C# [Выбрать]
  1.             private const string ServiceUrlHttp = "http://localhost:9001/RevitExternalService";
  2.             private const string ServiceUrlTcp = "net.tcp://localhost:9002/RevitExternalService";

Оффлайн Ярослав

  • ADN OPEN
  • **
  • Сообщений: 82
  • Карма: 1
Re: Доступ к Revit из внешнего приложения
« Ответ #20 : 03-05-2018, 11:02:46 »
Да такие. Так вот первый раз сервис запускался без проблем, только клиент не мог подключится к адресу. Но после того как я начал изменять конфиг файл клиента серверу перестал нравится URI.
А конфиг/биндинг нужно на оба подключения(ServiceUrlHttp и ServiceUrlTcp) создавать?

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Re: Доступ к Revit из внешнего приложения
« Ответ #21 : 03-05-2018, 11:10:27 »
Вообще говоря не понял, каким образом серверу перестал нравиться URI при изменении клиента?

Подключение можно только то, что нужно, тогда только надо убрать второй end point тоже. Я делал на основе вот этого https://habr.com/post/331952/
Клиент писать было немного лень, использовал wcftestclient, подключался к endpoint-у на http.

Если хотите, вечером форкну проект, залью рабочую версию

Оффлайн Ярослав

  • ADN OPEN
  • **
  • Сообщений: 82
  • Карма: 1
Re: Доступ к Revit из внешнего приложения
« Ответ #22 : 03-05-2018, 11:16:47 »
С URI уже разобрался, после перезагрузки системы, заработало.
За проект буду очень благодарен.
А пока сам попробую разбираться.

Отмечено как Решение Александр Ривилис 04-05-2018, 14:01:02

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Re: Доступ к Revit из внешнего приложения
« Ответ #23 : 03-05-2018, 21:53:48 »
Обещанный форк репозитория с рабочим кодом: https://github.com/CADBIMDeveloper/RevitExternalAccessDemo

Ну и результат работы создания стен, используя сервис:



Оффлайн Ярослав

  • ADN OPEN
  • **
  • Сообщений: 82
  • Карма: 1
Re: Доступ к Revit из внешнего приложения
« Ответ #24 : 04-05-2018, 08:54:27 »
БОЛЬШОЕ СПАСИБО!!!!!
Оказывается все так просто.
А мне еще учится и учится....(((
еще раз спасибо.

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Re: Доступ к Revit из внешнего приложения
« Ответ #25 : 04-05-2018, 09:14:53 »
Ну учиться надо всегда и везде)

А вообще, Autodesk эти летом обещает выложить Revit IO - движок Revit-а в облаке, по аналогии с тем, что уже давно есть для AutoCAD-а, это, вероятно, более подходящее решение для подобных задач