Создание фоновой задачи в расширениях толстого клиента¶
Для того, чтобы создать фоновую задачу в толстом клиенте, которая будет выполнять периодический опрос сервера, следует написать и зарегистрировать расширение, связанное с жизненным циклом приложения ApplicationExtension
в проекте Tessa.Extensions.Client
.
Ниже приведен пример расширения, которое периодически отправляет запрос на сервер для получения уведомлений по обсуждениям.
class ForumNotificationsApplicationExtension
: ApplicationExtension
{
#region Private Fields
private Timer timer;
private readonly INotificationButtonUIManager manager;
private readonly ILicenseManager licenseManager;
private readonly IFmNotificationProvider notificationProvider;
private readonly ISessionFailedChecker sessionFailedChecker;
private static readonly int forumRefreshInterval = 100;
private int isProcessingRequest;
#endregion
#region Constructors
public ForumNotificationsApplicationExtension(
INotificationButtonUIManager manager,
ILicenseManager licenseManager,
IFmNotificationProvider notificationProvider,
ISessionFailedChecker sessionFailedChecker)
{
this.manager = NotNullOrThrow(manager);
this.licenseManager = NotNullOrThrow(licenseManager);
this.notificationProvider = NotNullOrThrow(notificationProvider);
this.sessionFailedChecker = NotNullOrThrow(sessionFailedChecker);
}
#endregion
#region Private Methods
private async void CheckNotificationsAsync(CancellationToken cancellationToken = default)
{
// Проверяем, что сессия валидна, чтобы, в случае ошибки, не отправлять запросы на сервер
if (await this.sessionFailedChecker.IsCurrentSessionFailedAsync(cancellationToken))
{
return;
}
// Защита от одновременного выполнения запросов в случае, если операция не завершилась до следующего тика таймера
if (Interlocked.CompareExchange(ref this.isProcessingRequest, 1, 0) == 0)
{
try
{
// Открытие данного контекста позволяет не обновлять время последней активности по сессии
await using var _ = SessionRequestTypeContext.Create(SessionRequestType.Background);
this.manager.SetNotificationProvider(this.notificationProvider);
if (await this.manager.IsExistNotificationsAsync(cancellationToken))
{
await this.manager.ShowNotificationButtonAsync(false, true, cancellationToken);
}
this.manager.SetNotificationProvider(this.notificationProvider);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
await this.manager.ShowErrorAsync(ex);
}
finally
{
Interlocked.Exchange(ref this.isProcessingRequest, 0);
}
}
}
#endregion
#region BaseOverride
public override async Task Initialize(IApplicationExtensionContext context)
{
if (!LicensingHelper.CheckForumLicense(await this.licenseManager.GetLicenseAsync(context.CancellationToken), out _))
{
return;
}
if (this.timer != null)
{
await this.timer.DisposeAsync();
}
this.timer = new Timer(
p => this.CheckNotificationsAsync(),
null,
0,
forumRefreshInterval);
}
public override async Task Shutdown(IApplicationExtensionContext context)
{
if (this.timer != null)
{
await this.timer.DisposeAsync();
}
this.timer = null;
}
#endregion
}
Необходимо зарегистрировать данное расширение:
[Registrator]
public sealed class Registrator : RegistratorBase
{
public override void RegisterUnity()
{
this.UnityContainer
.RegisterType<FmNotificationsApplicationExtension>(new PerResolveLifetimeManager());
}
public override void RegisterExtensions(IExtensionContainer extensionContainer)
{
extensionContainer
.RegisterExtension<IApplicationExtension, FmNotificationsApplicationExtension>(x => x
.WithOrder(ExtensionStage.AfterPlatform, 1)
.WithUnity(this.UnityContainer)
.WhenApplications(ApplicationIdentifiers.TessaClient));
}
}