Форматтер для плейсхолдеров
Форматтер для плейсхолдеров¶
Для плейсхолдеров можно зарегистрировать форматтер, позволяющий либо сделать постобработку текстового значения, либо представить данные в отличном от строки виде, например, в виде изображения. По умолчанию форматтер работает для любых плейсхолдеров, выполняющих форматирование через объект IPlaceholderFormatter
. По умолчанию в платформе эту возможность используют все плейсхолдеры, в т.ч. {f:...}
, {t:...}
, {fv:...}
, {tv:...}
, {cardLink}
, {date}
и др.
Note
Форматтеры для плейсхолдеров доступны, начиная со сборки 2.5.2.
Для примера напишем форматтер #reverse
, который меняет порядок символов в тексте на обратный. Форматтер регистрируется в проекте Tessa.Extensions.Shared
, чтобы быть доступным как на клиенте (для форматирования Digest карточки), так и на сервере (в файловых шаблонах и всех других случаях).
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Tessa.Platform.Placeholders;
using Unity;
using Unity.Lifetime;
namespace Tessa.Extensions.Shared.Placeholders
{
public class ReversePlaceholderFormatter : PlaceholderFormatterBase
{
protected override async ValueTask<string> FormatFieldTextAsync(
IPlaceholderReplacementContext context,
IPlaceholder placeholder,
IPlaceholderFormatSettings formatSettings,
IPlaceholderFormatRequest request,
CancellationToken cancellationToken = default)
{
string text = await base.FormatFieldTextAsync(context, placeholder, formatSettings, request, cancellationToken);
return string.IsNullOrEmpty(text) ? text : new string(text.Reverse().ToArray());
}
}
[Registrator]
public sealed class Registrator : RegistratorBase
{
public override void RegisterUnity()
{
this.UnityContainer
.RegisterType<ReversePlaceholderFormatter>(new ContainerControlledLifetimeManager())
;
}
public override void FinalizeRegistration()
{
this.UnityContainer
.Resolve<IPlaceholderFormatterContainer>()
.Register("reverse", this.UnityContainer.Resolve<ReversePlaceholderFormatter>())
;
}
}
}
Пример использования: {f:DocumentCommonInfo.Subject:#reverse}
Чтобы заменить плейсхолдер на изображение, можно переопределить базовый метод FormatFieldCore
.
Форматтер также может иметь обязательные или опциональные параметры, доступные посредством метода formatSettings.GetCustomFormatParameters()
. В плейсхолдерах они задаются как {f:DocumentCommonInfo.Subject:#reverse(key=value;option1;option2)}
, где key
- это строковый параметр со значением value
, а option1
и option2
- ключи со значениями bool (если присутствуют, то имеют значение true
).
Форматтер может использовать зависимости из контейнера Unity как получив их из конструктора (один раз за время работы приложения), так и из контекста context
(каждый раз при выполнении метода форматирования). Например, если требуется из уникального идентификатора получить ссылку на открытие карточки в web-клиенте вида https://address.org/tessa/web/tessa/card/12d8cf28-9902-4dfd-8cbc-0f8a4d994691
, то можно написать форматтер #webCardLink
, который использует настройки из ICardCache
для определения адреса веб-клиента.
Посредством такого форматтера можно преобразовать идентификатор исходящего документа в ссылку, которую отобразить в виде QR-кода: {t:OutgoingRefDocs.DocID:#webCardLink;qrcode(t=url)}
using System;
using System.Threading;
using System.Threading.Tasks;
using Tessa.Cards;
using Tessa.Cards.Caching;
using Tessa.Platform.Placeholders;
using Unity;
namespace Tessa.Extensions.Shared.Placeholders
{
public class WebCardLinkPlaceholderFormatter : PlaceholderFormatterBase
{
protected override async ValueTask<string> FormatFieldTextAsync(
IPlaceholderReplacementContext context,
IPlaceholder placeholder,
IPlaceholderFormatSettings formatSettings,
IPlaceholderFormatRequest request,
CancellationToken cancellationToken = default)
{
IUnityContainer unityContainer = context.TryGetUnityContainer();
if (unityContainer != null
&& unityContainer.IsRegistered<ICardCache>()
&& request.Field.Value is Guid cardID)
{
ICardCache cardCache = unityContainer.Resolve<ICardCache>();
string webAddress = await CardHelper.TryGetWebAddressAsync(cardCache, cancellationToken: cancellationToken);
if (!string.IsNullOrEmpty(webAddress))
{
return CardHelper.GetWebLink(webAddress, cardID, normalize: false);
}
}
return null;
}
}
[Registrator]
public sealed class Registrator : RegistratorBase
{
public override void FinalizeRegistration()
{
this.UnityContainer
.Resolve<IPlaceholderFormatterContainer>()
.Register("webCardLink", new WebCardLinkPlaceholderFormatter(), true)
;
}
}
}
Note
Такой форматтер уже содержится в типовом решении, поэтому в методе регистрации указан overrideFormatterName: true
.
Аналогично можно написать плейсхолдер, который может использовать возможности форматтеров. Например, плейсхолдер {webCardLink:#qrcode(t=url)}
, отображающий ссылку на текущую карточку в виде QR-кода.
using System;
using System.Threading;
using System.Threading.Tasks;
using Tessa.Cards;
using Tessa.Cards.Caching;
using Tessa.Platform.Placeholders;
using Unity;
namespace Tessa.Extensions.Shared.Placeholders
{
public static class PlaceholderHelper
{
public static async Task<PlaceholderValue> ReplaceWebCardLinkAsync(
IPlaceholderReplacementContext context,
IPlaceholder placeholder,
CancellationToken cancellationToken = default)
{
Guid? cardID = await context.TryGetCardIDAsync();
IUnityContainer unityContainer;
if (!cardID.HasValue
|| (unityContainer = context.TryGetUnityContainer()) == null
|| !unityContainer.IsRegistered<ICardCache>())
{
return null;
}
ICardCache cardCache = unityContainer.Resolve<ICardCache>();
string webAddress = await CardHelper.TryGetWebAddressAsync(cardCache, cancellationToken: cancellationToken);
if (string.IsNullOrEmpty(webAddress))
{
return null;
}
string text = CardHelper.GetWebLink(webAddress, cardID.Value, normalize: false);
return await context.FormatTextAsync(placeholder, text, cancellationToken: cancellationToken);
}
}
[Registrator]
public sealed class Registrator : RegistratorBase
{
public override void FinalizeRegistration()
{
this.UnityContainer
.Resolve<IPlaceholderContainer>()
.Register(new FieldPlaceholderType("webCardLink", PlaceholderHelper.ReplaceWebCardLinkAsync), true)
;
}
}
}
Note
Такой плейсхолдер уже содержится в типовом решении, поэтому в методе регистрации указан overrideType: true
.