diff --git a/src/Umbraco.Core/Events/IScopedNotificationPublisher.cs b/src/Umbraco.Core/Events/IScopedNotificationPublisher.cs
index 75fbf83860..8ac4f4312d 100644
--- a/src/Umbraco.Core/Events/IScopedNotificationPublisher.cs
+++ b/src/Umbraco.Core/Events/IScopedNotificationPublisher.cs
@@ -13,7 +13,7 @@ namespace Umbraco.Cms.Core.Events
/// Supresses all notifications from being added/created until the result object is disposed.
///
///
- IDisposable Supress();
+ IDisposable Suppress();
///
/// Publishes a cancelable notification to the notification subscribers
diff --git a/src/Umbraco.Core/Events/ScopedNotificationPublisher.cs b/src/Umbraco.Core/Events/ScopedNotificationPublisher.cs
index 6ea7ee5b6a..cf6260291b 100644
--- a/src/Umbraco.Core/Events/ScopedNotificationPublisher.cs
+++ b/src/Umbraco.Core/Events/ScopedNotificationPublisher.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Reflection;
using System.Threading.Tasks;
using Umbraco.Cms.Core.Notifications;
@@ -28,7 +29,7 @@ namespace Umbraco.Cms.Core.Events
throw new ArgumentNullException(nameof(notification));
}
- if (_isSuppressed)
+ if (CanSuppress(notification) && _isSuppressed)
{
return false;
}
@@ -44,7 +45,7 @@ namespace Umbraco.Cms.Core.Events
throw new ArgumentNullException(nameof(notification));
}
- if (_isSuppressed)
+ if (CanSuppress(notification) && _isSuppressed)
{
return false;
}
@@ -60,7 +61,7 @@ namespace Umbraco.Cms.Core.Events
throw new ArgumentNullException(nameof(notification));
}
- if (_isSuppressed)
+ if (CanSuppress(notification) && _isSuppressed)
{
return;
}
@@ -86,7 +87,7 @@ namespace Umbraco.Cms.Core.Events
}
}
- public IDisposable Supress()
+ public IDisposable Suppress()
{
lock(_locker)
{
@@ -98,6 +99,9 @@ namespace Umbraco.Cms.Core.Events
}
}
+ private bool CanSuppress(INotification notification)
+ => notification.GetType().GetCustomAttribute() == null;
+
private class Suppressor : IDisposable
{
private bool _disposedValue;
diff --git a/src/Umbraco.Core/Notifications/CannotSuppressNotificationAttribute.cs b/src/Umbraco.Core/Notifications/CannotSuppressNotificationAttribute.cs
new file mode 100644
index 0000000000..8279ae4caf
--- /dev/null
+++ b/src/Umbraco.Core/Notifications/CannotSuppressNotificationAttribute.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Umbraco.Cms.Core.Notifications
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ internal sealed class CannotSuppressNotificationAttribute : Attribute
+ {
+ }
+}
diff --git a/src/Umbraco.Core/Notifications/ContentRefreshNotification.cs b/src/Umbraco.Core/Notifications/ContentRefreshNotification.cs
index 6957da7f70..f2c81d3fac 100644
--- a/src/Umbraco.Core/Notifications/ContentRefreshNotification.cs
+++ b/src/Umbraco.Core/Notifications/ContentRefreshNotification.cs
@@ -5,7 +5,9 @@ using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Core.Notifications
{
+
[Obsolete("This is only used for the internal cache and will change, use saved notifications instead")]
+ [CannotSuppressNotification]
[EditorBrowsable(EditorBrowsableState.Never)]
public class ContentRefreshNotification : EntityRefreshNotification
{
diff --git a/src/Umbraco.Core/Notifications/MediaRefreshNotification.cs b/src/Umbraco.Core/Notifications/MediaRefreshNotification.cs
index 1c8b8b9bea..4fe0f82d33 100644
--- a/src/Umbraco.Core/Notifications/MediaRefreshNotification.cs
+++ b/src/Umbraco.Core/Notifications/MediaRefreshNotification.cs
@@ -5,6 +5,7 @@ using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Core.Notifications
{
+ [CannotSuppressNotification]
[Obsolete("This is only used for the internal cache and will change, use tree change notifications instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
public class MediaRefreshNotification : EntityRefreshNotification
diff --git a/src/Umbraco.Core/Notifications/MemberRefreshNotification.cs b/src/Umbraco.Core/Notifications/MemberRefreshNotification.cs
index a22c48348f..d4dfeef68f 100644
--- a/src/Umbraco.Core/Notifications/MemberRefreshNotification.cs
+++ b/src/Umbraco.Core/Notifications/MemberRefreshNotification.cs
@@ -5,6 +5,7 @@ using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Core.Notifications
{
+ [CannotSuppressNotification]
[Obsolete("This is only used for the internal cache and will change, use tree change notifications instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
public class MemberRefreshNotification : EntityRefreshNotification
diff --git a/src/Umbraco.Core/Notifications/ScopedEntityRemoveNotification.cs b/src/Umbraco.Core/Notifications/ScopedEntityRemoveNotification.cs
index 307ae2103c..a86ea659bb 100644
--- a/src/Umbraco.Core/Notifications/ScopedEntityRemoveNotification.cs
+++ b/src/Umbraco.Core/Notifications/ScopedEntityRemoveNotification.cs
@@ -5,6 +5,7 @@ using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Core.Notifications
{
+ [CannotSuppressNotification]
[Obsolete("This is only used for the internal cache and will change, use tree change notifications instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
public class ScopedEntityRemoveNotification : ObjectNotification
diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/Services/SectionServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Services/SectionServiceTests.cs
index 1e9a80faf6..d1f25a8f82 100644
--- a/src/Umbraco.Tests.Integration/Umbraco.Core/Services/SectionServiceTests.cs
+++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Services/SectionServiceTests.cs
@@ -42,7 +42,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services
private IUser CreateTestUser()
{
using IScope scope = ScopeProvider.CreateScope(autoComplete: true);
- using IDisposable _ = scope.Notifications.Supress();
+ using IDisposable _ = scope.Notifications.Suppress();
var globalSettings = new GlobalSettings();
var user = new User(globalSettings)
diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/SupressNotificationsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/SupressNotificationsTests.cs
index 4c3fa23504..c40249b886 100644
--- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/SupressNotificationsTests.cs
+++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/SupressNotificationsTests.cs
@@ -37,7 +37,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping
public void GivenScope_WhenNotificationsSuppressed_ThenNotificationsDoNotExecute()
{
using IScope scope = ScopeProvider.CreateScope(autoComplete: true);
- using IDisposable _ = scope.Notifications.Supress();
+ using IDisposable _ = scope.Notifications.Suppress();
ContentType contentType = ContentTypeBuilder.CreateBasicContentType();
ContentTypeService.Save(contentType);
@@ -50,7 +50,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping
{
using (IScope parentScope = ScopeProvider.CreateScope(autoComplete: true))
{
- using IDisposable _ = parentScope.Notifications.Supress();
+ using IDisposable _ = parentScope.Notifications.Suppress();
using (IScope childScope = ScopeProvider.CreateScope(autoComplete: true))
{
@@ -68,7 +68,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping
int asserted = 0;
using (IScope scope = ScopeProvider.CreateScope(autoComplete: true))
{
- using IDisposable suppressed = scope.Notifications.Supress();
+ using IDisposable suppressed = scope.Notifications.Suppress();
MediaType mediaType = MediaTypeBuilder.CreateImageMediaType("test");
MediaTypeService.Save(mediaType);
@@ -83,6 +83,19 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping
Assert.AreEqual(asserted + 1, TestContext.CurrentContext.AssertCount);
}
+ [Test]
+ public void GivenSuppressedNotificationsOnParent_WhenChildSupresses_ThenExceptionIsThrown()
+ {
+ using (IScope parentScope = ScopeProvider.CreateScope(autoComplete: true))
+ using (IDisposable parentSuppressed = parentScope.Notifications.Suppress())
+ {
+ using (IScope childScope = ScopeProvider.CreateScope(autoComplete: true))
+ {
+ Assert.Throws(() => childScope.Notifications.Suppress());
+ }
+ }
+ }
+
private class TestContentNotificationHandler : INotificationHandler
{
public void Handle(ContentSavingNotification notification)