diff --git a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs b/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs index ae6b6f135b..d6fff0f99d 100644 --- a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs +++ b/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs @@ -49,6 +49,16 @@ namespace Umbraco.Cms.Core.Cache _logger.LogInformation("Initializing Umbraco internal event handlers for cache refreshing."); + // bind to user and user group events + Bind(() => UserService.SavedUserGroup += UserService_SavedUserGroup, + () => UserService.SavedUserGroup -= UserService_SavedUserGroup); + Bind(() => UserService.DeletedUserGroup += UserService_DeletedUserGroup, + () => UserService.DeletedUserGroup -= UserService_DeletedUserGroup); + Bind(() => UserService.SavedUser += UserService_SavedUser, + () => UserService.SavedUser -= UserService_SavedUser); + Bind(() => UserService.DeletedUser += UserService_DeletedUser, + () => UserService.DeletedUser -= UserService_DeletedUser); + // bind to dictionary events Bind(() => LocalizationService.DeletedDictionaryItem += LocalizationService_DeletedDictionaryItem, () => LocalizationService.DeletedDictionaryItem -= LocalizationService_DeletedDictionaryItem); @@ -100,6 +110,10 @@ namespace Umbraco.Cms.Core.Cache () => MacroService.Deleted -= MacroService_Deleted); // bind to member events + Bind(() => MemberService.Saved += MemberService_Saved, + () => MemberService.Saved -= MemberService_Saved); + Bind(() => MemberService.Deleted += MemberService_Deleted, + () => MemberService.Deleted -= MemberService_Deleted); Bind(() => MemberGroupService.Saved += MemberGroupService_Saved, () => MemberGroupService.Saved -= MemberGroupService_Saved); Bind(() => MemberGroupService.Deleted += MemberGroupService_Deleted, @@ -119,6 +133,12 @@ namespace Umbraco.Cms.Core.Cache //Bind(() => ContentService.DeletedBlueprint += ContentService_DeletedBlueprint, // () => ContentService.DeletedBlueprint -= ContentService_DeletedBlueprint); + // bind to public access events + Bind(() => PublicAccessService.Saved += PublicAccessService_Saved, + () => PublicAccessService.Saved -= PublicAccessService_Saved); + Bind(() => PublicAccessService.Deleted += PublicAccessService_Deleted, + () => PublicAccessService.Deleted -= PublicAccessService_Deleted); + // bind to relation type events Bind(() => RelationService.SavedRelationType += RelationService_SavedRelationType, () => RelationService.SavedRelationType -= RelationService_SavedRelationType); @@ -126,6 +146,20 @@ namespace Umbraco.Cms.Core.Cache () => RelationService.DeletedRelationType -= RelationService_DeletedRelationType); } + #region PublicAccessService + + private void PublicAccessService_Saved(IPublicAccessService sender, SaveEventArgs e) + { + _distributedCache.RefreshPublicAccess(); + } + + private void PublicAccessService_Deleted(IPublicAccessService sender, DeleteEventArgs e) + { + _distributedCache.RefreshPublicAccess(); + } + + #endregion + #region ContentService /// @@ -259,6 +293,35 @@ namespace Umbraco.Cms.Core.Cache #endregion + #region UserService + + private void UserService_SavedUser(IUserService sender, SaveEventArgs e) + { + foreach (var entity in e.SavedEntities) + _distributedCache.RefreshUserCache(entity.Id); + } + + private void UserService_DeletedUser(IUserService sender, DeleteEventArgs e) + { + foreach (var entity in e.DeletedEntities) + _distributedCache.RemoveUserCache(entity.Id); + } + + private void UserService_SavedUserGroup(IUserService sender, SaveEventArgs e) + { + foreach (var entity in e.SavedEntities) + _distributedCache.RefreshUserGroupCache(entity.UserGroup.Id); + } + + private void UserService_DeletedUserGroup(IUserService sender, DeleteEventArgs e) + { + + foreach (var entity in e.DeletedEntities) + _distributedCache.RemoveUserGroupCache(entity.Id); + } + + #endregion + #region FileService /// @@ -314,6 +377,20 @@ namespace Umbraco.Cms.Core.Cache #endregion + #region MemberService + + private void MemberService_Deleted(IMemberService sender, DeleteEventArgs e) + { + _distributedCache.RemoveMemberCache(e.DeletedEntities.ToArray()); + } + + private void MemberService_Saved(IMemberService sender, SaveEventArgs e) + { + _distributedCache.RefreshMemberCache(e.SavedEntities.ToArray()); + } + + #endregion + #region MemberGroupService private void MemberGroupService_Deleted(IMemberGroupService sender, DeleteEventArgs e) diff --git a/src/Umbraco.Infrastructure/Cache/DistributedCacheHandler.cs b/src/Umbraco.Infrastructure/Cache/DistributedCacheHandler.cs deleted file mode 100644 index a72b37c189..0000000000 --- a/src/Umbraco.Infrastructure/Cache/DistributedCacheHandler.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Linq; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Infrastructure.Services.Notifications; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Core.Cache -{ - internal class DistributedCacheHandler : - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler - { - private readonly DistributedCache _distributedCache; - - public DistributedCacheHandler(DistributedCache distributedCache) => _distributedCache = distributedCache; - - public void Handle(MemberSavedNotification notification) => _distributedCache.RefreshMemberCache(notification.SavedEntities.ToArray()); - - public void Handle(MemberDeletedNotification notification) => _distributedCache.RemoveMemberCache(notification.DeletedEntities.ToArray()); - - public void Handle(UserSavedNotification notification) - { - foreach (var entity in notification.SavedEntities) - { - _distributedCache.RefreshUserCache(entity.Id); - } - } - - public void Handle(UserDeletedNotification notification) - { - foreach (var entity in notification.DeletedEntities) - { - _distributedCache.RemoveUserCache(entity.Id); - } - } - - public void Handle(UserGroupSavedNotification notification) - { - foreach (var entity in notification.SavedEntities) - { - _distributedCache.RefreshUserGroupCache(entity.Id); - } - } - - public void Handle(UserGroupDeletedNotification notification) - { - foreach (var entity in notification.DeletedEntities) - { - _distributedCache.RemoveUserGroupCache(entity.Id); - } - } - - public void Handle(PublicAccessEntrySavedNotification notification) => _distributedCache.RefreshPublicAccess(); - - public void Handle(PublicAccessEntryDeletedNotification notification) => _distributedCache.RefreshPublicAccess(); - } -} diff --git a/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs b/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs index d973254659..2e5c587f64 100644 --- a/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs +++ b/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs @@ -76,17 +76,6 @@ namespace Umbraco.Cms.Core.Compose .AddNotificationHandler() .AddNotificationHandler() .AddNotificationHandler(); - - // add notifications handlers for distributed cache - builder - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler(); } } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/MemberService.cs b/src/Umbraco.Infrastructure/Services/Implement/MemberService.cs index fd5c9480a7..32fc6955cf 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/MemberService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/MemberService.cs @@ -796,6 +796,7 @@ namespace Umbraco.Cms.Core.Services.Implement if (raiseEvents) { scope.Notifications.Publish(new MemberSavedNotification(member, evtMsgs).WithStateFrom(savingNotification)); + scope.Events.Dispatch(Saved, this, new SaveEventArgs(member, false)); } Audit(AuditType.Save, 0, member.Id); @@ -834,6 +835,7 @@ namespace Umbraco.Cms.Core.Services.Implement if (raiseEvents) { scope.Notifications.Publish(new MemberSavedNotification(membersA, evtMsgs).WithStateFrom(savingNotification)); + scope.Events.Dispatch(Saved, this, new SaveEventArgs(membersA, false)); } Audit(AuditType.Save, 0, -1, "Save multiple Members"); @@ -875,6 +877,7 @@ namespace Umbraco.Cms.Core.Services.Implement // a member has no descendants _memberRepository.Delete(member); scope.Notifications.Publish(new MemberDeletedNotification(member, evtMsgs).WithState(notificationState)); + scope.Events.Dispatch(Deleted, this, new DeleteEventArgs(member, false)); // media files deleted by QueuingEventDispatcher } @@ -1018,6 +1021,7 @@ namespace Umbraco.Cms.Core.Services.Implement int[] ids = _memberGroupRepository.GetMemberIds(usernames); _memberGroupRepository.AssignRoles(ids, roleNames); scope.Notifications.Publish(new AssignedMemberRolesNotification(ids, roleNames)); + scope.Complete(); } } @@ -1031,6 +1035,7 @@ namespace Umbraco.Cms.Core.Services.Implement int[] ids = _memberGroupRepository.GetMemberIds(usernames); _memberGroupRepository.DissociateRoles(ids, roleNames); scope.Notifications.Publish(new RemovedMemberRolesNotification(ids, roleNames)); + scope.Complete(); } } @@ -1043,6 +1048,7 @@ namespace Umbraco.Cms.Core.Services.Implement scope.WriteLock(Constants.Locks.MemberTree); _memberGroupRepository.AssignRoles(memberIds, roleNames); scope.Notifications.Publish(new AssignedMemberRolesNotification(memberIds, roleNames)); + scope.Complete(); } } @@ -1055,6 +1061,7 @@ namespace Umbraco.Cms.Core.Services.Implement scope.WriteLock(Constants.Locks.MemberTree); _memberGroupRepository.DissociateRoles(memberIds, roleNames); scope.Notifications.Publish(new RemovedMemberRolesNotification(memberIds, roleNames)); + scope.Complete(); } } @@ -1068,10 +1075,11 @@ namespace Umbraco.Cms.Core.Services.Implement #region Event Handlers - /// - /// Occurs after members have been exported. - /// - public static event TypedEventHandler Exported; + [Obsolete("Will be removed in an upcoming version. Implement an INotificationHandler for MemberDeletedNotification instead.")] + public static event TypedEventHandler> Deleted; + + [Obsolete("Will be removed in an upcoming version. Implement an INotificationHandler for MemberSavedNotification instead.")] + public static event TypedEventHandler> Saved; #endregion diff --git a/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs b/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs index b79b0ec0ab..afe309e8b4 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs @@ -140,6 +140,7 @@ namespace Umbraco.Cms.Core.Services.Implement scope.Complete(); scope.Notifications.Publish(new PublicAccessEntrySavedNotification(entry, evtMsgs).WithStateFrom(savingNotifiation)); + scope.Events.Dispatch(Saved, this, new SaveEventArgs(entry, false)); } return OperationResult.Attempt.Succeed(evtMsgs, entry); @@ -176,6 +177,7 @@ namespace Umbraco.Cms.Core.Services.Implement scope.Complete(); scope.Notifications.Publish(new PublicAccessEntrySavedNotification(entry, evtMsgs).WithStateFrom(savingNotifiation)); + scope.Events.Dispatch(Saved, this, new SaveEventArgs(entry, false)); } return OperationResult.Attempt.Succeed(evtMsgs); @@ -202,6 +204,7 @@ namespace Umbraco.Cms.Core.Services.Implement scope.Complete(); scope.Notifications.Publish(new PublicAccessEntrySavedNotification(entry, evtMsgs).WithStateFrom(savingNotifiation)); + scope.Events.Dispatch(Saved, this, new SaveEventArgs(entry, false)); } return OperationResult.Attempt.Succeed(evtMsgs); @@ -228,9 +231,16 @@ namespace Umbraco.Cms.Core.Services.Implement scope.Complete(); scope.Notifications.Publish(new PublicAccessEntryDeletedNotification(entry, evtMsgs).WithStateFrom(deletingNotification)); + scope.Events.Dispatch(Deleted, this, new DeleteEventArgs(entry, false)); } return OperationResult.Attempt.Succeed(evtMsgs); } + + [Obsolete("Will be removed in an upcoming version. Implement an INotificationHandler for PublicAccessEntrySavedNotification instead.")] + public static event TypedEventHandler> Saved; + + [Obsolete("Will be removed in an upcoming version. Implement an INotificationHandler for PublicAccessEntryDeletedNotification instead.")] + public static event TypedEventHandler> Deleted; } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs index 4fbe579ca3..07694ffb1a 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs @@ -142,6 +142,7 @@ namespace Umbraco.Cms.Core.Services.Implement _userRepository.Save(user); scope.Notifications.Publish(new UserSavedNotification(user, evtMsgs).WithStateFrom(savingNotification)); + scope.Events.Dispatch(SavedUser, this, new SaveEventArgs(user, false)); scope.Complete(); } @@ -255,6 +256,7 @@ namespace Umbraco.Cms.Core.Services.Implement _userRepository.Delete(user); scope.Notifications.Publish(new UserDeletedNotification(user, evtMsgs).WithStateFrom(deletingNotification)); + scope.Events.Dispatch(DeletedUser, this, new DeleteEventArgs(user, false)); scope.Complete(); } } @@ -298,6 +300,7 @@ namespace Umbraco.Cms.Core.Services.Implement if (raiseEvents) { scope.Notifications.Publish(new UserSavedNotification(entity, evtMsgs).WithStateFrom(savingNotification)); + scope.Events.Dispatch(SavedUser, this, new SaveEventArgs(entity, false)); } scope.Complete(); @@ -351,6 +354,7 @@ namespace Umbraco.Cms.Core.Services.Implement if (raiseEvents) { scope.Notifications.Publish(new UserSavedNotification(entitiesA, evtMsgs).WithStateFrom(savingNotification)); + scope.Events.Dispatch(SavedUser, this, new SaveEventArgs(entitiesA, false)); } //commit the whole lot in one go @@ -861,6 +865,7 @@ namespace Umbraco.Cms.Core.Services.Implement { scope.Notifications.Publish(new UserGroupSavedNotification(userGroup, evtMsgs).WithStateFrom(savingNotification)); scope.Notifications.Publish(new UserGroupWithUsersSavedNotification(userGroupWithUsers, evtMsgs).WithStateFrom(savingUserGroupWithUsersNotification)); + scope.Events.Dispatch(SavedUserGroup, this, new SaveEventArgs(new UserGroupWithUsers(userGroup, addedUsers, removedUsers), false)); } scope.Complete(); @@ -887,6 +892,7 @@ namespace Umbraco.Cms.Core.Services.Implement _userGroupRepository.Delete(userGroup); scope.Notifications.Publish(new UserGroupDeletedNotification(userGroup, evtMsgs).WithStateFrom(deletingNotification)); + scope.Events.Dispatch(DeletedUserGroup, this, new DeleteEventArgs(userGroup, false)); scope.Complete(); } @@ -1166,5 +1172,17 @@ namespace Umbraco.Cms.Core.Services.Implement } #endregion + + [Obsolete("Will be removed in an upcoming version. Implement an INotificationHandler for UserSavedNotification instead.")] + public static event TypedEventHandler> SavedUser; + + [Obsolete("Will be removed in an upcoming version. Implement an INotificationHandler for UserDeletedNotification instead.")] + public static event TypedEventHandler> DeletedUser; + + [Obsolete("Will be removed in an upcoming version. Implement an INotificationHandler for UserGroupSavedNotification instead.")] + public static event TypedEventHandler> SavedUserGroup; + + [Obsolete("Will be removed in an upcoming version. Implement an INotificationHandler for UserGroupDeletedNotification instead.")] + public static event TypedEventHandler> DeletedUserGroup; } } diff --git a/src/Umbraco.Tests.Integration/Cache/DistributedCacheBinderTests.cs b/src/Umbraco.Tests.Integration/Cache/DistributedCacheBinderTests.cs index 8fbe858294..9b8a1e9c98 100644 --- a/src/Umbraco.Tests.Integration/Cache/DistributedCacheBinderTests.cs +++ b/src/Umbraco.Tests.Integration/Cache/DistributedCacheBinderTests.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; @@ -17,6 +18,7 @@ namespace Umbraco.Cms.Tests.Integration.Cache [UmbracoTest(Boot = true)] public class DistributedCacheBinderTests : UmbracoIntegrationTest { + private IUserService UserService => GetRequiredService(); private ILocalizationService LocalizationService => GetRequiredService(); private IDataTypeService DataTypeService => GetRequiredService(); private IFileService FileService => GetRequiredService(); @@ -25,7 +27,11 @@ namespace Umbraco.Cms.Tests.Integration.Cache private IDomainService DomainService => GetRequiredService(); private IMemberTypeService MemberTypeService => GetRequiredService(); private IMacroService MacroService => GetRequiredService(); + private IMemberService MemberService => GetRequiredService(); private IMemberGroupService MemberGroupService => GetRequiredService(); + private IMediaService MediaService => GetRequiredService(); + private IContentService ContentService => GetRequiredService(); + private IPublicAccessService PublicAccessService => GetRequiredService(); private IRelationService RelationService => GetRequiredService(); private UriUtility UriUtility => GetRequiredService(); private IUmbracoContextFactory UmbracoContextFactory => GetRequiredService(); @@ -36,6 +42,11 @@ namespace Umbraco.Cms.Tests.Integration.Cache var definitions = new IEventDefinition[] { + new EventDefinition>(null, UserService, new SaveEventArgs(Enumerable.Empty())), + new EventDefinition>(null, UserService, new DeleteEventArgs(Enumerable.Empty())), + new EventDefinition>(null, UserService, new SaveEventArgs(Enumerable.Empty())), + new EventDefinition>(null, UserService, new DeleteEventArgs(Enumerable.Empty())), + new EventDefinition>(null, LocalizationService, new SaveEventArgs(Enumerable.Empty())), new EventDefinition>(null, LocalizationService, new DeleteEventArgs(Enumerable.Empty())), @@ -65,6 +76,9 @@ namespace Umbraco.Cms.Tests.Integration.Cache new EventDefinition>(null, MacroService, new SaveEventArgs(Enumerable.Empty())), new EventDefinition>(null, MacroService, new DeleteEventArgs(Enumerable.Empty())), + new EventDefinition>(null, MemberService, new SaveEventArgs(Enumerable.Empty())), + new EventDefinition>(null, MemberService, new DeleteEventArgs(Enumerable.Empty())), + new EventDefinition>(null, MemberGroupService, new SaveEventArgs(Enumerable.Empty())), new EventDefinition>(null, MemberGroupService, new DeleteEventArgs(Enumerable.Empty())), @@ -72,6 +86,9 @@ namespace Umbraco.Cms.Tests.Integration.Cache //new EventDefinition>(null, ContentService, new SaveEventArgs(Enumerable.Empty()), "SavedBlueprint"), //new EventDefinition>(null, ContentService, new DeleteEventArgs(Enumerable.Empty()), "DeletedBlueprint"), + new EventDefinition>(null, PublicAccessService, new SaveEventArgs(Enumerable.Empty())), + new EventDefinition>(null, PublicAccessService, new DeleteEventArgs(Enumerable.Empty())), + new EventDefinition>(null, RelationService, new SaveEventArgs(Enumerable.Empty())), new EventDefinition>(null, RelationService, new DeleteEventArgs(Enumerable.Empty())),