Files
Umbraco-CMS/src/Umbraco.Core/Events/ScopedNotificationPublisher.cs

149 lines
4.0 KiB
C#

// Copyright (c) Umbraco.
// See LICENSE for more details.
using Umbraco.Cms.Core.Notifications;
namespace Umbraco.Cms.Core.Events;
public class ScopedNotificationPublisher : ScopedNotificationPublisher<INotificationHandler>
{
public ScopedNotificationPublisher(IEventAggregator eventAggregator)
: base(eventAggregator)
{ }
}
public class ScopedNotificationPublisher<TNotificationHandler> : IScopedNotificationPublisher
where TNotificationHandler : INotificationHandler
{
private readonly IEventAggregator _eventAggregator;
private readonly List<INotification> _notificationOnScopeCompleted = new List<INotification>();
private readonly bool _publishCancelableNotificationOnScopeExit;
private readonly Lock _locker = new();
private bool _isSuppressed;
public ScopedNotificationPublisher(IEventAggregator eventAggregator, bool publishCancelableNotificationOnScopeExit = false)
{
_eventAggregator = eventAggregator;
_publishCancelableNotificationOnScopeExit |= publishCancelableNotificationOnScopeExit;
}
public bool PublishCancelable(ICancelableNotification notification)
{
ArgumentNullException.ThrowIfNull(notification);
if (_isSuppressed)
{
return false;
}
if (_publishCancelableNotificationOnScopeExit)
{
_notificationOnScopeCompleted.Add(notification);
}
else
{
_eventAggregator.Publish(notification);
}
return notification.Cancel;
}
public async Task<bool> PublishCancelableAsync(ICancelableNotification notification)
{
ArgumentNullException.ThrowIfNull(notification);
if (_isSuppressed)
{
return false;
}
if (_publishCancelableNotificationOnScopeExit)
{
_notificationOnScopeCompleted.Add(notification);
}
else
{
Task task = _eventAggregator.PublishAsync(notification);
if (task is not null)
{
await task;
}
}
return notification.Cancel;
}
public void Publish(INotification notification)
{
ArgumentNullException.ThrowIfNull(notification);
if (_isSuppressed)
{
return;
}
_notificationOnScopeCompleted.Add(notification);
}
public void ScopeExit(bool completed)
{
try
{
if (completed)
{
PublishScopedNotifications(_notificationOnScopeCompleted);
}
}
finally
{
_notificationOnScopeCompleted.Clear();
}
}
public IDisposable Suppress()
{
lock (_locker)
{
if (_isSuppressed)
{
throw new InvalidOperationException("Notifications are already suppressed.");
}
return new Suppressor(this);
}
}
protected virtual void PublishScopedNotifications(IList<INotification> notifications)
=> _eventAggregator.Publish<INotification, TNotificationHandler>(notifications);
private sealed class Suppressor : IDisposable
{
private readonly ScopedNotificationPublisher<TNotificationHandler> _scopedNotificationPublisher;
private bool _disposedValue;
public Suppressor(ScopedNotificationPublisher<TNotificationHandler> scopedNotificationPublisher)
{
_scopedNotificationPublisher = scopedNotificationPublisher;
_scopedNotificationPublisher._isSuppressed = true;
}
public void Dispose() => Dispose(true);
private void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
lock (_scopedNotificationPublisher._locker)
{
_scopedNotificationPublisher._isSuppressed = false;
}
}
_disposedValue = true;
}
}
}
}