0. blackhole321 759 02.02.15 13:47 Сейчас в теме

Генерируем ВнешнееСобытие из внешнего приложения/скрипта web запросом

Простая внешняя компонента, которая позволяет генерировать внешние события в 1С:Предприятие из внешнего приложения/скрипта web запросом.

Перейти к публикации

Комментарии
Сортировка: Древо
1. mdSerg 02.02.15 17:54 Сейчас в теме
Т.е. чтобы обратиться из внешнего приложения, надо сначала запустить 1С , которая вызовет эту компоненту?
Не понял смысла компоненты - если надо запускать 1С?
Что мешает напрямую обратиться к веб-сервису 1С?
Приведите пример использования, пожалуйста.
2. Kabz 74 03.02.15 00:13 Сейчас в теме
Я думаю смысл использование дерганье тонкого ,веб клиента (формы) для передачи данных , с веб сервиса ты данные на форму просто так не передать.
3. blackhole321 759 03.02.15 09:23 Сейчас в теме
Kabz (2)
Да, именно так.
MdSerg (1)
В качестве примера могу привести библиотеку "Звонки из Lync" http://infostart.ru/public/322875/. В ней взаимодействие с Lync реализовано на PowerShell. И все было бы хорошо, однако необходимо передавать информацию о звонке в клиент 1С:Предприятие. Можно использовать обработчик ожидания и периодически проверять наличие звонков, а можно при наступлении звонка вызывать ВнешнееСобытие, написав примерно следующий код:
Invoke-WebRequest -Uri 'http://localhost:yourport/ExternalEvent?key=yourkey&source=yoursource&message=yourmessage' и обработать его в клиенте.
В общем, область применения примерно такая же как и для внешних компонент с той лишь разницей, что это можно делать из внешнего скрипта/приложения.
4. mdSerg 08.11.15 21:01 Сейчас в теме
Т.е. взаимодействие непосредственно с клиентом 1С, а не с сервером? (это полезно)
ВЕБ-Сервер д.б. установлен на клиентском компьютере?
5. blackhole321 759 09.11.15 12:34 Сейчас в теме
(4) mdSerg,
Добрый день.
Да, с клиентом 1С.
Веб-сервер - это и есть внешняя компонента. Устанавливается на клиенте штатным образом.
6. dablack 19.05.16 00:01 Сейчас в теме
Спасибо автору, вроде то, что надо, но немного насторожил момент, что адрес и ключ присваиваются автоматически при запуске.
А нет возможности их задать руками?
Мне необходимо организовать, что то вроде сервера печати. С мобильных приложений поступает задание на печать документа с таким то идентификатором.
И в случае с автоматическим назначением портов мобильному приложению придется перед каждым заданием на печать запрашивать текущий порт и ключ у веб-сервиса сервера 1С например (вдруг после прошлого задания на печать клиент 1с с запущенной ВК перезапустился....)
А если порт всегда один и тот же, то я бы смог сразу из мобильного приложения отправлять запрос на нужный ip:port..
В любом случае после долгого безрезультатного поиска какого нибудь мини веб-сервера который работал сам по себе в виде службы и в который можно было бы отправлять запросы POST запросы с двоичными данными и чтобы он их отправлял на печать на нужный принтер, Ваш продукт очень даже пригодится. Спасибо!
7. blackhole321 759 19.05.16 16:49 Сейчас в теме
(6) dablack,
Ключ можно задать руками. Порт только для чтения т.к. он выбирается динамически из списка свободных tcp портов.
Я правильно понимаю, что Вы хотите отправлять запросы на печать клиенту 1С на компьютере пользователя?
8. dablack 19.05.16 18:27 Сейчас в теме
Да, все верно, именно так.
9. blackhole321 759 19.05.16 18:47 Сейчас в теме
(8) dablack,
Ну Вам все равно необходимо каким-то образом получать список доступных хостов, с которых можно производить печать. В таком случае можно при старте передавать информацию о хосте/порте/ключе на сервер 1С и периодически обновлять эту информацию. Мобильное устройство, считав информацию использует ее до момента возникновения ошибки, при попытке отправить запрос. При возникновении ошибки информация о доступных хостах/портах/ключах считывается заново.
10. dablack 19.05.16 19:07 Сейчас в теме
Все таки мне гораздо удобнее было бы работать со статическим портом.
Файл скачал, но прошу прощения, а вы исходниками не поделитесь? Я думаю сам смогу разобраться даже со знаниями в С++ близкими к нулю где проставить порт. А то помимо печати есть еще мысли где я смогу применить данную компоненту и опять же порт очень хотелось бы статический... В любом случае спасибо!
11. dablack 04.10.16 20:58 Сейчас в теме
Насколько реально сделать так чтобы ExternalEvent возвращал не просто True/False а нечто другое (результат работы какой то либо функции) ?
12. blackhole321 759 05.10.16 18:49 Сейчас в теме
(11) dablack, Эта функция помещает событие в очередь, вызывая одноименную функцию платформы. Функция платформы возвращает тип Boolean, где возвращаемое значение - true, если событие добавлено в очередь и false, если произошла какая либо ошибка (см. описание интерфейса по ссылке в публикации). Соответственно получить какие-либо значения результатов вряд ли возможно. Для выполнения каких-либо действий на сервере 1С предприятие с последующим возвратом значений etc., Вы можете использовать web-сервисы.
Если не секрет, чем вызвана необходимость вызывать исполннение кода с последующим возвратом результатов именно на клиенте?
13. dablack 10.10.16 20:56 Сейчас в теме
(12) То что в данный момент возвращает только boolean это я знаю и этим пользуюсь. Не секрет, вариантов очень много для чего есть необходимость такого прямого GET запроса и получения ответа. Например, складские работники перемещаются по складу с терминалами и сканируют шк адреса ячеек, шк непосредственно товара и в случае (как сейчас и есть) обращения к http сервисам базы, на каждый "пик" проходит аутентификация, инициализация модуля сеансов и т.д. а только после всего это возвращаются нужные данные. Т.е. достаточно большие накладные расходы. Если бы ваша компонента умела возвращать не только true/false то для меня бы это была отличная альтернатива - обращаться к постоянно "взведенному" веб серверу. Да конечно вроде в 8.3.9. реализован механизм повторного использования сессии, но попробовать на тесте еще не успел, да и не очень пока хочется продакш базу переводить на свежую платформу из-за пары фичь.
p.s. очень не хватает все таки возможности задать порт руками) приходиться лишний http запрос делать на получение текущего порта...
14. blackhole321 759 11.10.16 21:24 Сейчас в теме
(13) dablack, Ну если использование штатных http сервисов категорически не устраивает - остается написать их самостоятельно :)

