Двоичный FI-счёт: две строки1050, своё DTD и настоящая ссылка на сущность

Учебные задачи

Полный серверный memory workflow: собственный typed FI writer → actual binary → собственный typed reader → проверка реального DTD/cursor/reference и двух числовых строк. Отдельно показан честный бизнес-отказ без цены, затем повторное полное чтение исходного пакета.

Где и как запускать

Полный серверный общий модуль собственной новой пустой FileCF8.5.1.1343. Own thick managed form вызывает серверный memory FI workflow; type/memory intersection SERVER, runtime0.

Подготовка

  1. Задача урока — передать свой счёт в двоичном формате Fast Infoset и проверить результат чтения, а не только наличие байтов. BOOK:3×250=750; TEA_:2×150=300. Ожидаются две реальные строки, количество5 и сумма1050. Примечание содержит ссылку на единственную собственную parsed entity memo. Это не JSON, не обмен Avito и не импорт рабочей базы.

  2. Вручную создайте НОВУЮ пустую файловую ИБ платформы8.5.1.1343 строго по пути C:\1C85_OwnFIInvoice\e61bfaa6-a820-41d9-adce-0da258601ffc\Base. Если он уже занят, остановитесь. UUID каталога — только учебная метка пути, не UUID базы. Здесь каталог, ИБ, учётная запись и файлы FI фактически не создавались.

  3. В Конфигураторе задайте имя конфигурации УчебныйСчетFastInfoset85, основной режим УправляемоеПриложение, режим совместимости НеИспользовать. Нужны ровно один общий модуль, одна управляемая общая форма и одна роль УчебныйАдминистратор85. Прикладных объектов, макетов, параметров сеанса и расширений нет.

  4. Создайте только в своей новой учебной ИБ одного реального пользователя УчебныйАдминистратор85. В собственной роли разрешите Администрирование и запуск толстого управляемого клиента; назначьте роль этому пользователю. Войдите им в один сеанс. Native ПолучитьПользователей требует административного права. Код получает настоящий UUID текущего пользователя и сравнивает с единственным native пользователем; ручного UUID-placeholder нет.

  5. Общие → Общие модули → УчебныйПакетСчетаFI85: Глобальный Нет; Сервер Да; оба клиента Нет; Внешнее соединение Нет; Вызов сервера Нет; Привилегированный Нет; Повторное использование возвращаемых значений НеИспользовать. Вставьте основной код целиком. moduleOwner=ОбщийМодуль. Экспортируется только ВыполнитьСвойУрок85; private helpers не являются загрузчиком произвольных чужих байтов.

  6. Общие → Общие формы → СчетFastInfoset85: создайте управляемую общую форму. Реквизиты Остановка85 типа Булево с исходным значением Ложь и Протокол85 типа Строка неограниченной длины. Протокол85 выведите полем ввода: ТолькоПросмотр Да, многострочный режим Да, удобная высота. Это только отображение готового серверного протокола.

  7. На вкладке Команды собственной формы создайте команду Проверить85, назначьте Действие=Проверить85, перетащите её на форму как кнопку с заголовком «Проверить свой FI-счёт». Вставьте целиком поддерживающий модуль формы. Не вызывайте обработчик вручную и не заменяйте серверный код клиентским.

  8. Вставьте поддерживающий модуль управляемого приложения целиком. Реальное событие ПриНачалеРаботыСистемы без параметров откроет собственную общую форму. Обновите только свою новую конфигурацию базы; вручную запустите её толстым управляемым клиентом8.5.1.1343. Здесь проверка конфигурации и запуск 1С не выполнялись.

  9. Нажмите собственную кнопку один раз. Если native FI reader не сохранит ожидаемый DTD, не предоставит объявление или ссылка не будет отдельным native узлом, урок остановится. Это честная граница будущего ручного опыта: отсутствующий native результат нельзя заменить строкой XML, искусственным node или подготовленным счётчиком.

  10. При успехе изучите оба положительных полных чтения и отдельный бизнес-отказ. В отрицательном собственном пакете у TEA_ отсутствует price; фактические Цена/Сумма второй строки остаются Неопределено, сумма прочитанной первой строки750, количество5. Это не успешный счёт1050 и не native DTD validation. После него читается исходный положительный пакет ещё раз.

  11. Вся работа FI выполняется на сервере. Хотя некоторые страницы отдельных методов перечисляют тонкий клиент, сам тип и memory SetBinaryData/Close доступны на сервере, толстом клиенте и внешнем соединении. Пересечение контекстов, а не отдельная широкая строка доступности, задаёт этот серверный workflow.

  12. Настоящие фабрики: Новый ЗаписьFastInfoset без аргументов; УстановитьДвоичныеДанные() включает memory mode. Закрыть() возвращает ДвоичныеДанные или Неопределено, поэтому нужен actual type/size guard. Затем новый ЧтениеFastInfoset получает именно возвращённые данные методом УстановитьДвоичныеДанные(Данные). Файлы и потоки не подставляются.

  13. ЗаписатьТипДокумента использует ровно два обязательных аргумента: имя invoice и своё внутреннее подмножество. В literal DTD только <!ENTITY memo "OWN_INVOICE_85">; нет внешнего подмножества, SYSTEM/PUBLIC, неразбираемых сущностей, нотаций, файлов или URL. Это не универсальный безопасный импорт чужого DTD.

  14. Перед сменой курсора проверяются фактические DTD Имя=invoice и Значение=весь собственный internal subset. Затем ПервоеОбъявление возвращает actual Булево, читается настоящий ТипУзлаXML.Сущность; СледующееОбъявление также проверяется как Булево. Объявлений ровно1. Generic Имя не документирует имя declaration Сущность — код НЕ выдаёт его за доказанный memo. Ownership задаётся собственным exact DTD text и единственным реальным объявлением.

  15. Вызов Прочитать после обхода объявления прерывает чтение DTD и идёт на следующий узел по native контракту. Внутри declaration-loop нет второго Прочитать, которое могло бы пропустить root. Count нельзя получить из подсчёта текста <!ENTITY в строке.

  16. ИмяНотации/ПубличныйИдентификатор/СистемныйИдентификатор readonly. Они читаются только на настоящих DTD/Entity/EntityReference узлах. Для своей внутренней parsed entity ожидаются пустые значения; непустые поля вызывают отказ. ИмяНотации описывает external unparsed entity, а не любое текстовое имя. Для отсутствующего идентификатора native docs обещают пустую строку.

  17. ЗаписатьСсылкуНаСущность("memo") не возвращает объект. При чтении требуются actual EntityReference, его native Имя=memo и одно реальное наблюдение. Это не утверждение о раскрытии сущности: ТекстПримечания берётся только из настоящего Text event, если он появится; literal значение не подставляется вместо отсутствующего текста. Если вместо reference пришёл иной протокол, fail-stop.

  18. Из каждого actual item читаются sku/quantity/price. Цена не превращается из Неопределено в0; собственный негативный вариант возвращает бизнес-результат Принят=Ложь с конкретной причиной. Конструкторы, повреждённый FI, неизвестные узлы, неверный DTD, ошибка 1С или ресурсов вызывают исключение; catch никогда не объявляет такую ошибку ожидаемым бизнес-успехом.

  19. Оба положительных чтения идут доEOF нового reader из тех же фактических байтов. Сравниваются не только количество и total, но обе реальные строки с артикулом/количеством/ценой/суммой, DTD/declaration/reference counts и наблюдённый текст. Точные FI-байты разных кодировщиков не сравниваются и побитовое сохранение не обещается.

  20. Остановка85 удерживается и на клиентской, и на серверной границе. При серверном исключении состояние формы может не синхронизироваться, поэтому клиент отдельно ставит свой sticky flag. После частичного отказа нет retry/rollback/автоматической подстановки. Закройте собственную форму и прочитайте фактическую диагностику.

  21. RuntimeVerified=False. Здесь выполнены только авторство и статические/native-source проверки; запуск1С, native FI сохранение DTD, compile, DB/UI/сеть/файлы/печать/provisioning/backup0. Числа1050/5 и наличие entity/reference — ожидаемый будущий ручной протокол, не измеренный результат.

