Перейти к содержанию

Работа с карточками объектов

Карточки – это документы или иные сущности, с которыми явно или опосредованно работает пользователь в системе, например, карточки ролей, карточки настроек или карточки последовательностей. С карточками любых типов помогает работать универсальное API карточек, которое и будет описано в этом разделе.

Взаимодействие клиент-сервер

Рассмотрим процесс, происходящий в системе при создании карточки. При этом создаётся “пустая” структура карточки, которая пока не сохранена в базе данных и отображается пользователю. При создании может резервироваться номер документа, заполняться какие-то данные по умолчанию и др.

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

При этом к плитке привязана команда вызова API карточек, доступного через интерфейс ICardRepository.

Выполняется вызов вида:

CardNewResponse response = cardRepository.New(new CardNewRequest { CardTypeID = ... });

При этом в запрос CardNewRequest передаётся идентификатор типа CardTypeID создаваемой карточки “Договор”. Метод New возвращает ответ на запрос CardNewResponse с созданной карточкой response.Card, при этом на клиенте и на сервере выполняется ряд этапов, на которых могут выполняться написанные разработчиком расширения.

При исполнении метода интерфейса ICardRepository без расширений выполняется ровно один запрос через границу клиент-сервер, который на сервере приводит к нескольким запросам к СУБД, причём они инициируются стандартным API. Пользовательские и платформенные расширения могут изменить это поведение, когда может не выполниться ни одного запроса (если речь о виртуальной карточке, доступной только на клиенте, такой как просмотр удалённой карточки) или, наоборот, может выполниться несколько запросов, в т.ч. к разным веб-сервисам (когда необходимо обратиться к веб-сервису, или же требуется загрузить несколько карточек одновременно, чтобы данные одной карточки использоваться вместо данных другой).

