Веб-сервер многопоточный с обработкой запросов в коде 1С (1C.Net:Предприятие)

Новая идея организации веб-сервера внутри 1С, предложенная в статье, опирается на проверенную временем богатую функциональность .Net Framework. Решение на основе идеи лишены недостатков COM и веб-сервисов 1С. По сравнению с COM http-сервер можно использовать вне локальной сети, поддерживается одновременная обработка нескольких запросов. По сравнению с веб-сервисами 1С решение на базе http-сервера обладает большей гибкостью, так как программист волен сам выбирать формат ответа сервера (в том числе HTML, JSON, графические изображения, RSS и т.д.), а также контролировать при ответе URL-адрес, идентификацию пользователей, коды ошибок, куки, кодировку, осуществлять кеширование. Настройка же http-сервера внутри 1С сводится к простому запуску внешней обработки.

В сентябрьском номере журнала MSDeveloper.ru была опубликована обзорная статья, посвященная технологии 1C.Net:Предприятие и использованию .Net Framework внутри 1С:Предприятие. Данная статья – продолжение, описывающее практическое применение технологии при решении разного рода задач. Метод изначально был разработан для подключения медицинского лабораторного оборудования к 1С:Предприятие 8.2, но может быть использован для подключения любого другого оборудования и организации обменов данными между базами 1С и другими системами. Статья сопровождается готовыми примерами, доступными для работы, расширения и экспериментов.

В процессе автоматизации деятельности предприятия при помощи 1С: Предприятие часто возникают задачи интеграции и обмена с оборудованием и другими сторонними информационными системами, например, банками, веб-сайтами, информационными системами партнеров. Традиционно 1С:Предприятие выступает в качестве потребителя услуг, и реже – в качестве поставщика. До этого момента у разработчиков популярными технологиями при получении информации от 1C были COM и веб-сервисы, которые появились только в версии 8.1.

У обеих технологий (COM и веб-сервисы) есть свои минусы. Главные недостатки заключаются в следующем. COM-технология позволяет в каждый момент времени выполнять только один запрос. Обращение возможно только внутри своей локальной сети. Обработка одновременных запросов для COM возможна, но требует затрат на организацию пула соединений и отладку многопоточного приложения. Веб-сервисы же сложны по настройке и негибкие для программирования: жестко привязаны к SOAP-стандартам. Подключение устройств, обменивающихся простыми пакетами, работающих по http-протоколу, невозможно.

Новая идея организации веб-сервера внутри 1С, предложенная в статье, опирается на проверенную временем богатую функциональность .Net Framework. Решение на основе идеи лишены недостатков COM и веб-сервисов 1С. По сравнению с COM http-сервер можно использовать вне локальной сети, поддерживается одновременная обработка нескольких запросов. По сравнению с веб-сервисами 1С решение на базе http-сервера обладает большей гибкостью, так как программист волен сам выбирать формат ответа сервера (в том числе HTML, JSON, графические изображения, RSS и т.д.), а также контролировать при ответе URL-адрес, идентификацию пользователей, коды ошибок, куки, кодировку, осуществлять кеширование. Настройка же http-сервера внутри 1С сводится к простому запуску внешней обработки.

Описание примера

Пример, приложенный к статье, состоит из двух файлов: http-сервера (внешняя обработка 1С 8.2 HttpServer82) и тестового приложения эмуляции одновременных запросов к серверу (внешняя обработка 1С 8.2 TestHttpServer82). Обе обработки выполнены на основе управляемых форм. По умолчанию оба приложения настроены на работу с портом 8082.

Сервер и тестовое приложение разработаны на 1С:Предприятие 8.2 и используют .Net Framework 4.0 и компонент Elisy .Net Bridge 4. Соответственно, для работы примера требуется установленный .Net Framework 4.0 и версия библиотеки Elisy .Net Bridge v.4.0.2.0 и выше. Elisy .Net Bridge позволяет гармонично использовать классы и технологии .Net Framework на 1С, ведущую роль оставляя 1С.

Для проверки работы достаточно запустить внешнюю обработку HttpServer82.epf из 1С:Предприятие 8.2. Если у вас Windows с включенным UAC, то запустить 1С:Предприятие необходимо под администратором, иначе у приложения не будет достаточно прав на прослушивание запросов.

Внешний вид обработки-примера

Внешняя обработка позволяет задать порт, по которому будет осуществляться прослушивание и число создаваемых потоков для обработки одновременных запросов. По умолчанию установлен порт 8082 и 50 потоков.

После нажатия на кнопку Старт сервер переходит в рабочее состояние и осуществляет обработку запросов на заданный порт. Например, теперь можно обратиться из вашего браузера по адресу http://localhost:8082 и открыть страницу, которую вернет сервер. В запросе же можно передавать параметры, например, так: http://localhost:8082/test?x=1

