Как исправить ошибку «Значение не является значением объектного типа (Записать)» в веб-клиенте 1С при работе с файлами?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке функционала загрузки файлов в 1С программисты часто сталкиваются с ситуацией, когда код идеально работает в тонком или толстом клиенте, но выдает фатальную ошибку в веб-клиенте. Типичный сценарий: пользователь выбирает файл, программа помещает его во временное хранилище, а при попытке сохранить этот файл на сервере возникает ошибка: «Значение не является значением объектного типа (Записать)». Рассмотрим подробно, почему это происходит и как правильно организовать работу с файлами, чтобы она была стабильной во всех типах клиентов.

Проанализируем ситуацию: почему возникает ошибка?

Разберем механизм возникновения ошибки. В коде на сервере обычно присутствует цикл обработки загруженных файлов, который выглядит следующим образом:


Пока Выборка.Следующий() Цикл
    ДанныеИзХранилища = ПолучитьИзВременногоХранилища(Выборка.Хранение);
    РасширениеФайла = ПолучитьРасширениеИмениФайла(Выборка.Имя);
    ИмяПромежуточногоФайла = ПолучитьИмяВременногоФайла(РасширениеФайла);
    
    // Именно здесь возникает ошибка, если ДанныеИзХранилища = Неопределено
    ДанныеИзХранилища.Записать(ИмяПромежуточногоФайла); 
    
    // Далее следует логика обработки файла...
КонецЦикла;

Ошибка «Значение не является значением объектного типа (Записать)» однозначно указывает на то, что метод ПолучитьИзВременногоХранилища() вернул Неопределено вместо ожидаемого объекта типа ДвоичныеДанные. Следовательно, по адресу, указанному в переменной Выборка.Хранение, данных в хранилище уже нет. Выясним причину, по которой данные исчезают именно в веб-клиенте.

Особенности времени жизни данных во временном хранилище

В платформе 1С существует строгий регламент очистки временного хранилища. Время жизни данных зависит от того, какой идентификатор был передан при помещении данных (метод ПоместитьВоВременноеХранилище или НачатьПомещениеФайлов):

  1. Без указания идентификатора: Данные живут только в течение одного серверного вызова. Как только управление возвращается на клиента, данные удаляются.
  2. С идентификатором формы (УИД формы): Данные сохраняются до тех пор, пока открыта форма, чей идентификатор был указан.
  3. С идентификатором сеанса: Данные живут до завершения сеанса пользователя.

Почему в тонком клиенте это работает, а в веб-клиенте нет? Тонкий клиент более «терпим» к контексту выполнения. Однако веб-клиент работает через HTTP-протокол, где взаимодействие клиента и сервера строго разделено на короткие сессии. В веб-клиенте механизмы оптимизации памяти сервера работают агрессивнее: если файл был помещен во временное хранилище без привязки к форме, сервер может очистить его сразу после завершения асинхронной операции загрузки, не дожидаясь следующего шага вашего алгоритма.

Решение проблемы: привязка к УИД формы

Рассмотрим правильный способ вызова диалога выбора и помещения файлов на клиенте. Основная задача — явно указать платформе, что данные должны храниться до закрытия текущей формы. Для этого в методе НачатьПомещениеФайлов (или ПоместитьФайл в старых версиях) необходимо заполнить четвертый параметр — УникальныйИдентификаторФормы.

Посмотрим на исправленный пример кода на клиенте:


&НаКлиенте
Процедура ЗагрузитьФайлы()
    
    ПриЗавершении = Новый ОписаниеОповещения("ПоместитьФайлыЗавершение", ЭтотОбъект);
    ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    ДиалогОткрытияФайла.МножественныйВыбор = Истина;
    
    // КРИТИЧЕСКИ ВАЖНЫЙ МОМЕНТ:
    // Четвертый параметр - ЭтаФорма.УникальныйИдентификатор
    // Это гарантирует, что файл не исчезнет из хранилища в веб-клиенте.
    
    НачатьПомещениеФайлов(ПриЗавершении, ДиалогОткрытияФайла, Истина, ЭтаФорма.УникальныйИдентификатор);

КонецПроцедуры

После этого в процедуре обработки завершения загрузки мы получаем массив структур, где в поле Хранение будет содержаться адрес во временном хранилище, который теперь «привязан» к форме и будет доступен на сервере в любой момент, пока форма открыта.

Оптимизация серверного кода: работа с ТЗ и запросами

Разберем еще один важный аспект, который часто встречается в подобных задачах. Если вы передаете таблицу значений (ТЗ) с адресами файлов на сервер для последующей обработки, старайтесь избегать лишних манипуляций. В исходном коде автора использовался запрос к временной таблице, созданной из ТЗ. Хотя это допустимо, для поиска строк в локальной таблице значений эффективнее использовать метод НайтиСтроки().

Проанализируем улучшенный вариант серверного кода, который исключает создание временных файлов на диске (что также может быть ограничено правами доступа в веб-клиенте):


&НаСервере
Процедура СохранитьФайлыНаСервере(УИДСтроки)
    
    // Вместо сложного запроса к ТЗ формы, используем поиск
    ПараметрыОтбора = Новый Структура("УИДСтроки", УИДСтроки);
    НайденныеСтроки = ФайлыСтрокТЧ.НайтиСтроки(ПараметрыОтбора);
    
    Для Каждого СтрокаФайла Из НайденныеСтроки Цикл
        
        // Получаем данные
        Данные = ПолучитьИзВременногоХранилища(СтрокаФайла.Хранение);
        
        Если Данные = Неопределено Тогда
            ЗаписьЖурналаРегистрации("ОшибкаЗагрузки", УровеньЖурналаРегистрации.Ошибка,,, 
                "Не удалось получить данные по адресу: " + СтрокаФайла.Хранение);
            Продолжить;
        КонецЕсли;
        
        // Рекомендуется использовать методы БСП для добавления файлов, 
        // которые умеют работать напрямую с ДвоичнымиДанными или адресом хранилища
        ПараметрыФайла = РаботаСФайлами.ПараметрыДобавленияФайла();
        ПараметрыФайла.Автор = ПараметрыСеанса.ТекущийПользователь;
        ПараметрыФайла.ИмяБезРасширения = СтрокаФайла.Имя;
        
        // Метод ДобавитьФайл может принимать адрес хранилища напрямую
        РаботаСФайлами.ДобавитьФайл(ПараметрыФайла, СтрокаФайла.Хранение);
        
    КонецЦикла;
    
КонецПроцедуры

Дополнительные рекомендации для веб-клиента

При работе в веб-браузере следует учитывать еще несколько нюансов:

Подводя итог: главная причина ошибки «Значение не является значением объектного типа (Записать)» — это преждевременная очистка временного хранилища. Всегда передавайте ЭтаФорма.УникальныйИдентификатор при загрузке файлов, и ваше решение будет стабильно работать в любом браузере и тонком клиенте.

← На главную