Функция ПроверитьСвойСтенд85()
    Если СтрокаСоединенияИнформационнойБазы() <> "File=""C:\1C85_OwnFIInvoice\e61bfaa6-a820-41d9-adce-0da258601ffc\Base"";" Тогда
        ВызватьИсключение "Только собственная новая учебная файловая ИБ";
    КонецЕсли;
    Если Метаданные.РежимСовместимости <> Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Тогда
        ВызватьИсключение "Не совпали своя конфигурация и точная платформа";
    КонецЕсли;
    Если Метаданные.ОбщиеМодули.Количество() <> 1 Или Метаданные.ОбщиеМодули.Найти("УчебныйПакетСчетаFI85") = Неопределено
        Или Метаданные.ОбщиеФормы.Количество() <> 1 Или Метаданные.ОбщиеФормы.Найти("СчетFastInfoset85") = Неопределено
        Или Метаданные.Роли.Количество() <> 1 Или Метаданные.Роли.Найти("УчебныйАдминистратор85") = Неопределено Тогда
        ВызватьИсключение "Нужны только свои общий модуль, форма и роль";
    КонецЕсли;
    Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0
        Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0
        Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0
        Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0
        Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0
        Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0
        Или Метаданные.Обработки.Количество() <> 0 Или Метаданные.Отчеты.Количество() <> 0
        Или Метаданные.Константы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0
        Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Или Метаданные.ХранилищаНастроек.Количество() <> 0
        Или Метаданные.ОбщиеМакеты.Количество() <> 0 Или Метаданные.ПараметрыСеанса.Количество() <> 0 Тогда
        ВызватьИсключение "Прикладная схема этого собственного урока должна быть пустой";
    КонецЕсли;
    Если РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.БазаДанных).Количество() <> 0
        Или РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансАктивные).Количество() <> 0
        Или РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансОтключенные).Количество() <> 0 Тогда
        ВызватьИсключение "В своём учебном стенде не должно быть расширений";
    КонецЕсли;
    Текущий = ПользователиИнформационнойБазы.ТекущийПользователь();
    Пользователи = ПользователиИнформационнойБазы.ПолучитьПользователей();
    Если Текущий = Неопределено Или Пользователи.Количество() <> 1 Тогда
        ВызватьИсключение "Нужен единственный собственный реальный пользователь ИБ";
    КонецЕсли;
    Если Текущий.Имя <> "УчебныйАдминистратор85" Или Пользователи[0].УникальныйИдентификатор <> Текущий.УникальныйИдентификатор Тогда
        ВызватьИсключение "Не совпал реальный UUID пользователя своей ИБ";
    КонецЕсли;
    Возврат Строка(Текущий.УникальныйИдентификатор);