Рассмотрим последовательность выполняемых действий:

  1. Перед отправкой на сервер выполняется цепочка расширений BeforeRequest, причём расширения определяются на клиенте в сборке Tessa.Extensions.Client.dll.

    • Эти расширения имеют доступ к текущему контексту UIContext.Current, посредством которого можно получить доступ к вкладке с карточкой, в том числе к конкретным контролам и другим объектам UI.

    • Если в результате выполнения цепочки расширений был установлен результат запроса в свойстве context.Response, то запрос к серверу не исполняется, и следующим шагом выполняется цепочка клиентских расширений AfterRequest. Такое поведение рекомендуется для взаимодействия с виртуальными карточками, доступными только на клиенте. Такими карточками могут быть карточки из сторонней системы, взаимодействие с которой производится с клиента, а не с сервера. Также это можно использовать для карточек, которые кэшируются на клиенте, и при повторном к ним обращении не загружаются с сервера, а создаются из кэша.

    • Если на этом этапе происходит необработанное исключение или ошибки валидации, то выполняется переход к клиентским расширениям AfterRequest, причём свойство context.RequestIsSuccessful устанавливается равным false.

  2. Выполняется сериализация запроса через границу клиент-сервер в формате BSON. На сервере запрос десериализуется, и выполнение продолжается.

  3. Цепочка расширений BeforeRequest на сервере выполняет подготовку карточки к обработке стандартным API.

    • При этом запрос может изменяться таким образом, чтобы стандартное API обработало карточку как-то иначе. Для создания карточки это не имеет особого смысла, но при сохранении карточки на этом этапе карточка может быть изменена перед сохранением: например, при сохранении карточки в процессе начала согласования в поле “Инициатор” записывается текущий пользователь, если других записей там не было.

    • Эта цепочка расширений так же, как и клиентская цепочка BeforeRequest, может установить результат запроса в свойстве context.Response, за счёт чего стандартное API вызвано не будет, а выполнение перейдёт к серверной цепочке расширений AfterRequest. Это рекомендуется для виртуальных карточек, которые доступны как на сервере, так и на клиенте. Данных таких карточек могут быть заполнены любым способом, например, прямыми запросами к базе данных или обращением к сторонней системе.

    • Если на этом этапе происходит необработанное исключение или ошибки валидации, то выполняется переходит к серверным расширениям AfterRequest, причём свойство context.RequestIsSuccessful устанавливается равным false.

  4. Выполняется стандартное API. При этом всегда формируется ответ на запрос штатными средствами платформы. При создании карточки формируется пустой пакет карточки, у которого поля секций заполнены значениями null или значениями из Default constraint, которые указаны.

    • В цепочке расширений AfterRequest платформенные или пользовательские расширения могут заполнить некоторые из полей, например, зарезервировать номер из последовательности и задать его в полях карточки.

    • Если на этом этапе происходит необработанное исключение или ошибки валидации, то выполняется переходит к серверным расширениям AfterRequest, причём свойство context.RequestIsSuccessful устанавливается равным false.

  5. Цепочка расширений AfterRequest на сервере может реагировать на несколько событий.

    • Оно должно проверить context.RequestIsSuccessful, чтобы убедиться в том, что к моменту начала цепочки не возникало ошибок. Если свойство возвращает false, то ошибки имеются.

    • Ошибки могут быть как в расширениях BeforeRequest, так и в стандартном API, причём собственно ошибку может сгенерировать SQL Server или другая внешняя подсистема (файловая система при сохранении карточки с файлами и др.). При наличии ошибок возможна их дополнительная обработка, например, запись информации об определённых ошибках в специальную таблицу.

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

    • Расширения могут полностью заменить ответ на запрос, если он их чем-то “не устроил”, например, если в карточке отсутствуют требуемые данные, и её нужно полностью загрузить из сторонней системы.

    • Если на этом этапе происходит необработанное исключение или ошибки валидации, то выполнение продолжается и в клиентских расширениях AfterRequest свойство context.RequestIsSuccessful устанавливается равным false.

  6. Выполняется сериализация ответа на запрос через границу клиент-сервер в формате BSON. На клиенте ответ на запрос десериализуется, и выполнение продолжается.

  7. Цепочка расширений AfterRequest на клиенте действует аналогично цепочке AfterRequest на сервере, но она имеет доступ к текущему контексту UIContext.Current для того, чтобы можно было определить, откуда производится действие с карточкой, и в соответствии с этим изменить ответ на запрос. Например, если создаётся карточка, когда открыта другая карточка, то некоторые из полей этой другой карточки могут быть заполнены из данных открытой карточки (это своего вида частичное копирование карточки).

    • Рекомендуется всегда проверять значение context.RequestIsSuccessful в самом начале всех расширений на этом этапе, т.к. при наличии ошибок логику выполнения расширения как правило следует изменить.

    • Если на этом этапе происходит необработанное исключение или ошибки валидации, то выполнение завершается, как и в случае отсутствия ошибок, но в результате запроса response.ValidationResult разработчик сможет обработать (или вывести пользователю на экран и в лог) все ошибки, возникшие как на этом этапе, так и на одном из предыдущих.

Info

  • На сервере обращение к ICardRepository исключает этапы, относящиеся к клиентским расширениям, но включает все остальные этапы, обращение к API выглядит точно также.

  • Любые расширения на сервере могут обращаться к СУБД, получая IDbScope из Unity или свойства context.DbScope.

  • На любом этапе выполнения запроса к ICardRepository расширения могут обратиться к методам ICardRepository для взаимодействия с этой или другой карточкой.

  • При обращении внутри транзакции на сервере следует обязательно использовать версию API без транзакций.

На следующей схеме приведён процесс типового запроса к API карточек.

На рисунке изображена карточка договора, в которой зарезервирован номер “Д-00003”, указан регистратор как текущий пользователь “Администратор” и заполнена дата регистрации, поля “Автор” и “Дата документа”.

Пакет карточки

Любая карточка представляется в памяти структурой в виде вложенных друг в друга хэш-таблиц и списков, поля которых определяют как системные, так и редактируемые пользователем свойства карточки. Такая структура называется пакетом карточки. При переходе через границу клиент-сервер пакет сериализуется в BSON (бинарная форма JSON). В коде расширений к карточке можно обращаться как к объекту Card, а можно получить внутреннее представление card.GetStorage() и обращаться к объекту Dictionary<string, object>.

Например, рассмотрим пакет в результате создания карточки “Договор”.

