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

Управления событиями веб-сервера Kestrel

Управления событиями веб-сервера Kestrel

Для подписки на событие завершение веб-сервера Kestrel, или для управления другими возможностями DI-контейнера ASP.NET Core, в контейнере Unity доступен интерфейс System.IServiceProvider, который предоставляет доступ к зависимостям, зарегистрированным в DI-контейнере ASP.NET Core, таким как сервис IHostApplicationLifetime, который позволяет отслеживать завершение приложения веб-сервиса. Если ваше расширение может быть запущено не только для веб-сервиса, то указывайте [OptionalDependency] для этого интерфейса.

Note

Указанный в примере код работоспособен, начиная со сборки платформы 3.5.0.

В проекте расширений Tessa.Extensions.Server, который будет содержать серверную логику подписки на событие завершения веб-сервера, добавьте ссылку на NuGet-пакет Microsoft.Extensions.Hosting.Abstractions той же версии, которая используется в текущей версии .NET Core (для сборки платформы 3.5.0 это версия пакета 3.1.10).

Поскольку Unity-контейнер может пересоздаваться несколько раз за время работы веб-сервера, то даже для расширения с ContainerControlledLifetimeManager не гарантируется, что экземпляр его класса существует ровно один за всё время работы сервера. Поэтому в примере используются статические поля subscribed и subscriptionLock для синхронизации подписки на событие, чтобы в приложении было не более одного обработчика событий. Если для вашего сценария это не требуется, то можно сразу вызвать метод ApplicationStopping.Register без дополнительных проверок.

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

using System; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; using NLog; using Tessa.BusinessCalendar; using Tessa.Cards; using Tessa.Cards.Extensions; using Tessa.Platform; using Tessa.Platform.Runtime; using Unity; using Unity.Lifetime;

namespace Tessa.Extensions.Server { public class WriteToLogOnShutdownExtension : CardRequestExtension { public WriteToLogOnShutdownExtension([OptionalDependency] IServiceProvider serviceProvider = null) { this.serviceProvider = serviceProvider; }

private readonly IServiceProvider serviceProvider;

private static bool subscribed;

private static readonly object subscriptionLock = new object();

private static readonly ILogger logger = LogManager.GetCurrentClassLogger();

public override async Task AfterRequest(ICardRequestExtensionContext context) { if (!context.RequestIsSuccessful || !context.Session.User.IsAdministrator()) { return; }

if (!subscribed) { var applicationLifetime = this.serviceProvider?.GetService<IHostApplicationLifetime>(); if (applicationLifetime != null) { lock (subscriptionLock) { if (!subscribed) { applicationLifetime.ApplicationStopping.Register(() => { logger.Info("Application is stopping from " + typeof(WriteToLogOnShutdownExtension).FullName); });

subscribed = true; } } } } } }

[Registrator] public sealed class WriteToLogRegistrator : RegistratorBase { public override void RegisterUnity() { this.UnityContainer .RegisterType<WriteToLogOnShutdownExtension>(new ContainerControlledLifetimeManager()); }

public override void RegisterExtensions(IExtensionContainer extensionContainer) { extensionContainer .RegisterExtension<ICardRequestExtension, WriteToLogOnShutdownExtension>(x => x .WithOrder(ExtensionStage.AfterPlatform) .WithUnity(this.UnityContainer) .WhenRequestTypes(BusinessCalendarServiceRequestTypes.ValidateCalendar)); } } }

Back to top