1. Создайте насервере 1С тестовую информационную базу
2. Добавьте в нее общий модуль, с возможностью доступа из внешнего соединения
3. Добавьте в модуль следующий код:


Функция МойМетод1() Экспорт
	Возврат "Вызов метода МойМетод1";
КонецФункции

Функция МойМетод2() Экспорт
	Возврат "Вызов метода МойМетод2";
КонецФункции

Функция МойМетод3() Экспорт
	Возврат "Вызов метода МойМетод3";
КонецФункции
Показать


4. Зарегистрируйте COM компонент, если он не был зарегистрирован ранее
5. Если Вы используете 64 битную систему - создайте для COM объекта COM+ приложение

6. Создайте скрипт PowerShell примерно следующего содержания:

# Инициализируем подключение к 1С

$Коннектор1С = New-Object -ComObject V83.ComConnector

$СтрокаПодключения =  "srvr='ИмяМоегоСервера'; ref='ИмяМоейБазы';"
$Соединение1С = $Коннектор1С.Connect($СтрокаПодключения);
$МойОбщийМодуль = [System.__ComObject].InvokeMember("МойОбщийМодуль",[System.Reflection.BindingFlags]::GetProperty,$null,$Соединение1С,$null)

# Инициализируем web-сервер

$ВебСлушатель = New-Object System.Net.HttpListener

$ВебСлушатель.Prefixes.Add("http://localhost:8080/Method1/")
$ВебСлушатель.Prefixes.Add("http://localhost:8080/Method2/")
$ВебСлушатель.Prefixes.Add("http://localhost:8080/Method3/")

$ВебСлушатель.AuthenticationSchemes = 'Anonymous'    
$ВебСлушатель.Start() 

# Получаем и обрабатываем web-запросы

