При организации обмена данными между базами «1С:Предприятие» (например, двумя конфигурациями «Управление нашей фирмой») часто используются Web-сервисы. Однако разработчики нередко сталкиваются с ситуацией, когда один и тот же метод Web-сервиса успешно отрабатывает при ручном вызове из формы, но выдает критическую ошибку «недостаточно фактических параметров» при выполнении в фоновом задании или через регламентное задание.
В этой статье мы подробно проанализируем, почему так происходит, разберем архитектурные особенности платформы 1С и предложим несколько эффективных способов решения этой проблемы.
Рассмотрим типичную ситуацию. В базе-источнике создан Web-сервис с операцией ПолучитьОстаткиНоменклатуры. Предполагается, что метод может принимать код конкретной номенклатуры или работать без него (для получения всех остатков). На стороне сервера 1С код функции выглядит следующим образом:
Функция ПолучитьОстаткиНоменклатуры(Код = Неопределено)
Если Код = Неопределено Тогда
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ЗапасыНаСкладахОстатки.Номенклатура.Код КАК НоменклатураКод,
| ЗапасыНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток
|ИЗ
| РегистрНакопления.ЗапасыНаСкладах.Остатки(&Дата, ) КАК ЗапасыНаСкладахОстатки";
Запрос.УстановитьПараметр("Дата", ТекущаяДата());
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
Возврат Новый ХранилищеЗначения(РезультатЗапроса);
Иначе
// Логика получения остатков по конкретному коду
// ...
КонецЕсли;
КонецФункции
Программист рассчитывает на то, что раз в заголовке функции указано значение по умолчанию Код = Неопределено, то метод можно вызывать без аргументов. Однако при обращении через WSПрокси в регламентном задании платформа выбрасывает исключение. Выясним причину этого поведения.
Разберем важный нюанс: когда вы работаете с Web-сервисом, вы вызываете не просто функцию модуля, а операцию, описанную в WSDL (Web Services Description Language). WSDL — это жесткий контракт. Если в метаданных Web-сервиса в 1С у операции добавлен параметр Код, то в описании интерфейса этот параметр становится обязательным элементом структуры запроса.
Платформа 1С при создании прокси-объекта (WSProxy) строго следует этому контракту. Если в WSDL указано, что метод принимает один параметр, вы не можете вызвать его как Прокси.ПолучитьОстаткиНоменклатуры(). Это фундаментальное отличие от обычного вызова процедур и функций внутри конфигурации. Даже если вы установили свойство параметра «Возможно пустое значение» (nillable), это лишь означает, что вы можете передать в него NULL, но сам параметр в списке аргументов при вызове метода присутствовать обязан.
Самое простое и быстрое решение — привести вызов в регламентном задании в соответствие с требованиями WSDL. Вместо вызова без параметров, необходимо явно передать Неопределено или пустое значение.
Проанализируем пример корректного вызова:
// В коде регламентного задания
Прокси = СформироватьWSПрокси(); // Ваша функция инициализации
// Вместо Прокси.ПолучитьОстаткиНоменклатуры() пишем:
ОстаткиХранилище = Прокси.ПолучитьОстаткиНоменклатуры(Неопределено);
Результат = ОстаткиХранилище.Получить();
Важный момент: Если параметр Код имеет строгий тип данных (например, string в XML), передача Неопределено может вызвать ошибку сериализации. В таком случае рекомендуется передавать пустую строку "", а на стороне сервера выполнять проверку Если ПустаяСтрока(Код) Тогда.
Для чистоты архитектуры и избежания путаницы в параметрах, рассмотрим вариант создания двух разных методов в Web-сервисе. Это исключит неоднозначность при интерпретации параметров.
ПолучитьВсеОстатки() без параметров.ПолучитьОстаткиПоНоменклатуре(Код) с обязательным параметром.В этом случае на стороне сервера обе функции могут вызывать одну общую внутреннюю процедуру, но интерфейс Web-сервиса станет прозрачным и понятным для вызывающей стороны. Это избавит вас от необходимости гадать, что именно передавать, если данные не требуются.
Если вы не хотите менять структуру методов, можно использовать подход со «служебными маркерами». Это часто помогает, когда возникают сложности с типизацией Неопределено в SOAP-запросах.
Рассмотрим пример логики:
// На стороне клиента (регламентное задание)
СлужебныйКод = "ALL_ITEMS";
Результат = Прокси.ПолучитьОстаткиНоменклатуры(СлужебныйКод);
// На стороне сервера (Web-сервис)
Функция ПолучитьОстаткиНоменклатуры(Код)
Если Код = "ALL_ITEMS" Или Код = "" Тогда
// Запрос по всем позициям
Иначе
// Запрос по конкретному коду
КонецЕсли;
КонецФункции
Иногда программист исправляет код, добавляет параметры или меняет их свойства, но ошибка «недостаточно фактических параметров» сохраняется. Проанализируем ситуацию: это может происходить из-за кэширования WSDL-описания на стороне сервера 1С или клиента.
При вызове Web-сервиса через Новый WSОпределения(URL) платформа загружает описание сервиса. Если это описание закэшировалось в сеансе фонового задания, изменения в метаданных не будут подхвачены немедленно. Рекомендуется:
WSПрокси.Если вы хотите реализовать действительно необязательный параметр (который можно вообще не передавать в XML-структуре), рассмотрим использование объектов XDTO. Для этого в пакете XDTO, который используется вашим Web-сервисом, у соответствующего свойства нужно установить значение Минимальное количество (minOccurs) = 0.
В этом случае, если свойство не заполнено, оно полностью исключается из XML-пакета. Однако для этого тип параметра операции Web-сервиса должен быть не примитивным (Строка, Число), а ссылаться на соответствующий ОбъектXDTO. Это более сложный, но профессиональный способ проектирования интерфейсов обмена.
Основная причина ошибки заключается в том, что интерфейс Web-сервиса игнорирует значения по умолчанию, прописанные в коде 1С. Чтобы исправить проблему, всегда передавайте в WSПрокси столько аргументов, сколько описано в операции Web-сервиса, используя Неопределено или пустые значения для тех полей, которые не требуются для текущего запроса.