КонецФункции

Функция СвоеПодмножество85()
    Возврат "<!ENTITY memo ""OWN_INVOICE_85"">";
КонецФункции

Функция ЗаписатьСвойПакет85(Пользователь, ПропуститьВторуюЦену)
    Если ТипЗнч(Пользователь) <> Тип("Строка") Или СтрДлина(Пользователь) <> 36
        Или ТипЗнч(ПропуститьВторуюЦену) <> Тип("Булево") Тогда
        ВызватьИсключение "Параметры только из собственного проверенного вызова";
    КонецЕсли;
    Запись = Новый ЗаписьFastInfoset;
    Запись.УстановитьДвоичныеДанные();
    Попытка
        Запись.ЗаписатьОбъявлениеXML();
        Запись.ЗаписатьТипДокумента("invoice", СвоеПодмножество85());
        Запись.ЗаписатьНачалоЭлемента("invoice");
        Запись.ЗаписатьАтрибут("owner", Пользователь);
        Запись.ЗаписатьНачалоЭлемента("item");
        Запись.ЗаписатьАтрибут("sku", "BOOK");
        Запись.ЗаписатьАтрибут("quantity", "3");
        Запись.ЗаписатьАтрибут("price", "250");
        Запись.ЗаписатьКонецЭлемента();
        Запись.ЗаписатьНачалоЭлемента("item");
        Запись.ЗаписатьАтрибут("sku", "TEA_");
        Запись.ЗаписатьАтрибут("quantity", "2");
        Если Не ПропуститьВторуюЦену Тогда
            Запись.ЗаписатьАтрибут("price", "150");
        КонецЕсли;
        Запись.ЗаписатьКонецЭлемента();
        Запись.ЗаписатьНачалоЭлемента("memo");
        Запись.ЗаписатьСсылкуНаСущность("memo");
        Запись.ЗаписатьКонецЭлемента();
        Запись.ЗаписатьКонецЭлемента();
        Данные = Запись.Закрыть();
    Исключение
        Запись.Закрыть();
        ВызватьИсключение;
    КонецПопытки;
    Если ТипЗнч(Данные) <> Тип("ДвоичныеДанные") Тогда
        ВызватьИсключение "Native writer не вернул собственные двоичные данные";
    КонецЕсли;
    Если Данные.Размер() = 0 Или Данные.Размер() > 16384 Тогда
        ВызватьИсключение "Неожиданный размер собственного маленького пакета FI";
    КонецЕсли;
    Возврат Данные;