while ($ВебСлушатель.IsListening)
{
    $Контекст = $ВебСлушатель.GetContext()
	$UrlЗапроса = $Контекст.Request.Url
	$Ответ = $Контекст.Response
    
    $ИмяМетода1С = ""

    if ($UrlЗапроса.AbsoluteUri.EndsWith("Method1", [System.StringComparison]::InvariantCultureIgnoreCase))
    {
        $ИмяМетода1С = "МойМетод1" 
    }
    elseif ($UrlЗапроса.AbsoluteUri.EndsWith("Method2", [System.StringComparison]::InvariantCultureIgnoreCase))
    {
        $ИмяМетода1С = "МойМетод2"
    }
    elseif ($UrlЗапроса.AbsoluteUri.EndsWith("Method3", [System.StringComparison]::InvariantCultureIgnoreCase))
    {
        $ИмяМетода1С = "МойМетод3"
    }

    $Результаты = [System.__ComObject].InvokeMember($ИмяМетода1С,[System.Reflection.BindingFlags]::InvokeMethod,$null,$МойОбщийМодуль, $null)
    
    # Возвращаем результат
    $Буфер = [System.Text.Encoding]::UTF8.GetBytes($Результаты)
	$Ответ.ContentLength64 = $Буфер.Length
	$Ответ.AppendHeader("Content-Type","text;charset=utf-8")
	$Ответ.OutputStream.Write($Буфер, 0, $Буфер.Length)
    $Ответ.Close()
 }

Показать


7. Замените в строке подключения значения базы и сервера на свои. При необходимости добавьте имя пользователя и пароль.
8. Сохраните скрипт и запустите его.
9. В браузере в строку адреса введите:
http://localhost:8080/Method1
http://localhost:8080/Method2
http://localhost:8080/Method3
Соответственно должны будут появиться результаты вызова соответствующих функций общего модуля.

Если устраивает производительность - добавляете многопоточность, передачу параметров и обработку ошибок
15. soal 12.10.17 12:29 Сейчас в теме
Очень понравилась разработка. Стабильно работает на винде. Только не хватает задания конкретного порта для регистрации. Комп конечного пользователя за роутером, конкретный порт можно пробросить, а пробрасывать все порты на роутер - открыть широко дверь всем с инета - не айс.
16. blackhole321 759 12.10.17 12:51 Сейчас в теме
(15) Это некий компромисс, т.к. порт может быть занят другим приложением/сервисом. Как пример - Вы запустили несколько экземпляров клиента 1С. Такого рода проблему можно решить написав что-то типа reverse proxy. После загрузки компонента, происходит регистрация на proxy и отправка ID клиенту, соответственно наружу выставляется один порт. Клиент посылает запросы с указанием ID на один порт, прокси пересылает данные по нужному адресу/порту в соответствии с ID.
18. soal 12.10.17 17:24 Сейчас в теме
(16) Порт может быть занят - вернуть ошибку "порт занят", или еще лучший вариант - если порт занят, запустить на свободном порту, а в коде можно будет проверить равен ли фактический порт заданному и уже решать в алгоритме, что дальше делать - отключаться или продолжать работу. В моем случае нужно будет отключиться и сообщить клиенту чтобы он проверил/освободил порт, либо пробросил новый порт (на который удалось подключиться) и указал его в настройках.
(17) reverse proxy - это уже перебор. Клиент с ноутбуком сидит, через wi-fi роутер. Поднимать ему на ноутбуке еще прокси чтобы ретранслировать запросы самому на себя по динамическому порту - это уже похоже на извращения )
Реально "предпочитаемый порт" добавит функциональной применимости Вашей компоненте в разы. Простой пример "проверь свои задачи". Вместо обработчика ожидания, который сейчас дергает мне сервер раз в минуту на предмет "а не появилось ли новых задач", можно было бы "по факту" оповестить клиента и "заставить его" открыть форму задачи сразу после ее записи в базе. Проблема с теми, кто сидит дома через веб-сервис. Сюда же еще проблема с тем, что работает только в MSIE, у нас большинство пользуют firefox и chrome, но это хотя бы решается установкой тонкого клиента.
19. blackhole321 759 12.10.17 21:40 Сейчас в теме
(18)
Несомненно, отчасти Вы правы, но лишь отчасти. Ваш подход применим для частного случая, когда запущен один экземпляра клиента 1С.
В случае если пользователь запустит несколько экземпляров или за роутером окажется несколько компьютеров, Ваш подход заставит пользователя совершить кучу действий. И хорошо, если пользователь достаточно квалифицирован, чтобы проделать все то, что Вы описали. И тут уже вопрос вкуса, что более правильно, заставлять пользователя иногда перенаправлять и сравнивать порты или один раз произвести настройку, скажем запуска скрипта при старте компьютера, пробросить порт на роутере и установить тонкого клиента.
Относительно работы только в IE - нельзя об'ять необ'ятное :). Запустить веб-сервер в отдельном потоке внутри компоненты 1С, в браузере, чтобы работало стабильно, требует некоторых усилий :) Скажем закрытие слушателя с последующим открытием на другом порту приводит к исключению, хотя в консольном приложении или обычной библиотеке все работает нормально.
Так,что как я написал выше - это некий компромисс
20. soal 13.10.17 12:57 Сейчас в теме
(19) Запускать на заданном порту не при создании компоненты, а командой StarsServ(port), получающей порт в параметре, если порт занят (отсутствует в списке свободных портов), запустить на свободном порту, а в коде можно будет проверить равен ли фактический порт заданному и уже решать в алгоритме, что дальше делать - отключаться или продолжать работу" - никаких действий от пользователя не надо и сервер гарантированно стартонёт.
Это тоже компромисс, который, тем не менее, повысит применимость компоненты. Тут же выше подобные вопросы уже были (10). Без задания приоритета при назначении порта - эта компонента только игрушка, а для создания стабильного рабочего решения бесполезна.
21. dablack 09.01.18 13:14 Сейчас в теме
Добрый день. Юрий, но может у вас получиться сделать возможность назначать порт при создании компоненты ? Реально рандомный номер порта очень мешает. Вариант предложенный в (20) всех устроит. Или поделитесь/продайте исходники мы сами поправим). Вариант с PowerShell не подходит.
Спасибо.
22. blackhole321 759 09.01.18 15:56 Сейчас в теме
(21)Поищу исходники, но это все пробовалось :) 1С начинает валиться с ошибками, хотя вроде никаких предпосылок. Я поэтому и написал, что это компромиссный вариант
17. blackhole321 759 12.10.17 15:07 Сейчас в теме
(15) В качестве иллюстрации и отправной точки можете попробовать нижеследующий скрипт PowerShell:

# Инициализируем web-сервер

$ВебСлушатель = New-Object System.Net.HttpListener

# По этому url регистрируем порт
# Запрос на регистрацию: http://localhost:8080/НомерПорта
$ВебСлушатель.Prefixes.Add("http://localhost:8080/")

# По этому url принимаем внешние запросы
# Необходимо запускать с правами администратора или настроить через netsh
$ВебСлушатель.Prefixes.Add("http://*:9090/")

$ВебСлушатель.AuthenticationSchemes = 'Anonymous'    
$ВебСлушатель.Start() 

# Порт, который слушает клиент 1С 
$port = 0

# Получаем и обрабатываем web-запросы

while ($ВебСлушатель.IsListening)
{
    $Контекст = $ВебСлушатель.GetContext()
    $UrlЗапроса = $Контекст.Request.Url
    $Ответ = $Контекст.Response
    
    $Результаты = ""

    if ($UrlЗапроса.Port -eq 8080)
    {
        # Регистрируем порт клиента
        $port = $UrlЗапроса.AbsolutePath.ToLower().Replace("/", "")

    }
    elseif ($UrlЗапроса.Port -eq 9090)
    {
        # Формируем строку запроса к клиенту 1С
        $UriЗапросаК1С = "http://localhost:" + $port + $UrlЗапроса.PathAndQuery
        
        # Выполняем запрос. Invoke-Webrequest не доступна в PowerShell 2
        $РезультатыЗапросаК1С = Invoke-WebRequest -Uri $UriЗапросаК1С

        $Результаты = $РезультатыЗапросаК1С.Content

    }
    
    # Возвращаем результат
    $Буфер = [System.Text.Encoding]::UTF8.GetBytes($Результаты)
    $Ответ.ContentLength64 = $Буфер.Length
    $Ответ.AppendHeader("Content-Type","text;charset=utf-8")
    $Ответ.OutputStream.Write($Буфер, 0, $Буфер.Length)
    $Ответ.Close()
 }

Показать


Он запускается на локальной машине, где работает клиент 1С. Запускать надо с правами администратора или разрешить слушать определенный порт обычному пользователю при помощи netsh
Регистрация порта - отправка из 1С веб-запроса http://localhost:8080/НомерПорта
На порт 9090 пробрасываете внешние запросы
Поддерживается только один клиент.
Оставьте свое сообщение
Новые вопросы с вознаграждением
Автор темы объявил вознаграждение за найденный ответ, его получит тот, кто первый поможет автору.

Вакансии

Удаленный консультант-разработчик 1С
Краснодар
зарплата от 60 000 руб. до 60 000 руб.
Полный день



Ведущий программист 1С
Москва
зарплата от 150 000 руб. до 180 000 руб.
Полный день

Руководитель проектов 1С
Москва
Полный день