{ Created: null, CreatedByID: 3db19fa0-228a-497f-873a-0250bf0a4ccb, CreatedByName: "Администратор", Flags: 0, ID: 2d489962-a521-4bce-9f19-f41506147bc5, Info: null, Modified: null, ModifiedByID: 3db19fa0-228a-497f-873a-0250bf0a4ccb, ModifiedByName: "Администратор", Tasks: null, TypeCaption: "Договор", TypeID: 335f86a1-d009-012c-8b45-1f43c2382c2d, TypeName: "Contract", Version: 0, Files: [ ], Permissions: { CardPermissions: 5461, FilePermissions: null, Sections: null }, Sections: { DocumentCommonInfo: { Fields: { Amount: null, AuthorID: 3db19fa0-228a-497f-873a-0250bf0a4ccb, AuthorName: "Администратор", CurrencyID: null, CurrencyName: null, DocDate: 10/06/2014 12:11:19 UTC, FullNumber: "Д-00003", Number: 3L, PartnerID: null, PartnerName: null, RegistrationDate: 10/06/2014 12:11:19 UTC, RegistratorID: 3db19fa0-228a-497f-873a-0250bf0a4ccb, RegistratorName: "Администратор", State: "проект", Subject: null } }, KrApprovalCommonInfoVirtual: { Fields: { ApprovedBy: null, AuthorComment: null, AuthorID: null, AuthorName: null, CurrentApprovalStageRowID: null, Cycle: 0, DisapprovedBy: null, MainCardId: null, StateID: 0, StateName: "Проект" } }, KrApproversVirtual: { .table: 1, Rows: null }, KrStagesVirtual: { .table: 1, Rows: [ ] } }, TaskHistory: [ ] }

Пакет содержит:

  • Системная информация (идентификатор карточки ID, тип карточки с идентификатором TypeID, алиасом TypeName и отображаемым именем TypeName, идентификатор CreatedByID и имя CreatedByName пользователя, создавшего карточку).

  • Данные карточки (секции Sections, строки Rows и поля Fields, редактируемые пользователем или скрытые от пользователя и редактируемые в коде расширений).

  • Разрешения на различные взаимодействия с карточкой Permissions. Система разрешений многоуровневая и позволяет настроить общие разрешения на всю карточку CardPermissions (например, флаг ProhibitModify запрещает редактировать всю карточку), а также разрешения Sections на секции, поля и строки, которые могут переопределить разрешения более высокого уровня.

  • Список заданий Tasks. Каждое задание содержит системную информацию (идентификатор, кто и когда создал, на какую дату запланировано выполнение и т.п.), а также само является особым видом карточки и содержит настраиваемые данные карточки и список разрешений. Отличие карточки задания от обычной карточки в том, что с ней невозможно взаимодействовать как с отдельной сущностью, т.е. любые действия выполняются в рамках основной карточки.

  • Список файлов Files. Файл также содержит как системные поля (идентификатор, размер в байтах, список версий и др.), так и настраиваемые данные карточки, и список разрешений, т.к. так же, как и задание, является особым видом карточки.

  • История заданий TaskHistory. Содержит информацию о завершённых заданиях вместе с их результатами.

  • Дополнительная информация Info. В этом разделе может записываться любая (в т.ч. и структурированная) информация, которая нужна расширениям.

В пакете карточки могут быть следующие особые поля:

  • .FieldName - поле добавлено системой (начинается с точки) и содержит нужную платформе информацию; такие поля не влияют на данные и удаляются при сохранении карточки. Определить, является ли поле системным, можно по его ключу, передав его в хэлпер CardHelper.IsSystemKey(string).

  • .changed - список названий изменённых полей, для строковой секции содержится в CardSection, а для табличной или древовидной - в каждой строке CardRow. Пример: .changed: [ "FullName", "Phone" ]

  • .state - состояние строки CardRowState, содержится в каждой строке CardRow табличной или древовидной секции. Значения: 0 - строка не изменена; 1 - строка изменена; 2 - строка добавлена; 3 - строка удалена.

  • __Field - поле добавлено расширениями (начинается с двух подчеркиваний) и содержит нужную им информацию; такие поля не учитываются платформой, не влияют на данные и удаляются при сохранении карточки. Определить, является ли поле пользовательским, можно по его ключу, передав его в хэлпер CardHelper.IsUserKey(string).

Вы можете посмотреть пакет карточки в интерфейсе Tessa Client, открыв любую карточку и выбрав в левой панели тайл Другие→Структура карточки. В открывшемся диалоге можно просмотреть как полностью пакет карточки (сняв флажок “Карточка при сохранении”), так и пакет, который будет отправлен на сервер, если пользователь нажмет “Сохранить” прямо сейчас (при установленном флажке “Карточка при сохранении”).

