При интеграции систем на платформе 1С:Предприятие с внешними приложениями или другими базами данных разработчики часто выбирают механизм Web-сервисов (SOAP). Это надежное и стандартизированное решение, однако его настройка требует предельной точности. Малейшее несовпадение в конфигурации пакетов XDTO, URI пространств имен или метаданных веб-сервиса приводит к тому, что клиентское приложение получает пустое значение (Неопределено), порождая трудночитаемые ошибки в коде.
В этой статье мы подробно разберем, почему возникает популярная ошибка «Значение не является значением объектного типа (Name)», проанализируем исходный код интеграции, выявим архитектурные неточности и покажем пошаговый алгоритм их устранения.
Рассмотрим ситуацию, с которой столкнулся разработчик. В базе-источнике опубликован веб-сервис со следующей функцией:
Функция GetOborotyScheta()
ЗаявкаТип = ФабрикаXDTO.Тип("http://192.16.0.176/request", "Schet");
Заявка = ФабрикаXDTO.Создать(ЗаявкаТип);
Заявка.Name = "11111";
Возврат Заявка;
КонецФункции
В базе-приемнике написана обработка для получения этих данных:
Процедура ВыводДанныхИзВебСервиса()
Определение = Новый WSОпределения("http://backup:****@172.16.0.176/buh1c_V831CDEV/ws/Vase/request.1cws?wsdl");
Прокси = Новый WSПрокси(Определение, "http://172.16.0.176/request", "Vase" , "VaseSoap");
Прокси.Пользователь="backup";
Прокси.Пароль="******";
ДанныеЗаявки = Прокси.GetOborotyScheta();
Предупреждение(Строка(ДанныеЗаявки.Name));
КонецПроцедуры
При выполнении этого кода система выдает ошибку:
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(15)}: Значение не является значением объектного типа (Name)
Давайте разберем по шагам, почему переменная ДанныеЗаявки оказалась равна Неопределено, и какие скрытые механизмы платформы 1С повлияли на этот результат.
Обратите внимание на адреса, которые используются в кодовой базе веб-сервиса и обработки:
"http://192.16.0.176/request""http://172.16.0.176/request"Выясним причину этой нестыковки. Начинающие разработчики часто путают сетевой адрес сервера (физический IP-адрес) и URI пространства имен в пакете XDTO. URI пространства имен — это чисто логический уникальный идентификатор (строка), используемый XML-анализатором для разграничения типов данных. Он абсолютно не обязан быть реальной работающей веб-ссылкой и не должен меняться при переносе базы на другой сервер или изменении его IP-адреса.
Если в коде метода ФабрикаXDTO.Тип() указан URI, который хотя бы на один символ отличается от пространства имен, прописанного в свойствах вашего пакета XDTO в конфигураторе, метод вернет Неопределено. Соответственно, попытка выполнить ФабрикаXDTO.Создать(Неопределено) завершится неудачей или вернет пустой объект, который не сможет быть передан клиенту.
Чтобы платформа 1С могла корректно упаковать (сериализовать) сложный объект XDTO и передать его через SOAP-протокол, ей необходимо точно знать его тип еще на этапе разбора WSDL-схемы.
Проанализируем свойства операции веб-сервиса в конфигураторе. Очень часто разработчики совершают ошибку, оставляя свойство «Тип возвращаемого значения» пустым, либо выбирая там базовые типы вроде string или anyType (из стандартного пространства имен XML-схем).
Если функция веб-сервиса возвращает сложный объект (в нашем случае тип Schet), а в свойствах операции возвращаемый тип настроен неверно, платформа не сможет преобразовать объект XDTO в XML-пакет. В результате при вызове метода через WSПрокси на стороне клиента будет получено значение Неопределено.
При изменении структуры XDTO-пакетов или настроек операции веб-сервиса в конфигураторе изменения могут не вступать в силу на клиенте. Почему это происходит?
Публикация веб-сервиса происходит на стороне веб-сервера (IIS или Apache). Эти серверы очень жестко кэшируют файлы описания SOAP-сервисов (файлы с расширением .1cws и их схемы WSDL). Даже если вы обновили конфигурацию базы данных и перезапустили сеанс 1С, веб-сервер может продолжать отдавать клиентам старую структуру схемы. Клиент обращается к методу по устаревшим правилам, не находит нужных свойств и возвращает Неопределено.
Давайте детально разберем, как исправить все вышеперечисленные архитектурные проблемы, чтобы восстановить работоспособность нашего интеграционного решения.
Откажитесь от использования динамических IP-адресов в качестве пространств имен XDTO-пакетов. Задайте вашему пакету XDTO постоянное, уникальное символическое имя.
Например, в свойствах пакета XDTO в конфигураторе установите:
ПространствоИмен: http://www.mycompany.ru/buh/request
После этого скорректируйте код создания объекта в модуле веб-сервиса:
Функция GetOborotyScheta()
// Используем жестко заданное пространство имен, независимое от IP сервера
ЗаявкаТип = ФабрикаXDTO.Тип("http://www.mycompany.ru/buh/request", "Schet");
Если ЗаявкаТип = Неопределено Тогда
ЗаписатьЛогСобытий("Не удалось инициализировать тип 'Schet'. Проверьте XDTO-пакет!");
Возврат Неопределено;
КонецЕсли;
Заявка = ФабрикаXDTO.Создать(ЗаявкаТип);
Заявка.Name = "11111";
Возврат Заявка;
КонецФункции
Откройте свойства операции веб-сервиса в дереве метаданных конфигурации:
GetOborotyScheta).http://www.mycompany.ru/buh/request.Schet.После внесения изменений в конфигурацию базы данных обязательно выполните следующие действия:
iisreset. Если используется Apache, перезапустите соответствующую службу Windows или процесс демона в Linux.WSОпределения платформа кэширует WSDL локально. Чтобы этого избежать при отладке, можно временно отключать кэширование или использовать динамическое имя файла.На стороне вызывающей системы (клиента) мы должны использовать фабрику XDTO конкретного прокси-объекта, а не глобальную фабрику конфигурации. Это защитит нас от несоответствия версий метаданных. Перепишем клиентскую процедуру:
Процедура ВыводДанныхИзВебСервиса()
// Подключаемся к опубликованному веб-сервису
ПутьКWsdl = "http://172.16.0.176/buh1c_V831CDEV/ws/Vase/request.1cws?wsdl";
Попытка
Определение = Новый WSОпределения(ПутьКWsdl, "backup", "******");
// Важно: Пространство имен в WSПрокси должно строго соответствовать пространству имен веб-сервиса в метаданных!
Прокси = Новый WSПрокси(Определение, "http://www.mycompany.ru/buh/request", "Vase", "VaseSoap");
Прокси.Пользователь = "backup";
Прокси.Пароль = "******";
// Получаем данные от сервера
ДанныеЗаявки = Прокси.GetOborotyScheta();
Если ДанныеЗаявки = Неопределено Тогда
ВызватьИсключение "Сервер вернул пустое значение. Проверьте отладчиком внутреннее состояние серверного метода.";
КонецЕсли;
// Выводим полученное значение свойства
Предупреждение("Получено значение свойства Name: " + Строка(ДанныеЗаявки.Name));
Исключение
ЗаписьЖурналаРегистрации("Интеграция.WebСервисы", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Произошла ошибка при обращении к Web-сервису: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
КонецПроцедуры
Если веб-сервис по-прежнему возвращает пустые данные, нам поможет серверная отладка. По умолчанию отладка веб-сервисов (которые исполняются в контексте фоновых заданий веб-сервера) отключена. Давайте включим её:
-debug.GetOborotyScheta() в модуле веб-сервиса.ФабрикаXDTO.Тип() корректное описание типа или инициализирует его как Неопределено.Применяя предложенные правила организации пространств имен и контроля типов, вы навсегда избавитесь от неожиданных ошибок сериализации в ваших интеграционных механизмах 1С.