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

Создание расширений для изменения типов карточек ICardMetadataExtension

Создание расширений для изменения типов карточек ICardMetadataExtension

Расширения ICardMetadataExtension позволяют изменять типы карточек и информацию по секциям и колонкам при построении метаинформации. Построение происходит на сервере при первичном запуске application pool или при обращении к метаинформации после её сброса, например, после того, как пользователь изменил типы карточек или схему данных.

Расширение реализует интерфейс ICardMetadataExtension, или наследуется от CardMetadataExtension, переопределяя только нужные методы:

  • ModifyTypes - изменяет типы карточек, по которым затем будет строиться метаинформация. Принимает контекст расширения, содержащий изменяемую коллекцию типов CardTypes. Любые действия, связанные с изменением типов карточек, но не изменяющие секции и колонки, рекомендуется выполнять именно в этом методе.

  • ModifyMetadata - изменяет метаинформацию по типам карточек после её построения. К этому моменту уже определена коллекция доступных типов карточек, т.е. она получена из базы данных и изменена вызовом ModifyTypes. Секции, колонки и перечисления были созданы стандартными средствами платформы, но в этом методе их можно изменить. Например, добавить новые виртуальные секции с произвольной структурой, которые затем присоединить к существующим типам карточек.

Расширение должно быть зарегистрировано как на сервере (для фактического использования), так и на клиенте для специальных сценариев построения метаинформации (таких, как предпросмотр типа карточки с расширениями в TessaAdmin).

В качестве примера использования расширения рассмотрим задачу динамического изменения типов карточек, для которых требуется использовать процесс согласования KrProcess. Процесс со стороны физической структуры данных целиком и полностью реализован в карточке-сателлите, которая добавляется к нужным типам карточек в расширениях. То, какие именно типы могут использоваться в процессе согласования, определяется в карточке настроек KrSettings. В структуру согласуемых карточек требуется добавить виртуальные секции, вкладку “Процесс согласования” и валидаторы, которые добавлены в специальный скрытый тип карточки KrCard.

Расширение должно во все типы карточек, включённые в карточку настроек процесса согласования, добавить секции, вкладки и валидаторы из типа KrCard. При работе на сервере получение списка типов карточек выполняется из базы данных (метод CheckTypeInServerMode), а на клиенте в случае предпросмотра - из кэша карточек ICardCache, откуда может быть получена карточка настроек со списком типов. Расширение объявляется в Shared-сборке, но по-разному регистрируется на клиенте и на сервере.

public sealed class KrCardMetadataExtension : CardMetadataExtension { public KrCardMetadataExtension(ICardMetadata clientCardMetadata, ICardCache clientCache) { if (clientCardMetadata == null) { throw new ArgumentNullException("clientCardMetadata"); } if (clientCache == null) { throw new ArgumentNullException("clientCache"); }

this.clientMode = true; this.clientCardMetadata = clientCardMetadata; this.clientCache = clientCache; }

public KrCardMetadataExtension(IDbScope serverDbScope) { if (serverDbScope == null) { throw new ArgumentNullException("serverDbScope"); }

this.clientMode = false; this.serverDbScope = serverDbScope; }

private readonly bool clientMode;

private readonly ICardMetadata clientCardMetadata;

private readonly ICardCache clientCache;

private readonly IDbScope serverDbScope;

private delegate bool CheckTypeFunc(CardType cardType, ref List<Guid> allowedCardTypeIDs);

private bool CheckTypeInClientMode(CardType cardType, ref List<Guid> allowedCardTypeIDs) { if (cardType.InstanceType != CardInstanceType.Card) { return false; }

if (allowedCardTypeIDs == null) { if (!this.clientCache.Cards.IsAllowed("KrSettings")) { return false; }

Card krSettings = this.clientCache.Cards["KrSettings"];

allowedCardTypeIDs = krSettings .Sections["KrSettingsCardTypes"] .Rows .Where(x => x.State == CardRowState.None) .Select(x => x.Get<Guid>("CardTypeID")) .Distinct() .ToList();

allowedCardTypeIDs.Remove(DefaultCardTypes.KrCardTypeID); }

return allowedCardTypeIDs.Contains(cardType.ID); }

private bool CheckTypeInServerMode(CardType cardType, ref List<Guid> allowedCardTypeIDs) { if (cardType.InstanceType != CardInstanceType.Card) { return false; }

if (allowedCardTypeIDs == null) { using (this.serverDbScope.Create()) { allowedCardTypeIDs = this.serverDbScope.Db .SetCommand("select CardTypeID from KrSettingsCardTypes with(nolock)") .LogCommand() .ExecuteScalarList<Guid>();

allowedCardTypeIDs.Remove(DefaultCardTypes.KrCardTypeID); } }

return allowedCardTypeIDs.Contains(cardType.ID); }

public override void ModifyTypes(ICardMetadataExtensionContext context) { CardType krCardType;

if (!context.CardTypes.TryGetValue(DefaultCardTypes.KrCardTypeID, out krCardType)) { // если в метаинформации, которая строится, есть тип карточки с процессом согласования и отсутствует тип карточки KrCard, то: // - на клиенте можем получить тип из серверной метаинформации; // - на сервере расширение в таком случае не выполняет действий, т.к. на сервере метаинформация строится сразу по всем типам и нужного типа просто нет. if (!this.clientMode || !this.clientCardMetadata.CardTypes.TryGetValue(DefaultCardTypes.KrCardTypeID, out krCardType)) { return; } }

CheckTypeFunc checkTypeFunc = this.clientMode ? (CheckTypeFunc)CheckTypeInClientMode : CheckTypeInServerMode;

List<Guid> allowedCardTypeIDs = null; foreach (CardType targetCardType in context .CardTypes .Where(x => checkTypeFunc(x, ref allowedCardTypeIDs))) { // быстрее скопировать весь тип карточки, чем отдельные его части CardType krCardTypeClone = krCardType.DeepClone();

targetCardType.SchemeItems.AddRange(krCardTypeClone.SchemeItems); targetCardType.Forms.AddRange(krCardTypeClone.Forms); targetCardType.Validators.AddRange(krCardTypeClone.Validators); } } }

Регистрация расширения на сервере:

extensionContainer .RegisterExtension<ICardMetadataExtension, KrCardMetadataExtension>(x => x .WithOrder(ExtensionStage.AfterPlatform) .WithUnity(unityContainer .RegisterType<KrCardMetadataExtension>( new ContainerControlledLifetimeManager(), new InjectionConstructor(typeof(IDbScope)))));

Регистрация расширения на клиенте (для предпросмотра):

extensionContainer .RegisterExtension<ICardMetadataExtension, KrCardMetadataExtension>(x => x .WithOrder(ExtensionStage.AfterPlatform) .WithUnity(unityContainer .RegisterType<KrCardMetadataExtension>( new ContainerControlledLifetimeManager(), new InjectionConstructor( typeof(ICardMetadata), typeof(ICardCache)))));

Back to top