Загрузка, сохранение и удаление карточки

Когда пользователь нажимает плитку “Сохранить” или выбирает вариант завершения задания, то производится сохранение карточки. При этом карточка сначала сохраняется запросом repository.Store(...), а затем загружается запросом repository.Get(...), если сохранение было успешно.

В запрос на сохранение CardStoreRequest передаётся пакет карточки, а в ответе на запрос CardStoreResponse возвращаются сообщения валидации и некоторая системная информация, например, версия после сохранения.

В запрос на загрузку CardGetRequest передаётся идентификатор загружаемой карточки и тип карточки, а в ответе на запрос CardGetResponse возвращается загруженная карточка, если загрузка успешна, и сообщения валидации, которые могут содержать информацию по ошибкам, если, например, карточка не найдена по указанному идентификатору или у пользователя нет прав на открытие карточки. Указанный в запросе тип карточки не учитывается стандартным API, но используется для фильтрации расширений на загрузку карточки.

Процесс загрузки карточки ничем принципиально не отличается от создания, кроме того, что это другой метод ICardRepository, он принимает другой тип запроса и возвращает другой ответ. Также загруженные карточки сжимаются платформенными расширениями непосредственно перед передачей на клиент, где они разжимаются до того, как управление перейдёт к пользовательским расширениям. В процессе того, как стандартное API выполняет запросы на загрузку карточки, захватывается блокировка на чтение карточки. Возможно любое количество одновременных запросов на чтение карточки, но изменяться или удаляться карточка при этом не будет. Специальные расширения, которые выполнялись бы внутри блокировки, отсутствуют, но в цепочках BeforeRequest или AfterRequest можно захватить блокировку вручную, после чего загрузить какую-либо дополнительную информацию по карточке.

В процессе сохранения есть свои особенности. Они связаны с тем, что на сервере сохранение карточки средствами стандартного API выполняются в транзакции. Для того, чтобы в той же самой транзакции выполнить расширения, используются цепочки расширений AfterBeginTransaction и BeforeCommitTransaction.

  1. Стандартное API на сервере подготавливает запросы на сохранение. Если при этом возникает исключение или ошибка валидации, то выполнение переходит к цепочке расширений AfterRequest.

  2. Открывается транзакция и захватывается блокировка на запись карточки. При этом параллельно никто не может читать или изменять карточку, пока блокировка не будет снята.

  3. Цепочка расширений AfterBeginTransaction выполняется сразу после открытия транзакции. На этот момент стандартное API уже построило SQL-запросы на сохранение, поэтому изменять запрос CardStoreRequest к этому моменту не имеет смысла.

    • Расширения позволяют скорректировать состояние базы данных перед тем, как стандартное API выполнит запросы. Например, если есть карточка-сателлит, на которую ссылается сохраняемая карточка, то такую карточку требуется создать именно в этой цепочке. При этом можно использовать как прямые запросы к БД, так и стандартное API ICardRepository, которое следует запросить из Unity с именем CardRepositoryNames.WithoutTransaction. Такое API не будет выполнять действия с карточками внутри транзакции, поэтому можно будет использовать ту же самую транзакцию, что и в основной карточке.

    • Если при выполнении цепочки возникает необработанное исключение, или в свойство context.ValidationResult записывается ошибка валидации, то транзакция откатывается, блокировка снимается, а выполнение переходит к цепочке серверных расширений AfterRequest.

    • В случае ошибок внутри транзакции на этом или более позднем этапе следует учесть, что произойдёт откат транзакции, т.е. будут отменены все изменения, сделанные в базе данных для соединения, доступного через context.DbScope. Если изменения были сделаны в другом соединении с базой данных или на файловой системе (например, был удалён файл, контент которого хранился на диске), то их потребуется вручную откатить в цепочке расширений AfterRequest. Возможно, эти изменения следует делать сразу в AfterRequest, чтобы они выполнялись только в случае успешного сохранения карточки.

  4. Стандартное API выполняет SQL запросы (взятие блокировки на запись, изменение полей карточки, вставка/удаление строки в коллекционные секции, создание и завершение задач, добавление файлов (без контента)) после расширений BeforeRequest и перед расширениями AfterBeginTransaction.

    • При возникновении исключений на этом этапе транзакция откатывается вместе со всеми изменениями, выполненными в цепочке AfterBeginTransaction, после чего выполнение переходит к AfterRequest.
  5. Цепочка расширений BeforeCommitTransaction выполняется после стандартного API и перед коммитом транзакции. В этой цепочке рекомендуется изменять значения, сохранённые стандартным API в базе данных. Например, поставить дату сохранения “задним числом”.

    • Если возникли необработанное исключение или ошибки валидации, то транзакция откатывается и выполнение переходит к цепочке серверных расширений AfterRequest.
  6. Выполняется коммит транзакции. Снимается блокировка на запись.