Результат работы обработки

Для проверки сервера в многопоточном режиме придумана внешняя обработка TestHttpServer82.epf, которая осуществляет одновременный запуск запросов в цикле. В основу обработки для организации параллельной работы положена замечательная технология PLINQ (Parallel LINQ) из .Net framework 4.

Обработка для тестирования работы

Запускать тестовую обработку TestHttpServer82.epf следует из отдельного от сервера сеанса 1С:Предприятие, иначе одновременный запуск в одном сеансе двух обработок приведет к зависанию. В качестве параметров тестового примера выступают адрес запроса, число одновременных запросов и число циклов. По умолчанию запуск алгоритма приведет к 3 циклам обращений по адресу http://localhost:8082 с 20 одновременными запросами (надо отметить, что число одновременных запросов ограничено числом ядер процессора).

Принцип работы

.Net framework предлагает своим разработчикам класс HttpListener, отвечающий за прослушивание http-протокола. Используя HttpListener, вы можете создать прослушивание http-трафика, которое отвечает на http-запросы. Вы можете использовать этот класс только на операционных системах Windows XP SP2 или Windows Server 2003 и выше. Попытка использования класса на более ранних системах вызовет исключение.

Ниже приведен пример кода для 1С, который инициализирует объект типа HttpListener, настраивая его на прослушивание всех URL по порту 8082. При запуске в 1С работа программы приостанавливается, пока не последует запрос на порт, например, из браузера. Как только вы пошлете из браузера запрос, например, http://127.0.0.1:8082/ 1С вернет описанную в программе html-строку.

За что ответственен каждый участок кода, можно понять из комментариев, приведенных внутри исходного кода.

ПодключитьВнешнююКомпоненту("Elisy.NetBridge4");
AddIn = New("AddIn.ElisyNetBridge4");
net = AddIn.GetNet();

Если НЕ net.GetStatic("System.Net.HttpListener","IsSupported") Тогда
Сообщить("Для класса HttpListener нужна ОС Windows XP SP2/2003 и выше");
Возврат;
КонецЕсли;

listener = net.New("System.Net.HttpListener");
listener.Prefixes.Add("http://*:8082/");
listener.Start();

Сообщить("Прослушивание...");

//Метод GetContext блокирует выполнение программы пока ждет запрос.
context = listener.GetContext();
request = context.Request;
// Получить объект ответа
response = context.Response;
// Создать ответ - HTML-строку
responseString = "Ответ от HttpListener";
buffer = net.GetStatic("System.Text.Encoding", "UTF8").GetBytes(responseString);
// Получить поток ответа и записать ответ в него.
response.ContentLength64 = buffer.Length;
output = response.OutputStream;
output.Write(buffer,0,buffer.Length);
// Необходимо закрыть выходной поток и остановить прослушивание
output.Close();
listener.Stop();

Это самый простой пример. Главный смысл простейшего примера в том, что 1С превращается в полнофункциональный http-сервер, а 1С-программист получает инструмент для гибкой настройки ответа с сервера. Он может вернуть его в любом формате (html, рисунок или JSON), затребовать идентификацию пользователя или вообще вернуть ошибку. Но вместе с тем есть недостатки: блокирование всего приложения, обработка только одного запроса. Пример к статье содержит более сложный код, за счет чего устранены недостатки простейшего примера из листинга.

От простого к сложному

В готовый пример вошел видоизмененный код работы с HttpListener, в котором вызов метода listener.GetContext() заменен вызовом асинхронных аналогов listener.BeginGetContext() и listener.EndGetContext(). Кроме этого создаются N отдельных потоков и заложена синхронизация между потоками с вызовом кода-обработки запроса на стороне 1С:Предприятие.