КонецФункции

Процедура ПроверитьЛокальныеИдентификаторы85(Чтение)
    Если ТипЗнч(Чтение) <> Тип("ЧтениеFastInfoset") Тогда
        ВызватьИсключение "Нужен настоящий собственный reader Fast Infoset";
    КонецЕсли;
    Если Чтение.ТипУзла <> ТипУзлаXML.ОпределениеТипаДокумента
        И Чтение.ТипУзла <> ТипУзлаXML.Сущность И Чтение.ТипУзла <> ТипУзлаXML.СсылкаНаСущность Тогда
        ВызватьИсключение "Проверка идентификаторов вызывается только в своём DTD/entity/reference контексте";
    КонецЕсли;
    Если Чтение.ИмяНотации <> "" Или Чтение.ПубличныйИдентификатор <> "" Или Чтение.СистемныйИдентификатор <> "" Тогда
        ВызватьИсключение "Этот урок не принимает внешних или неразбираемых сущностей";
    КонецЕсли;
КонецПроцедуры

Функция ПрочитатьСвоиОбъявления85(Чтение)
    Если ТипЗнч(Чтение) <> Тип("ЧтениеFastInfoset") Или Чтение.ТипУзла <> ТипУзлаXML.ОпределениеТипаДокумента Тогда
        ВызватьИсключение "Объявления читаются только из текущего настоящего DTD";
    КонецЕсли;
    Если Чтение.Имя <> "invoice" Или Чтение.Значение <> СвоеПодмножество85() Тогда
        ВызватьИсключение "Не совпал собственный фактический DTD до смены курсора";
    КонецЕсли;
    ПроверитьЛокальныеИдентификаторы85(Чтение);
    Объявлений = 0;
    Позиция = Чтение.ПервоеОбъявление();
    Если ТипЗнч(Позиция) <> Тип("Булево") Или Не Позиция Тогда
        ВызватьИсключение "Reader не предоставил собственное объявление DTD: дальнейшее выполнение запрещено";
    КонецЕсли;
    Пока Позиция Цикл
        Если Чтение.ТипУзла <> ТипУзлаXML.Сущность Тогда
            ВызватьИсключение "В собственном literal DTD допустимо только одно объявление parsed entity";
        КонецЕсли;
        ПроверитьЛокальныеИдентификаторы85(Чтение);
        Объявлений = Объявлений + 1;
        Если Объявлений > 1 Тогда
            ВызватьИсключение "Неожиданное дополнительное объявление собственного DTD";
        КонецЕсли;
        Позиция = Чтение.СледующееОбъявление();
        Если ТипЗнч(Позиция) <> Тип("Булево") Тогда
            ВызватьИсключение "NextDeclaration должен вернуть настоящее Булево";
        КонецЕсли;
    КонецЦикла;
    Если Объявлений <> 1 Тогда
        ВызватьИсключение "Собственный DTD должен предоставить ровно одно настоящее объявление";
    КонецЕсли;
    Возврат Объявлений;
КонецФункции

Функция ПрочитатьСвойПакет85(Данные, Пользователь)
    Если ТипЗнч(Данные) <> Тип("ДвоичныеДанные") Или ТипЗнч(Пользователь) <> Тип("Строка")
        Или СтрДлина(Пользователь) <> 36 Тогда
        ВызватьИсключение "Читаем только результат собственного private writer и actual user UUID";
    КонецЕсли;
    Строки = Новый Массив;
    Сумма = 0;
    Количество = 0;
    Причина = "";
    КореньОткрыт = Ложь;
    КореньЗакрыт = Ложь;
    Дочерний = "";
    DTD = 0;
    Объявлений = 0;
    Примечаний = 0;
    Ссылок = 0;
    ТекстПримечания = "";
    Чтение = Новый ЧтениеFastInfoset;
    Чтение.УстановитьДвоичныеДанные(Данные);
    Попытка
        Пока Чтение.Прочитать() Цикл
            Если Чтение.ТипУзла = ТипУзлаXML.ОбъявлениеXML Тогда
                Если DTD <> 0 Или КореньОткрыт Или КореньЗакрыт Тогда
                    ВызватьИсключение "XML declaration в неожиданном месте";
                КонецЕсли;
            ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.ОпределениеТипаДокумента Тогда
                Если DTD <> 0 Или КореньОткрыт Или КореньЗакрыт Тогда
                    ВызватьИсключение "DTD только один и перед собственным invoice";
                КонецЕсли;
                DTD = DTD + 1;
                Объявлений = ПрочитатьСвоиОбъявления85(Чтение);
            ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
                Если Чтение.Имя = "invoice" Тогда
                    Если КореньОткрыт Или КореньЗакрыт Или DTD <> 1 Или Объявлений <> 1
                        Или Чтение.КоличествоАтрибутов() <> 1 Или Чтение.ПолучитьАтрибут("owner") <> Пользователь Тогда
                        ВызватьИсключение "Не совпали own root, его положение и actual user UUID";
                    КонецЕсли;
                    КореньОткрыт = Истина;
                ИначеЕсли Чтение.Имя = "item" Тогда
                    Если Не КореньОткрыт Или КореньЗакрыт Или Дочерний <> "" Или Примечаний <> 0 Или Строки.Количество() >= 2 Тогда
                        ВызватьИсключение "Не совпало положение своей строки счёта";
                    КонецЕсли;
                    Дочерний = "item";
                    Артикул = Чтение.ПолучитьАтрибут("sku");
                    ИсходноеКоличество = Чтение.ПолучитьАтрибут("quantity");
                    ИсходнаяЦена = Чтение.ПолучитьАтрибут("price");
                    Если Артикул = Неопределено Или ИсходноеКоличество = Неопределено Тогда
                        ВызватьИсключение "В своей строке отсутствуют артикул или количество";
                    КонецЕсли;
                    КоличествоСтроки = Число(ИсходноеКоличество);
                    Если (Строки.Количество() = 0 И (Артикул <> "BOOK" Или КоличествоСтроки <> 3))
                        Или (Строки.Количество() = 1 И (Артикул <> "TEA_" Или КоличествоСтроки <> 2)) Тогда
                        ВызватьИсключение "Не совпала полная последовательность своих двух строк";
                    КонецЕсли;
                    ЦенаСтроки = Неопределено;
                    СуммаСтроки = Неопределено;
                    Если ИсходнаяЦена = Неопределено Тогда
                        Если Строки.Количество() <> 1 Или Чтение.КоличествоАтрибутов() <> 2 Или Причина <> "" Тогда
                            ВызватьИсключение "Неизвестный дефект вместо собственного отрицательного варианта";
                        КонецЕсли;
                        Причина = "TEA_: отсутствует обязательный атрибут price";
                    Иначе
                        Если Чтение.КоличествоАтрибутов() <> 3 Тогда
                            ВызватьИсключение "Неизвестные атрибуты своей строки";
                        КонецЕсли;
                        ЦенаСтроки = Число(ИсходнаяЦена);
                        Если (Строки.Количество() = 0 И ЦенаСтроки <> 250) Или (Строки.Количество() = 1 И ЦенаСтроки <> 150) Тогда
                            ВызватьИсключение "Цена прочитана, но не совпала со своим полным контролем";
                        КонецЕсли;
                        СуммаСтроки = КоличествоСтроки * ЦенаСтроки;
                        Сумма = Сумма + СуммаСтроки;
                    КонецЕсли;
                    Количество = Количество + КоличествоСтроки;
                    Строки.Добавить(Новый Структура("Артикул,Количество,Цена,Сумма", Артикул, КоличествоСтроки, ЦенаСтроки, СуммаСтроки));
                ИначеЕсли Чтение.Имя = "memo" Тогда
                    Если Не КореньОткрыт Или КореньЗакрыт Или Дочерний <> "" Или Строки.Количество() <> 2
                        Или Примечаний <> 0 Или Чтение.КоличествоАтрибутов() <> 0 Тогда
                        ВызватьИсключение "Не совпало положение собственного примечания";
                    КонецЕсли;
                    Дочерний = "memo";
                    Примечаний = Примечаний + 1;
                Иначе
                    ВызватьИсключение "Неизвестный элемент вместо собственных invoice/item/memo";
                КонецЕсли;
            ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.СсылкаНаСущность Тогда
                Если Не КореньОткрыт Или КореньЗакрыт Или Дочерний <> "memo" Или Ссылок <> 0 Или Чтение.Имя <> "memo" Тогда
                    ВызватьИсключение "Не совпала реальная ссылка на собственную сущность";
                КонецЕсли;
                ПроверитьЛокальныеИдентификаторы85(Чтение);
                Ссылок = Ссылок + 1;
            ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст Тогда
                Если Дочерний <> "memo" Или Ссылок <> 1 Или Чтение.Значение <> "OWN_INVOICE_85" Или ТекстПримечания <> "" Тогда
                    ВызватьИсключение "Неожиданный actual text: значение сущности не подставляется вручную";
                КонецЕсли;
                ТекстПримечания = Чтение.Значение;
            ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.КонецСущности Тогда
                Если Дочерний <> "memo" Или Ссылок <> 1 Тогда
                    ВызватьИсключение "Неожиданный EndEntity вне своего reference";
                КонецЕсли;
            ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
                Если Чтение.Имя = "invoice" Тогда
                    Если Не КореньОткрыт Или КореньЗакрыт Или Дочерний <> "" Или Строки.Количество() <> 2
                        Или Примечаний <> 1 Или Ссылок <> 1 Тогда
                        ВызватьИсключение "Неполный собственный invoice перед завершением";
                    КонецЕсли;
                    КореньОткрыт = Ложь;
                    КореньЗакрыт = Истина;
                ИначеЕсли Чтение.Имя = Дочерний И (Дочерний = "item" Или Дочерний = "memo") Тогда
                    Дочерний = "";
                Иначе
                    ВызватьИсключение "Нарушен порядок настоящих EndElement";
                КонецЕсли;
            Иначе
                ВызватьИсключение "Неожиданный native FI узел: нельзя дорисовать отсутствующий протокол";
            КонецЕсли;
        КонецЦикла;
    Исключение
        Чтение.Закрыть();
        ВызватьИсключение;
    КонецПопытки;
    Чтение.Закрыть();
    Если КореньОткрыт Или Не КореньЗакрыт Или Дочерний <> "" Или DTD <> 1 Или Объявлений <> 1
        Или Строки.Количество() <> 2 Или Примечаний <> 1 Или Ссылок <> 1 Или Количество <> 5 Тогда
        ВызватьИсключение "Неполный actual FI readback до конца своих двоичных данных";
    КонецЕсли;
    Если Причина = "" И Сумма <> 1050 Тогда
        ВызватьИсключение "Реальные native количества и цены не дали сумму1050";
    КонецЕсли;
    Возврат Новый Структура("Принят,Причина,Строки,Количество,Сумма,DTD,Объявлений,Ссылок,ТекстПримечания",
        Причина = "", Причина, Строки, Количество, Сумма, DTD, Объявлений, Ссылок, ТекстПримечания);
