При интеграции 1С с внешними системами часто используется механизм Web-сервисов (SOAP). Распространенный сценарий — вызов операций веб-сервиса из скриптов PowerShell с помощью командлета New-WebServiceProxy. Однако иногда разработчики и системные администраторы сталкиваются с ситуацией, когда вызов метода с динамически сформированной датой возвращает пустой или некорректный результат, в то время как при передаче жестко заданной строки (например, '03.10.2017') всё работает исправно.
Рассмотрим подробно причины возникновения этой проблемы и разберем варианты ее решения как на стороне PowerShell, так и в конфигурации 1С.
Проанализируем исходный код вызова веб-сервиса в PowerShell:
$svc = New-WebServiceProxy –Uri 'http://server/base/ws/PersonnelData?wsdl'
$currDate = (Get-Date -DisplayHint Date -Format dd.MM.yyyy).ToString()
$UserArray = $svc.ReadStaffTable($currDate)
В данном примере выполняется получение текущей даты в формате dd.MM.yyyy с последующей передачей переменной $currDate в метод ReadStaffTable.
Выясним, что происходит на стороне 1С. В конфигураторе в дереве метаданных у веб-сервиса PersonnelData для операции ReadStaffTable установлен параметр QueryData с типом данных string (строка). В модуле веб-сервиса обработка входящего параметра выглядит следующим образом:
Функция ReadStaffTable(QueryData) Экспорт
ДатаЗапроса = СтрокаВДату("dd.MM.yyyy", СтруктураПараметровОперацийWebСервисов.QueryData);
// Дальнейшее формирование выборки данных
КонецФункции
Функция ожидает строго определенный формат строки с точками в качестве разделителей: 03.10.2017. Если строка не соответствует шаблону dd.MM.yyyy, алгоритм сбросит значение ДатаЗапроса в пустую дату ('0001-01-01'), и запрос к базе данных вернет некорректные результаты.
Почему же динамически сформированное значение $currDate перестает работать, а строка '03.10.2017' отрабатывает успешно?
Причина кроется в особенностях работы среды .NET Framework, на которой базируется PowerShell. В строках форматирования .NET символ точки . является не буквальным символом, а специальным управляющим символом разделителя дат (DateSeparator).
Если скрипт PowerShell выполняется на сервере с англоязычной локалью (например, en-US), .NET автоматически заменяет точку на разделитель, принятый в этой системной культуре — символ слэша /. В результате выражение (Get-Date -Format "dd.MM.yyyy").ToString() возвращает строку "03/10/2017" вместо "03.10.2017".
Когда эта строка поступает в 1С, вызов СтрокаВДату("dd.MM.yyyy", ...) не может разобрать дату со слэшами и сбрасывает ее в пустую. При передаче строкового литерала '03.10.2017' механизм форматирования .NET не задействуется, и строки передаются с точками напрямую.
Чтобы гарантировать передачу точек в строке даты независимо от локали операционной системы, рассмотрим несколько способов экранирования разделителя в PowerShell.
Способ 1. Экранирование символа разделителя кавычками
Заключим точки в одинарные кавычки внутри управляющей строки формата. В этом случае .NET воспримет их как буквальные символы:
$currDate = (Get-Date).ToString("dd'.'MM'.'yyyy")
$UserArray = $svc.ReadStaffTable($currDate)
Способ 2. Использование инвариантной культуры (InvariantCulture)
Форматирование с явно указанной нейтральной культурой исключает влияние региональных настроек Windows:
$currDate = (Get-Date).ToString("dd.MM.yyyy", [System.Globalization.CultureInfo]::InvariantCulture)
$UserArray = $svc.ReadStaffTable($currDate)
Способ 3. Явное приведение типа переменной
Для предотвращения передачи сложных объектов в SOAP-запрос укажем тип [string] при объявлении переменной:
[string]$currDate = (Get-Date).ToString("dd'.'MM'.'yyyy")
$UserArray = $svc.ReadStaffTable($currDate)
Разберем, как сделать работу Web-сервисов более надежной на стороне платформы 1С:
string для параметров, содержащих дату, рекомендуется задавать стандартный тип XML Schema date (xs:date) в свойствах операции Web-сервиса. В этом случае платформы 1С и .NET автоматически берут на себя сериализацию в формат ISO (yyyy-MM-dd).Invoke-RestMethod.