Если в карточке не выполняется изменений, то при сохранении через стандартное API не захватывается блокировка на запись, не открывается транзакции и в карточке не производится никаких изменений (не меняется, кто и когда последний раз сохранял карточку, и не увеличивается номер её версии). При этом не выполняются цепочки расширений AfterBeginTransaction и BeforeCommitTransaction, т.к. нет транзакции. Чтобы установить необходимость выполнения таких расширений независимо от наличия изменений в карточке, то следует установить в запросе флаг request.ForceTransaction = true. В таком случае транзакция всегда открывается, расширения выполняются, но версия карточки и другая системная информация по-прежнему не будет изменена при отсутствии изменений в карточке.

На рисунке приведена схема выполнения запроса на сохранение карточки. Все расширения на серверной стороне могут обращаться к СУБД, поэтому СУБД не отображена на схеме.

Сохранение карточки возможно в двух сценариях.

  • Первичное сохранение карточки, когда она только что была создана и ещё ни разу не сохранена. При этом карточка добавляется в базу данных SQL-запросами INSERT, а свойство card.StoreMode пакета карточки возвращает CardStoreMode.Insert. Перед передачей запроса на сохранение CardStoreRequest с клиента на сервер выполняется метод RemoveAllButChanged(), который удаляет из пакета карточки ненужные данные, такие как история заданий TaskHistory и разрешения на доступ к полям Permissions.

  • Повторное сохранение (изменение) карточки. Для строковых секций карточки генерируются SQL-запросы UPDATE, а свойство card.StoreMode пакета карточки возвращает CardStoreMode.Update. В этом случае метод RemoveAllButChanged() удаляет всю информацию по карточке, которая не изменяется. Например, это файлы и задания, которые не создаются или удаляются, и не изменены. Или это секции с полями и строками, значения которых остались прежними.

    • При сохранении в серверных расширениях может не быть информации по каким-либо полям, которые хоть и не были изменены, но косвенно влияют на изменённые поля. Например, если изменилась сумма договора, но не изменилась валюта, то на сервере нельзя будет сделать проверку “больше ли сумма договора, чем 10000 USD”, т.к. валюта неизвестна. В этом случае возможно два выхода.

    • Серверные расширения могут доверять клиенту, в таком случае клиент при изменении суммы передаёт поле с валютой в Info пакета карточки, или использует синтаксис пользовательских полей __Currency, а серверные расширения уже задействуют информацию от клиента для проверки условия.

    • Другой способ: серверное расширение загружает данные по валюте из базы данных, если валюта не была изменена на клиенте. Если загрузку данных и проверку выполнять в расширениях AfterBeginTransaction или BeforeCommitTransaction, то это гарантирует, что параллельный запрос на сохранение не сможет изменить данные после загрузки, но перед фактическим сохранением карточки.

Удаление карточки – это вызов метода repository.Delete(…). В запросе CardDeleteRequest указывается идентификатор удаляемой карточки и тип карточки. Тип не учитывается стандартным API, но используется для фильтрации расширений на удаление. В ответе на запрос CardDeleteResponse возвращаются сообщения валидации, которые могут содержать ошибки с указанием того, почему удаление не удалось выполнить.

В запросе на удаление также указывается флаг request.DeletionMode, который определяет способ удаления. Значение WithBackup обозначает, что карточка удаляется вся, кроме файлов, но перед удалением сериализуется и помещается в “корзину”, из которой она потом может быть восстановлена. Значение WithoutBackup определяет, что карточка удаляется окончательно и восстановлению не подлежит. Поэтому, если требуется сделать освобождение номера при окончательном удалении карточки, но номер не следует освобождать, если карточка переходит в корзину, то в коде расширения следует проверить, что свойство DeletionMode равно WithoutBackup.