КонецФункции

Процедура СравнитьДваРеальныхЧтения85(До, После)
    Если Не До.Принят Или Не После.Принят Или До.Причина <> После.Причина
        Или До.Количество <> После.Количество Или До.Сумма <> После.Сумма
        Или До.DTD <> После.DTD Или До.Объявлений <> После.Объявлений Или До.Ссылок <> После.Ссылок
        Или До.ТекстПримечания <> После.ТекстПримечания Или До.Строки.Количество() <> 2 Или После.Строки.Количество() <> 2 Тогда
        ВызватьИсключение "Два настоящих чтения собственного пакета не совпали";
    КонецЕсли;
    Для Индекс = 0 По 1 Цикл
        Первая = До.Строки[Индекс];
        Вторая = После.Строки[Индекс];
        Если Первая.Артикул <> Вторая.Артикул Или Первая.Количество <> Вторая.Количество
            Или Первая.Цена <> Вторая.Цена Или Первая.Сумма <> Вторая.Сумма Тогда
            ВызватьИсключение "Не совпал полный native snapshot своей строки";
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Функция ВыполнитьСвойУрок85() Экспорт
    Пользователь = ПроверитьСвойСтенд85();
    Данные = ЗаписатьСвойПакет85(Пользователь, Ложь);
    До = ПрочитатьСвойПакет85(Данные, Пользователь);
    Если Не До.Принят Тогда
        ВызватьИсключение "Положительный собственный пакет отказал до отрицательной проверки";
    КонецЕсли;
    ОтрицательныеДанные = ЗаписатьСвойПакет85(Пользователь, Истина);
    Отказ = ПрочитатьСвойПакет85(ОтрицательныеДанные, Пользователь);
    Если Отказ.Принят Или Отказ.Причина <> "TEA_: отсутствует обязательный атрибут price"
        Или Отказ.Строки.Количество() <> 2 Или Отказ.Количество <> 5 Или Отказ.Сумма <> 750
        Или Отказ.Строки[1].Цена <> Неопределено Или Отказ.Строки[1].Сумма <> Неопределено Тогда
        ВызватьИсключение "Не подтверждён узкий собственный бизнес-отказ без подстановки цены";
    КонецЕсли;
    После = ПрочитатьСвойПакет85(Данные, Пользователь);
    СравнитьДваРеальныхЧтения85(До, После);
    Возврат "Будущий ручной протокол: собственных строк " + Формат(После.Строки.Количество(), "ЧГ=0;ЧДЦ=0")
        + "; количество " + Формат(После.Количество, "ЧГ=0;ЧДЦ=0") + "; сумма " + Формат(После.Сумма, "ЧГ=0;ЧДЦ=0")
        + Символы.ПС + "Фактический DTD=1, native entity declaration=1, native reference=1."
        + Символы.ПС + "Отдельный бизнес-отказ: " + Отказ.Причина
        + Символы.ПС + "Текст раскрытия сущности не гарантируется; наблюдено: [" + После.ТекстПримечания + "]";
