При разработке интеграций на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда код, успешно работающий в обычной обработке, выдает ошибку при выполнении через Web-сервис. Одной из самых коварных является ошибка «Не удалось записать» при попытке фиксации данных в регистре сведений. Разберем подробно, почему это происходит и как найти «невидимую» причину сбоя.
Первое, что мы должны понять: выполнение кода в модуле Web-сервиса происходит в неинтерактивном сеансе. В отличие от обычного пользователя, запускающего программу через клиентское приложение, сеанс Web-сервиса имеет ряд ограничений:
ПараметрыСеанса.ТекущийПользователь, запись завершится ошибкой, так как параметр пуст.USR1CV8) должен иметь физический доступ к временным папкам на сервере.Как показывает практика и обсуждение на форумах, основной причиной скрытых ошибок записи являются Подписки на события. Даже если в модуле самого регистра сведений чисто, система может выполнять код в других модулях перед записью. Рассмотрим ситуацию, когда в конфигурации (например, «Охрана труда») используется система защиты или специализированная библиотека.
Проанализируем подписку ПолныеПраваРегистры. Если источник подписки — РегистрСведенийНаборЗаписей, а событие — ПередЗаписью, то при каждом вызове метода Записать() управление передается в обработчик подписки. Если этот обработчик находится в защищенном модуле без исходного кода или требует специфической лицензии, которая «не подхватилась» в сеансе Web-сервиса, запись будет заблокирована платформой.
В примере автора используется МенеджерЗаписи. Несмотря на его удобство для простых операций, для Web-сервисов и фоновых заданий более надежным считается использование объекта НаборЗаписей. Это позволяет более гибко управлять фильтрами и транзакциями.
Рассмотрим правильный подход к записи через НаборЗаписей с установкой привилегированного режима:
Функция ЗаписатьВРегистрИнтеграции(ДанныеСтруктура) Экспорт
Результат = "Успешно";
// Включаем привилегированный режим, чтобы обойти RLS и проверку прав
УстановитьПривилегированныйРежим(Истина);
Набор = РегистрыСведений.IntegrationServiceDocuments.СоздатьНаборЗаписей();
// Обязательно устанавливаем отбор по измерениям (в данном случае UID)
Набор.Отбор.UID.Установить(Новый УникальныйИдентификатор());
НоваяЗапись = Набор.Добавить();
НоваяЗапись.UID = Набор.Отбор.UID.Значение;
НоваяЗапись.ДатаДокумента = ТекущаяДата();
НоваяЗапись.ТипДокумента = Перечисления.IntegrationDocumentType.Организация;
НоваяЗапись.СтатусДокумента = Перечисления.IntegrationDocumentStatus.Новый;
Попытка
Набор.Записать();
Исключение
// Здесь мы получим подробное описание ошибки
Результат = ОписаниеОшибки();
// Логируем ошибку в Журнал регистрации, так как WS может «проглотить» детали
ЗаписьЖурналаРегистрации("Web-сервис.ЗаписьРегистра",
УровеньЖурналаРегистрации.Ошибка, , , Результат);
КонецПопытки;
УстановитьПривилегированныйРежим(Ложь);
Возврат Результат;
КонецФункции
Выясним причину, по которой Записать() может молча падать. Если в конфигурации используется RLS (Record Level Security), платформа при записи проверяет условия доступа. Эти условия часто завязаны на параметры сеанса. В Web-сервисе процедура УстановкаПараметровСеанса в Модуле сеанса вызывается автоматически, но она должна корректно отрабатывать для пользователя, под которым авторизован Web-сервис.
Проверьте следующий код в Модуле сеанса:
Процедура УстановкаПараметровСеанса(ТребуемыеПараметры)
// Если параметры не инициализированы для Web-сервиса,
// запись в регистры с контролем доступа будет невозможна.
Если ТребуемыеПараметры = Неопределено Тогда
// Инициализация всех параметров
КонецЕсли;
// Пример заполнения критичного параметра
Если НуженПараметр("ТекущийПользователь", ТребуемыеПараметры) Тогда
ПараметрыСеанса.ТекущийПользователь = Пользователи.АвторизованныйПользователь();
КонецЕсли;
КонецПроцедуры
Если Журнал регистрации молчит, а ошибка Не удалось записать сохраняется, проанализируем ситуацию на уровне СУБД. Проблема может заключаться в конфликте блокировок или нарушении уникальности индекса, которое платформа не может интерпретировать в контексте WS.
Для этого настройте Технологический журнал (logcfg.xml) на сбор событий EXCP (исключения) и DBMSSQL (запросы к базе данных). В файлах логов вы увидите реальную причину отказа SQL-сервера. Часто оказывается, что тип данных, передаваемый через Web-сервис (например, слишком длинная строка или некорректная дата), не соответствует метаданным регистра.
Подведем итоги и сформируем план действий для решения проблемы:
Подписки на события, где источником выступает ваш регистр. Если обработчик находится в закрытом модуле (как ПолныеПраваРегистры), попробуйте выполнить запись внутри блока УстановитьПривилегированныйРежим(Истина).МенеджерЗаписи в пользу НаборЗаписей. Это более «чистый» способ работы с данными на стороне сервера.Исключение.
НачатьТранзакцию();
Попытка
РегНабор.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
// Обработка ошибки
КонецПопытки;
Важно: При работе с Web-сервисами всегда логируйте ошибки в ЗаписьЖурналаРегистрации, так как клиентское приложение, вызывающее сервис, может получить лишь общий код ошибки 500, в то время как сервер 1С хранит детальную информацию о причине сбоя в своих логах.