Запросы на удаление выполняются через стандартный API в блокировке на запись и в транзакции, которая может быть расширена любыми расширениями таким же образом, как и расширения на сохранение AfterBeginTransaction и BeforeCommitTransaction.

Запросы Request

Любые взаимодействия с сервисом карточек, которые не укладываются в операции создания (New), сохранения (Store), загрузки (Get) и удаления (Delete) могут быть представлены в виде универсальных расширений ICardRequestExtension, которые получают некоторый абстрактный запрос CardRequest с указанием типа запроса (RequestType: Guid), а возвращают CardResponse с сообщениями валидации.

В зависимости от указанного RequestType выполняются различные расширения, которые могут быть связаны с любыми действиями. Выполнение запроса с цепочками расширений в таком случае аналогично запросам на создание и загрузку карточки, т.е. есть цепочки BeforeRequest и AfterRequest на клиенте и на сервере.

В платформу входят следующие типы запросов:

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

  • DeleteHistory: Позволяет удалить историю действий для заданной карточки. Как правило, этот метод не нуждается в расширении, если только не используются дополнительные (несистемные) таблицы с данными в истории действий.

  • Запросы для последовательностей, которые обеспечивают работу клиентского API ISequenceProvider. Расширять эти запросы не рекомендуется.

Для того, чтобы создать собственный тип запросов Request, достаточно определить тип запроса RequestType как случайный Guid, доступный как статическое поле в сборке Tessa.Extensions.Shared. Расширения на клиенте или сервере подписываются на этот RequestType.

public static class MyRequestTypes { public static readonly Guid MyType = new Guid("..."); }

public sealed class MyRequestExtension : CardRequestExtension { public override async Task AfterRequest(ICardRequestExtensionContext context) { if (context.RequestIsSuccessful) { ... } } }

extensionContainer .RegisterExtension<ICardRequestExtension, MyRequestExtension>(x => x .WithOrder(ExtensionStage.AfterPlatform) .WhenRequestTypes(MyRequestTypes.MyType))

CardResponse response = cardRepository.Request( new CardRequest { RequestType = MyRequestTypes.MyType, ... })

Специальные методы выполнения запросов

До сих пор было рассмотрено лишь стандартное взаимодействия с методами API карточек. Для некоторых методов доступно также специальное взаимодействие, которое используется при выполнении прочих действий с карточками в системе. Метод задаётся как значение перечисления в запросах к Card***Request, свойство Method.

Для создания карточки New доступны следующие виды методов:

  • Default – стандартное создание карточки, рассмотренное ранее.

  • Template – карточка создаётся по шаблону.

Для загрузки карточки Get:

  • Default – карточка загружается стандартным способом;

  • Backup - карточка загружается в режиме создания резервной копии, т.е. карточка загружается перед тем, как она будет удалена с сохранением загруженной информации для возможного последующего восстановления.

  • Export - карточка загружается в режиме административного экспорта.

Для сохранения карточки Store:

  • Default – карточка сохраняется стандартным способом;

  • Restore – карточка создаётся в режиме восстановления, т.е. карточка была удалена, после чего восстанавливается. Версия карточки, файлы и некоторые системные поля будут восстановлены после завершения операции. При установке этого свойства стандартный компонент сохранения не закрывает блокировку на запись.

  • Import - карточка сохраняется в режиме административного импорта.

Для удаления карточки доступен только стандартный метод Default. Для запросов Request не определены методы, т.к. поведение запросов изменяется в зависимости от типа запроса RequestType.

По умолчанию любое расширение регистрируется на обработку метода Default. Чтобы изменить это поведение и зарегистрировать расширение на другой метод или сразу несколько методов, при регистрации используется вызов WhenMethod(…). Если расширение зарегистрировано на несколько методов, то оно может проверить текущий метод в запросе через свойство context.Request.Method.

Например, следующее расширение регистрируется сразу на несколько методов сохранения.

extensionContainer .RegisterExtension<ICardStoreExtension, MyStoreExtension>(x => x .WithOrder(ExtensionStage.AfterPlatform, 4) .WithSingleton<MyStoreExtension>() .WhenMethod(CardStoreMethod.Default, CardStoreMethod.Restore, CardStoreMethod.Import));

Back to top