КонецФункции
Полный модуль своей управляемой общей формы

Общие → Общие формы → СчетFastInfoset85 → Модуль

Windows thick managed own client/server form; sticky fail-stop at both boundaries.

&НаКлиенте
Процедура Проверить85(Команда)
#Если ТолстыйКлиентУправляемоеПриложение Тогда
    Если Остановка85 Тогда
        ВызватьИсключение "Клиентская граница запрещает повтор после частичного отказа";
    КонецЕсли;
    Попытка
        ПроверитьНаСервере85();
    Исключение
        Остановка85 = Истина;
        Протокол85 = "Отказ: закройте свою форму и изучите фактическую диагностику. Автоповтора нет.";
        ВызватьИсключение;
    КонецПопытки;
#Иначе
    ВызватьИсключение "Нужен свой толстый управляемый клиент";
#КонецЕсли
КонецПроцедуры

&НаСервере
Процедура ПроверитьНаСервере85()
    Если Остановка85 Тогда
        ВызватьИсключение "Серверная граница запрещает повтор после частичной ошибки";
    КонецЕсли;
    Попытка
        Протокол85 = УчебныйПакетСчетаFI85.ВыполнитьСвойУрок85();
    Исключение
        Остановка85 = Истина;
        ВызватьИсключение;
    КонецПопытки;
КонецПроцедуры
Полный модуль своего управляемого приложения

Своя конфигурация → Модуль управляемого приложения

Windows thick managed own application; real OnStart0.

Процедура ПриНачалеРаботыСистемы()
#Если ТолстыйКлиентУправляемоеПриложение Тогда
    ОткрытьФорму("ОбщаяФорма.СчетFastInfoset85");
#Иначе
    ВызватьИсключение "Учебный сценарий только для своего толстого управляемого клиента";
#КонецЕсли
КонецПроцедуры

Разбор по шагам

  1. Подготовьте только свой new FileCF, одного настоящего пользователя, серверный общий модуль, управляемую форму и реальную кнопку; вставьте все три полных модуля.

  2. Проверьте actual .1343/FileCF/пустую metadata/one-user UUID. Native writer создаёт собственный binary invoice с DTD и parsed memo; actual Close проверяется как ДвоичныеДанные.

  3. Новый native reader проверяет реальный DTD text до cursor change, проходит First/NextDeclaration и отклоняет внешние идентификаторы. Ни DOMBuilder, ни искусственный declaration здесь не используются.

  4. Прочитайте все собственные элементы/атрибуты/reference доEOF. Настоящие quantity и price дают две строки750/300, quantity5/total1050. Полный snapshot хранится из actual native чтения.

  5. Создайте отдельный собственный пакет без второй цены. Он синтаксически формируется native writer, но бизнес-обязательное поле отсутствует. Отказ конкретный, Цена/Сумма второй строки остаются Неопределено; произвольное исключение не считается ожидаемым результатом.

  6. Ещё одним новым reader прочитайте исходные собственные байты и сравните весь actual snapshot двух positive чтений. Только после полного совпадения показывается итоговый протокол.

Как проверить результат

  1. Будущий ручной positive протокол:2actual item, BOOK3×250=750, TEA_2×150=300; native quantity5,total1050 дважды.

  2. Actual DTD1, declaration1 и reference1 наблюдены native reader. Неизвестный retained DTD/default или FirstDeclaration=False вызывает fail-stop, а не подставленную entity.

  3. Readonly notation/public/system empties проверяются в своих actual node contexts; external/unparsed metadata отвергается. Generic declaration Имя не используется для неописанного entity-name proof.

  4. Business negative: конкретное отсутствие TEA_.price, две реальные строки/quantity5/actual partialsum750, вторая Цена/Сумма Неопределено. Native parser/constructor/read/типовая ошибка не признаётся этой проверкой.

  5. Статические/native-source проверки не подтверждают FI runtime retention/expansion, компиляцию 1С, визуализацию или выполнение в ИБ.

Ожидаемый результат

Ожидаемый будущий ручной результат: собственный native FI-счёт2строки/количество5/сумма1050 дважды, actual DTD/declaration/reference1, узкий бизнес-отказ при отсутствии второй цены. RuntimeVerified=False, actual1C/DB/UI/network/files/provisioning/backup0.

На что обратить внимание

  1. Fast Infoset — бинарное представление XML, а не текст UTF-8, JSON или API Avito. Данные читаются соответствующим native reader без декодирования байтов в XML-строку.

  2. Не используйте широкую доступность отдельного метода как разрешение перенести весь тип/memory lifecycle в thin/web. Этот основной модуль серверный.

  3. Внутренний parsed entity и external unparsed entity различаются; три readonly поля — настоящие идентификаторы узла, а не setter или способ загрузить внешний ресурс.

  4. Нельзя обещать раскрытие memo по наличию WriteEntityReference или угадывать declaration Имя. Отсутствующий native cursor/reference останавливает опыт.

  5. Нельзя заменить реальные числовые атрибуты подготовленными750/300/1050; контрольные числа только проверяют вычисление после actual чтения.

  6. Negative business-result не означает успешную native DTD validation и не классифицирует произвольные runtime/OOM/повреждённые FI ошибки.

  7. Это только собственный bounded memory урок; чужие байты/DTD/файлы/сетевые URI/производственные базы не допускаются.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.