Достоинством предлагаемой реализации http-сервера является возможность одновременной обработки N запросов в разных потоках с передачей логики обработки в метод формы 1С:Предприятие. Пример при каждом запросе возвращает html с описанием источника и URL запроса. Решение очень гибкое, так как все доработки можно делать прямо из конфигуратора 1С. Никакие дополнительные проекты (например, C# или VB.Net) не задействованы.

Пример условно можно разделить на 2 части: код, который выполняется на стороне 1С:Предприятие и код, который выполняется на стороне .Net framework. При этом .Net framework взял на себя все, что нельзя реализовать средствами 1С:Предприятие, например, создание и синхронизацию потоков.

Http-сервер оформлен в виде управляемой формы. При нажатии на кнопку Старт происходит создание объектов классов HttpServer и Helper. Оба класса описываются на C# в макете обработки ИсходныйКод и компилируются «на лету» в обработчике ПриОткрытии формы. Класс Helper отвечает за перенаправление .Net-события в функцию ОбработатьЗапрос на форме 1С и формирование сообщение об ошибке.

Опустив не относящиеся к теме задачи по инициализации формы и вспомогательных классов, следует остановиться на методе ОбработатьЗапрос, который отвечает за возврат результата http-клиенту. Вызывается обработчик из класса Helper, в качестве параметра принимает объект контекста, может возвратить сообщение об ошибке, которое будет возвращено клиенту.

Объект контекста типа HttpListenerContext, передаваемый в метод ОбработатьЗапрос содержит два важных свойства: Request и Response, отвечающие за информацию о запросе и ответе соответственно.

Значение свойств Context.Request в отладчике

Свойство Request позволяет получить параметры и содержимое, переданные клиентом при запросе. Информация о запросе, помещенная в свойство Request содержит такие основные свойства как:

  • AcceptTypes – MIME-типы, поддерживаемые клиентом
  • ContentEncoding – информация о кодировке при ответе
  • Headers – набор заголовков
  • HttpMethod – метод HTTP, определенный клиентом
  • InputStream – поток, содержащий данные тела, пришедшие от клиента
  • IsAuthenticated – булево значение, показывающее идентифицирован ли пользователь
  • IsLocal – значение, показывающее локальный ли запрос (через localhost)
  • QueryString – строка запроса из запроса
  • RawUrl – информация об URL без хоста и порта
  • UrlReferrer – URL ресурса-источник данного перехода
  • UserAgent – информация о агенте-браузере пользователя

Значение свойств Context.Response в отладчике

Через свойство Response осуществляется возврат контента клиенту, передача информации об ошибке или перенаправление. Сопровождаться все может выставлением необходимых заголовков. Многие свойства ответа (Response) схожи со свойствами запроса. Значимые среди них следующие:

  • ContentEncoding – информация о кодировке при ответе
  • Headers – набор заголовков
  • OutputStream – поток, в который будет записан ответ (например, текст Html, XML или байтовый массив изображения)
  • RedirectLocation – свойство отвечает за HTTP-заголовок Location и позволяет перенаправить вызов
  • StatusCode – код статсуса при возврате клиенту,например: 200 (OK), 404 (ресурс не найден)
  • StatusDescription – описание статуса при возврате клиенту

Следующий код метода ОбработатьЗапрос преобразует сформированную строку РезультатHTML с HTML-кодом в набор байт и записывает этот набор байт в выходной поток, который будет возвращен клиенту. Ссылка на выходной поток получена через параметр метода.

ОтветСервера = context.Response;
МассивБайт = net.GetStatic("System.Text.Encoding", "UTF8").GetBytes(РезультатHTML);
ОтветСервера.ContentLength64 = МассивБайт.Length;
ВыходнойПоток = ОтветСервера.OutputStream;
ВыходнойПоток.Write(МассивБайт, 0, МассивБайт.Length);
ВыходнойПоток.Close();

Основой обработки является класс HttpServer, который создает объект HttpListener и нужное число потоков для обработки. При вызове метода Start происходит запуск всех потоков-обработчиков и отдельного потока для работы HttpListener. Благодаря этому, можно продолжать работать с 1С во время работы http-сервера. При поступлении запроса HttpListener помещает запрос в очередь, где каждый запрос последовательно обрабатывает первый свободный поток. При обработке потока срабатывает цепочка вызовов: событие HttpServer.ProcessRequest, обработчик события Helper. HttpServer_ProcessRequest, 1С-функция Форма. ОбработатьЗапрос. Код C# класса HttpServer при запуске 1C из макета ИсходныйКод компилируется «на лету».

_listener.AuthenticationSchemes = authenticationScheme;
_listener.Prefixes.Add(String.Format(@"http://+:{0}/", port));
_listener.Start();
_listenerThread.Start();

for (int i = 0; i < _workers.Length; i++)
{
_workers[i] = new Thread(Worker);
_workers[i].Start();
}

Начало получения запросов происходит в методе HandleRequests до тех пор, пока обработка не прекратится пользователем. При поступлении запроса, запрос передается в метод ContextReady и работа процесса прослушивания продолжается.

private void HandleRequests()
{
while (_listener.IsListening)
{
var context = _listener.BeginGetContext(ContextReady, null);

if (0 == WaitHandle.WaitAny(new[] { _stop, context.AsyncWaitHandle }))
return;
}
}
private void Worker()
{
WaitHandle[] wait = new[] { _ready, _stop };
while (0 == WaitHandle.WaitAny(wait))
{
HttpListenerContext context;
lock (_queue)
{
if (_queue.Count > 0)
context = _queue.Dequeue();
else
{
_ready.Reset();
continue;
}
}

try { ProcessRequest(context); }
catch (Exception e) { Console.Error.WriteLine(e); }
}
}

Заключение

Многопоточный сервер, описанный в статье, по простоте настройки и функциональности превосходит традиционные методы доступа извне к информационным базам 1С:Предприятие 8.х. Это простой по запуску метод, позволяющий одновременно обрабатывать несколько запросов. При этом приложение 1С не блокируется, и пользователь может продолжать работу после запуска сервера.

Основное преимущество предложенного подхода – полная подконтрольность программисту процесса от получения запроса до формирования ответа. Например, на этапе получения запроса может быть выполнен парсинг URL, получена информация о том, как себя идентифицировал пользователь, а также полная информация о клиенте (поддерживаемые языки, записанные куки, заголовки, метод доступа). Ответ же можно вернуть практически любой, начиная от ошибки 404 Not found, заканчивая разными графическими форматами, форматами Word, Excel и популярными форматами на основе XML (JSON, HTML, RSS).

Пример, приложенный к статье, спроектирован так, что его функциональность можно легко расширить. Например, для организации кеша применить System.Web.Caching.Cache класс из .Net framework. А при парсинге URL попробовать поработать с классом RouteCollection из Asp.Net MVC. При создании RSS-ленты вам поможет класс System.ServiceModel.Syndication .SyndicationFeed. А при Json-сериализации обратите внимание на класс System.Runtime.Serialization.Json.DataContractJsonSerializer.

Конкретно для предложенного подхода на данный момент не выявлено явных недостатков. Есть вероятность того, что 1С:Предприятие в силу своих ограничений не сможет обеспечить на своей стороне должного распараллеливания и значительного увеличения производительности. Тем не менее опыты проведенные ранее для 1С:Предприятие 8.2 показали, что в схожем применении 1С достигается увеличение производительности, и 1С работает при этом стабильно.

Необходимо обратить внимание разработчиков еще на несколько моментов. Любая публикация информации в Интернете связана с риском взлома вне зависимости от способа публикации. Но в предложенном способе благодаря гибкости есть больше возможностей противостоять угрозам извне. Например, в запросе теперь доступен IP-адрес клиента, который можно блокировать по каким-то правилам (осуществляя поиск в черном списке локально или в специализированных сервисах). Параметры запроса доступны в виде строк и их можно анализировать на стороне 1С или .Net framework и блокировать опасное содержимое. Кроме этого есть несколько специализированных .Net-библиотек, доступных для решения данной проблемы, которые можно привлечь в 1С, например AntiXSS.

Второй момент заключается в том, что известные методы, в том числе и этот, предоставления услуг со стороны 1С не предназначены для массовых обращений и будут всегда уступать с этой точки зрения профессиональным серверам, например, IIS. При решении таких задач для массового доступа к информационным базам 1С рекомендуется обратить внимание на технологию прямого доступа к данным Elisy Open InfoBase. Более подробно о ней можно узнать в октябрьском выпуске журнала MSDeveloper.ru, ознакомившись со статьей «Elisy Open Infobase — необычно-экономное использование 1С:Предприятие 8 на Asp.Net-хостинге».

55 Comments

  1. SergDi

    очень интересно, но придумать практическое применение не могу…

    Reply
  2. Elisy

    (1) Изначально писался для подключения медицинского лабораторного оборудования, работающего пакетами http. Но, показалось, что применений можно больше найти, например, опубликовать в Интернет как 8.2 )))))

    Reply
  3. sytkosa

    Надо более приближенный пример «для народа». Например какой нибудь приемщик заявок от клиентов

    Reply
  4. oleg_km

    делаем тоже самое но на ActiveX. Планирум применять как личный кабинет клиента или сотрудника: промотр сообщений, электронной почты, остатки, прайсы, наиболее важные отчеты.

    Reply
  5. zavyzka

    Должно быть очень специфическое использование.

    Reply
  6. kandellaster

    а можете ткнуть носом по теме обработки параметров пришедших на сервер в POST запросе?

    Reply
  7. Elisy

    (6) kandellaster,

    Судя по обсуждениям в Интернете нужно использовать Request.InputStream

    В простейшем случае так (код на C#):

    var requestBody = new StreamReader(context.Request.InputStream).ReadToEnd();

    еще предлагается воспользоваться готовым методом HttpUtility.ParseQueryString:

    var nameValuePairs = HttpUtility.ParseQueryString(requestBody, context.Request.ContentEncoding);

    Здесь пример на C# как получить все значения из POST-запроса руками:

    http://blog.mikehacker.net/2006/11/13/httplistener-and-forms/

    Reply
  8. kandellaster

    получилос), спа си бо

    Reply
  9. kandellaster

    и еще созрел такой вопрос немного не по теме но все же)

    в каталоге откуда запускается сервер лежит папка CSS с файлами, в шаблоне прописано их подключение но не подключаются, пробовал копировать их в корень с шаблоном но результат тот же, в какую сторону копнуть?

    Reply
  10. kandellaster

    нашел приблизительное решение http://www.dreamincode.net/forums/topic/215467-c%23-httplistener-and-threading/

    но как то статично все кажется

    Reply
  11. Elisy

    (9) kandellaster,

    и еще созрел такой вопрос немного не по теме но все же)

    в каталоге откуда запускается сервер лежит папка CSS с файлами, в шаблоне прописано их подключение но не подключаются, пробовал копировать их в корень с шаблоном но результат тот же, в какую сторону копнуть?

    Файловая система автоматически с веб-сервером никак не связана. В коде обработки ОбработатьЗапрос нужно отлавливать обращения к ресурсам вида «/mycssfile.css», самостоятельно загружать содержимое из файла и возвращать в ответ.

    Reply
  12. kandellaster

    тобиш это можно сделать средствами 1С ? не прибегая к изменению исходника сервера?

    Reply
  13. Elisy

    (12) kandellaster,

    тобиш это можно сделать средствами 1С ? не прибегая к изменению исходника сервера?

    Да, можно сделать средствами 1С. Гибкость решения это позволяет. Таким же образом можно возвращать рисунки, js-скрипты — всю статику.

    Reply
  14. kandellaster

    действительно все оказалось просто)) спасибо

    Reply
  15. sashocq

    Все-таки непонятна многопоточность. 1С не поддерживает многопоточность внутри одного процесса. И если код с локальными переменными и будет так работать, то запросы к БД — вряд ли.

    Reply
  16. Elisy

    (15) sashocq,

    Все-таки непонятна многопоточность. 1С не поддерживает многопоточность внутри одного процесса. И если код с локальными переменными и будет так работать, то запросы к БД — вряд ли.

    Согласен, что в таком решении 1С-слабое звено и требуются дополнительные исследования. Но как альтернатива громоздким веб-сервисам или для простых операций с оборудованием решение вполне подходит.

    Reply
  17. kandellaster

    ну вот таки на основе вашей разработки пишу в целях самообразования веб-фреймворк с роутами, системой шаблонизации, авторизацией и прочими плюшками

    Reply
  18. kandellaster

    а да и REST сервисами )))

    Reply
  19. Elisy

    (17) Отлично и не только вы заинтересовались. Решение действительно простое и гибкое, подходит для многих применений. Если будут проблемы, пишите здесь. Постараемся подсказать.

    Reply
  20. ja-maik-a

    Каким образом можно в 1с получить то, что содержится в теле Post запроса?

    Reply
  21. Elisy

    (20)

    Каким образом можно в 1с получить то, что содержится в теле Post запроса?

    В посте (7) был уже такой вопрос.

    Следующий код в функции ОбработатьЗапрос считает тело POST-запроса в строку телоЗапроса через StreamReader:

    запрос = context.Request;
    Если запрос.HttpMethod = «POST» тогда
    //Обработка POST-запроса
    входнойПоток = запрос.InputStream;
    считывательПотока = net.New(«System.IO.StreamReader», запрос.InputStream);
    телоЗапроса = считывательПотока.ReadToEnd();
    КонецЕсли;
    

    Показать

    Reply
  22. ja-maik-a

    (21)Да, я прочитал ветку. Просто сначала не понял как вызывать методы классов из 1с.

    Спасибо, все сработало

    Reply
  23. ja-maik-a

    Еще вопрос:

    Возможно ли запустить в одном сеансе 1с два и более http сервера на разных портах?

    Reply
  24. Elisy

    (23) ja-maik-a,

    Возможно ли запустить в одном сеансе 1с два и более http сервера на разных портах?

    Думаю, что возможно. Возможны подходы при решении задачи:

    1. Расположить их на разных формах

    2. Доработать исходный код, чтобы в метод

    public void AddEvent(HttpServer httpServer, object form)

    передавалось также имя функции формы. И на него сослаться в методе HttpServer_ProcessRequest

    Reply
  25. sigum

    Прошу помочь разобраться с ошибкой.

    На windows xp Все работает нормально

    если пытаюсь запустить на windows server 2003 где установлен sharepoint server 3.0, соответвенно SQL-server, IIS-server

    При команде в 1С82 Net.GetStatic(«System.Net.HttpListener», «IsSupported») выдается ошибка:

    {Обработка.HttpServer82.Форма.Форма.Форма(353)}: Ошибка при вызове метода контекста (Start)

    HttpServer.Start(Объект.Порт, net.New(«System.Net.AuthenticationSchemes»).Anonymous);

    по причине:

    Произошла исключительная ситуация (Elisy.NetBridge.dll): System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> System.Net.HttpListenerException: Процесс не может получить доступ к файлу, так как этот файл занят другим процессом

    at System.Net.HttpListener.AddAllPrefixes()

    at System.Net.HttpListener.Start()

    at Elisy.NetBridge.HttpServer.HttpServer.Start(Int32 port, AuthenticationSchemes authenticationScheme)

    — End of inner exception stack trace —

    at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner)

    at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)

    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)

    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

    at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)

    at Elisy.ElisyNetBridge.InvokeMethod_Internal(Object instance, String method, Object[] args)

    at CDispatchExWrapper.InvokeEx(CDispatchExWrapper* , Int32 id, UInt32 __unnamed001, UInt16 wFlags, tagDISPPARAMS* pdp, tagVARIANT* pVarRes, tagEXCEPINFO* pei, IServiceProvider* __unnamed006)

    возможно что объект использует sharepoint, как использовать совместно на одном сервере?

    Reply
  26. Elisy

    (25) sigum,

    Прошу помочь разобраться с ошибкой.

    На windows xp Все работает нормально

    если пытаюсь запустить на windows server 2003 где установлен sharepoint server 3.0, соответвенно SQL-server, IIS-server

    Судя по сообщению об ошибке, ошибка возникает на другой строке:

    HttpServer.Start(Объект.Порт, net.New(«System.Net.AuthenticationSchemes»).Anonymous);

    и http-серверу не нравится значение Объект.Порт. Попробуйте изменить порт прослушивания — должно помочь.

    Иногда зависший процесс 1С не освобождает порт и не дает запустить прослушивание по этому же порту. Нужно убить процесс через диспетчер задач.

    Посмотреть процесс, который занял порт, можно через утилиту: netstat -a -o

    и по PID выйти на процесс.

    Reply
  27. sigum

    Дествительно, используемый порт 8082 был занят Microsoft.offise.server.conversions.launcher.exe.

    Смена порта исключила ошибку.

    Большое спасибо за помощь.

    Reply
  28. Elisy
    Еще такой вопрос:

    object error = _form.GetType().InvokeMember(«ОбработатьЗапрос»,
    System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Public,
    null, _form, new object[] { context });
    

    Понятно, что первый параметр имя процедуры в 1с, а что значат остальные параметры?

    и сколько и каких типов может быть передано параметров в 1с?

    Первый параметр — имя процедуры в 1С, значения в new object[] { context } передаются как параметры процедуры 1С. Т.е. передается context. Можно передать N параметров, например new object[] { context, DateTime.Now } передастся 2й параметр дата. В процедуру 1С нужно добавить 2й параметр. Процедура 1С должна быть экспортной.

    Reply
  29. foxbeast

    Тестируя возможность применения компоненты, наткнулся на проблему с получением значений из коллекции Cookies, пришедших в запросе браузера. Они нужны для создания авторизованных сессий.

    Cookies = ContextRequest.Cookies;  // здесь все хорошо, Cookies — COM объект System.Net.CookieCollection
    Если Cookies.Count > 0 Тогда           // да, больше 0, потому что кука s1 там есть и свойство Count=1
    Если Cookies[«s1»] // а вот тут ругается — говорит, что поле s1 у объекта не обнаружено
    …
    

    Пробовал разные варианты:

    Cookies[0] — «получение элемента по индексу для значения не определено»

    ContextRequest.Cookies(«s1») — возражает, что нет такого метода (а без ContextRequest 1С считает, что я пытаюсь вызвать несуществующую процедуру или функцию)

    Cookies.Item[«s1»] — ошибка при получении значения атрибута контекста

    ну и так далее.

    Я что-то делаю неправильно, или это какой-то баг?

    Reply
  30. foxbeast

    Сработало Cookies.get_Item(«s1»), метод про который MSDN умалчивает, во всяком случае для .NET 4.0.

    Reply
  31. Elisy

    (30) foxbeast,

    Сработало Cookies.get_Item(«s1»), метод про который MSDN умалчивает, во всяком случае для .NET 4.0.

    Действительно, одной из мало документированных возможностей является доступ к индексным свойствам .Net через get_Item и set_Item. Эта альтернатива используется для доступа к сборкам через COM, где нет индексных свойств. В .Net Bridge методы get_Item/set_Item также доступны.

    Reply
  32. адуырщдв

    Интересно, попробуем прикрутить к нашей задаче.

    Reply
  33. diver.sun

    В своё время столкнулся с той же проблемой, обошелся без .net bridge просто сам написал веб сервер в виде внешней компоненты, уже используется для личного кабинета в области продаж авиабилетов. А 1с действительно не многопоточна, обошел эту проблему путем создания внешнего приложения которое уже запускает потоки выполнения 1с. Если есть вопросы в личку.

    Reply
  34. ja-maik-a

    (33) diver.sun, а каждый поток 1с забирает лицензию при таком использовании?

    Reply
  35. diver.sun

    Ну если они на одной машине крутятся…..

    Reply
  36. ja-maik-a

    (35) diver.sun, а запрос по таймауту не отвалится, пока будет ждать загрузки 1с?

    Reply
  37. diver.sun

    Не…..приложение запускает 3 потока 1с, и ждет, регулярно контролируя не отвалилась ли 1с….и готов ли поток выполнения, при поступлении запроса он отправляется в один из свободных потоков. по тайм ауту выполнения запроса или тестового запроса поток выполнения перезапускается…..тоесть каждый запрос не ждет пока 1с запустится..

    Reply
  38. diver.sun

    Выглядит так

    Reply
  39. ja-maik-a

    (38) diver.sun, каким образом передается контекст в 1с (параметры запроса, тип запроса)?

    Reply
  40. diver.sun

    1с запускается как процесс с переопредением потоков ввода вывода. с командной строкой в которой указана обработка которая используя ВК ловит события записи в стандартный поток вводи и может писать в стандартный поток вывода FastCGI

    Reply
  41. ja-maik-a

    А можно ли ознакомиться как-нибудь с кодом? Посмотреть как происходить вызов с командной строки и прием этого вызова в 1с и получение параметров?

    Reply
  42. Makushimo

    Чего-то совсем не понял как это использовать. А хочется.

    Проясните такие вопросы:

    1. Рабочая база 1С может служить нттр-сервером и принимать запросы из вне, правильно?

    2. Из вне в эту базу могут приходить запросы от:

    — сайтов

    — других баз 1С в локальной сети

    — других баз 1С через интернет (при этом публиковать эту базу отдельно не надо)

    верно?

    3. Количество одновременных запросов, которое может принять сервер внутри базы 1С ограниченно?. Каким количеством?

    4. Входящие запросы складываются в очередь. Где эта очередь хранится?

    5. Входящие запросы по очереди обрабатываются последовательно? или в 1С можно использовать фоновые задания для одновременного выполнения сразу нескольких входящих запросов из очереди?

    6. Теоретически все входящие запросы в базе 1С можно как то самому классифицировать и определить обработку каждому из них. Так?

    7. Может ли сама база 1С, которая типо сервер, отправлять несколько параллельных запросов? Сколько?

    8. Можно ли эти компоненты как то срастить с сайтом, например, чтобы он выступал приемщиком-обработчиком запросов, а 1С как бы не причем?

    9. Можете написать от и до пример работы с несколькими запросами сразу:

    — от другой базы 1С из локальной сети

    — от другой базы 1С через интернет

    — 2-3 запроса от сайта

    Именно одновременно. Хочется увидеть как это все разруливать в коде базы 1С, которая типо сервер.

    10. не понятно, каким образом оборудование отправляет запросы в базу 1С, которая типо сервер.

    Reply
  43. yaroslavch

    Статья хорошая, интересная, НО! где брать саму компоненту? Приложенные обработки без неё не работают,

    Reply
  44. Elisy

    (43) yaroslavch,

    Отдельная страница есть для компонента, где можно бесплатную демо-версию скачать:

    http://infostart.ru/public/20035/

    Reply
  45. yaroslavch

    (44) Elisy, Сергей. До смешного доходит. Но ни как в боевом действии не могу попробовать вашу обработку.

    Не взлетают ваши обработки, сначала на длл(Microsoft.СSharp.dll, mscorlib.dll) ругались, переустанавливал фреймворк до 4.6.1

    Теперь ваша компонента выдаёт (на нажатие кнопки старт/стоп):

    {ВнешняяОбработка.HttpServer82.Форма.Форма.Форма(88)}: Ошибка при вызове метода контекста (Stop)

    HttpServer.Stop();

    по причине:

    Произошла исключительная ситуация (Elisy.NetBridge.dll): System.Reflection.TargetInvocationException: Адресат вызова создал исключение. —> System.Threading.ThreadStateException: Поток не запущен.

    в System.Threading.Thread.JoinInternal(Int32 millisecondsTimeout)

    в Elisy.NetBridge.HttpServer.HttpServer.Stop()

    — Конец трассировки внутреннего стека исключений —

    в System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)

    в System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)

    в System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

    в System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)

    в Elisy.ElisyNetBridge.InvokeMethod_Internal(Object instance, String method, Object[] args)

    в CDispatchExWrapper.InvokeEx(CDispatchExWrapper* , Int32 id, UInt32 __unnamed001, UInt16 wFlags, tagDISPPARAMS* pdp, tagVARIANT* pVarRes, tagEXCEPINFO* pei, IServiceProvider* __unnamed006)

    Reply
  46. Elisy

    (45) yaroslavch,

    Как-будто ошибка происходит при попытке остановки сервера. Значит до этого была попытка запуска и тоже должна быть ошибка. Какая?

    Попробуйте запустить 1С с правами Администратора (правый клик на ярлык 1С — Запустить от имени администратора). Возможно, не хватает прав на запуск сервера под обычным пользователем.

    Reply
  47. yaroslavch

    (46) Elisy, спасибо, попробовал запустить с правами администратора — помогло. Но! это не совсем правильно, не могут же все пользователи с Администраторскими правами работать.

    Мне программист знакомый на C# сказал что не хватает прав(в винде) для прослушивания порта. По идее обработку нужно настраивать так, или компоненты, чтобы права были. А вот как это сделать, не давая полных администраторских прав? что зарегистрировать, что прописать?

    так же в обработке пришлось переписать строку, участок кода реализован не оптимально, т.к. компоненты могут лежать по разному адресу:

    Эту:   параметрыКомпилятора.ReferencedAssemblies.Add(«C:Program FilesReference AssembliesMicrosoftFramework.NETFrameworkv4.0Microsoft.CSharp.dll»);
    на эту:
    параметрыКомпилятора.ReferencedAssemblies.Add(«C:Program Files (x86)Reference AssembliesMicrosoftFramework.NETFrameworkv4.0Microsoft.CSharp.dll»);
    

    Reply
  48. Elisy

    (47) yaroslavch,

    так же в обработке пришлось переписать строку, участок кода реализован не оптимально, т.к. компоненты могут лежать по разному адресу:

    Вроде, начиная с .Net 4 ссылки на основные сборки .Net можно указывать без пути. Попробуйте так:

    параметрыКомпилятора.ReferencedAssemblies.Add(«Microsoft.CSharp»);

    Reply
  49. Elisy

    (47) yaroslavch,

    Мне программист знакомый на C# сказал что не хватает прав(в винде) для прослушивания порта. По идее обработку нужно настраивать так, или компоненты, чтобы права были. А вот как это сделать, не давая полных администраторских прав? что зарегистрировать, что прописать?

    Есть вопрос/ответ в Интернете по поводу прав:

    http://stackoverflow.com/questions/4019466/httplistener-access-denied

    Пишут, что права на конкретный адрес можно выставить так:

    netsh http add urlacl url=http://+:80/MyUri user=DOMAINuser

    Reply
  50. yaroslavch

    Сергей. Еще такая проблемка. Пробовали обработку сервера, скрыть. Т.е. сделать невидимой, ну и поставить на автозапуск фоном от пользователя.

    Но столкнулись с проблемой. Если сервер «стартануть», и закрыть 1С, не прекращая работу обработки(обработчик при закрытии не срабатывает), то Ваша компонента зависает, до перезагрузки компьютера или принудительного её завершения. Что достаточно не удобно.

    Есть ли такой функционал, чтобы компонента проверяла свою связь с вызвавшей её обработкой, и если такая связь прерывается (обработка закрыта), то чтобы компонента сама себя закрывала?

    Reply
  51. Elisy

    (50) yaroslavch,

    Есть ли такой функционал, чтобы компонента проверяла свою связь с вызвавшей её обработкой, и если такая связь прерывается (обработка закрыта), то чтобы компонента сама себя закрывала?

    Обработка и компонент внутри 1С живут по правилам COM/OLE. Зависание означает, что на какой-то объект в .Net остались ссылки. По этой причине в форме сделан обработчик ПередЗакрытием, позволяющий корректно освободить ссылки на объекты.

    Если закомментировать этот обработчик, то в обычном режиме при закрытии приложения остается 1С в задачах невидимой. Скорее всего, у вас происходит такая же ситуация. Вам нужно каким-то способом добиться «освобождения» объектов.

    Reply
  52. yaroslavch

    (51) Elisy, я это понимаю, в обработчике перед закрытием, есть код завершения. Но есть бага у 1С, которую я уже наблюдаю на нескольких конфигурациях. Суть в том, что когда закрываешь конфу глобально, файл-выход или «по крестику», то обработки «при закрытии» — НЕ СРАБАТЫВАЮТ.

    И сделать что-то в условиях, когда конфигурацию запрещено менять, ни чего нельзя. В этом и предыстория появления предыдущего вопроса….

    Reply
  53. Elisy

    (52) yaroslavch, я так понял речь идет об ошибке в 1С. В этом случае нужно искать обходной путь. Исследовать нужно. Возможно, сработает другое событие, показывающее окончание работы с формой. Может в новой версии платформы исправили поведение и нужно обновиться. Может, исследовать возможность показа скрытых форм в момент завершения работы.

    И кардинальный способ — сделать отдельно работающее приложение на C#, которое свяжется с 1С другим способом через Elisy Business Connector или COM.

    Reply
  54. ja-maik-a

    Добрый день!

    Можете выложить пример изменения заголовков Headers в ответе?

    Reply
  55. Elisy

    (54) За ответ отвечает класс HttpListenerResponse

    https://docs.microsoft.com/en-us/dotnet/api/system.net.httplistenerresponse?view=netframework-4.7.2

    Модифицировать нужно форму 1С — метод ОбработатьЗапрос(контекст)

    Установка content-type

    ответСервера.Response.ContentType = «application/json; charset=utf-8»;

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *