Skip to content

Commit 118b26a

Browse files
authored
Clear member cache by older user name when member user name is updated (16) (#19690)
* Pass notification state to cache refreshers. Pass previous user name into member saved notification state and use when refreshing cache to clear the member by keys based on this. * Fixed issue raised in code review. * Fixed casing for state key. * Added removed parameter to unit tests. * Fix breaking change.
1 parent e00dcef commit 118b26a

File tree

33 files changed

+312
-10
lines changed

33 files changed

+312
-10
lines changed

src/Umbraco.Core/Cache/DistributedCacheExtensions.cs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Umbraco.Cms.Core.Cache;
55
using Umbraco.Cms.Core.Models;
66
using Umbraco.Cms.Core.Models.Membership;
7+
using Umbraco.Cms.Core.Notifications;
78
using Umbraco.Cms.Core.Services.Changes;
89

910
namespace Umbraco.Extensions;
@@ -152,11 +153,49 @@ public static void RefreshContentCache(this DistributedCache dc, IEnumerable<Tre
152153

153154
#region MemberCacheRefresher
154155

156+
[Obsolete("Please use the overload taking all parameters. Scheduled for removal in Umbraco 18.")]
155157
public static void RefreshMemberCache(this DistributedCache dc, IEnumerable<IMember> members)
156-
=> dc.RefreshByPayload(MemberCacheRefresher.UniqueId, members.DistinctBy(x => (x.Id, x.Username)).Select(x => new MemberCacheRefresher.JsonPayload(x.Id, x.Username, false)));
158+
=> dc.RefreshMemberCache(members, new Dictionary<string, object?>());
157159

160+
public static void RefreshMemberCache(this DistributedCache dc, IEnumerable<IMember> members, IDictionary<string, object?> state)
161+
=> dc.RefreshByPayload(
162+
MemberCacheRefresher.UniqueId,
163+
GetPayloads(members, state, false));
164+
165+
[Obsolete("Please use the overload taking all parameters. Scheduled for removal in Umbraco 18.")]
158166
public static void RemoveMemberCache(this DistributedCache dc, IEnumerable<IMember> members)
159-
=> dc.RefreshByPayload(MemberCacheRefresher.UniqueId, members.DistinctBy(x => (x.Id, x.Username)).Select(x => new MemberCacheRefresher.JsonPayload(x.Id, x.Username, true)));
167+
=> dc.RemoveMemberCache(members, new Dictionary<string, object?>());
168+
169+
public static void RemoveMemberCache(this DistributedCache dc, IEnumerable<IMember> members, IDictionary<string, object?> state)
170+
=> dc.RefreshByPayload(
171+
MemberCacheRefresher.UniqueId,
172+
GetPayloads(members, state, true));
173+
174+
// Internal for unit test.
175+
internal static IEnumerable<MemberCacheRefresher.JsonPayload> GetPayloads(IEnumerable<IMember> members, IDictionary<string, object?> state, bool removed)
176+
=> members
177+
.DistinctBy(x => (x.Id, x.Username))
178+
.Select(x => new MemberCacheRefresher.JsonPayload(x.Id, x.Username, removed)
179+
{
180+
PreviousUsername = GetPreviousUsername(x, state)
181+
});
182+
183+
private static string? GetPreviousUsername(IMember x, IDictionary<string, object?> state)
184+
{
185+
if (state.TryGetValue(MemberSavedNotification.PreviousUsernameStateKey, out object? previousUserNames) is false)
186+
{
187+
return null;
188+
}
189+
190+
if (previousUserNames is not IDictionary<Guid, string> previousUserNamesDictionary)
191+
{
192+
return null;
193+
}
194+
195+
return previousUserNamesDictionary.TryGetValue(x.Key, out string? previousUsername)
196+
? previousUsername
197+
: null;
198+
}
160199

161200
#endregion
162201

src/Umbraco.Core/Cache/NotificationHandlers/DistributedCacheNotificationHandlerBase.cs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,20 @@ public abstract class DistributedCacheNotificationHandlerBase<TEntity, TNotifica
1010
{
1111
/// <inheritdoc />
1212
public void Handle(TNotification notification)
13-
=> Handle(GetEntities(notification));
13+
=> Handle(
14+
GetEntities(notification),
15+
notification is StatefulNotification statefulNotification
16+
? statefulNotification.State
17+
: new Dictionary<string, object?>());
1418

1519
/// <inheritdoc />
1620
public void Handle(IEnumerable<TNotification> notifications)
17-
=> Handle(notifications.SelectMany(GetEntities));
21+
{
22+
foreach (TNotification notification in notifications)
23+
{
24+
Handle(notification);
25+
}
26+
}
1827

1928
/// <summary>
2029
/// Gets the entities from the specified notification.
@@ -25,9 +34,23 @@ public void Handle(IEnumerable<TNotification> notifications)
2534
/// </returns>
2635
protected abstract IEnumerable<TEntity> GetEntities(TNotification notification);
2736

37+
// TODO (V18): When removing the obsolete method, make the remaining Handle method abstract
38+
// rather than virtual. It couldn't be made abstract when introduced as that would be a breaking change.
39+
2840
/// <summary>
2941
/// Handles the specified entities.
3042
/// </summary>
3143
/// <param name="entities">The entities.</param>
44+
[Obsolete("Please use the overload taking all parameters. Scheduled for removal in Umbraco 18.")]
3245
protected abstract void Handle(IEnumerable<TEntity> entities);
46+
47+
/// <summary>
48+
/// Handles the specified entities.
49+
/// </summary>
50+
/// <param name="entities">The entities.</param>
51+
/// <param name="state">The notification state.</param>
52+
protected virtual void Handle(IEnumerable<TEntity> entities, IDictionary<string, object?> state)
53+
#pragma warning disable CS0618 // Type or member is obsolete
54+
=> Handle(entities);
55+
#pragma warning restore CS0618 // Type or member is obsolete
3356
}

src/Umbraco.Core/Cache/NotificationHandlers/Implement/ContentTreeChangeDistributedCacheNotificationHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public ContentTreeChangeDistributedCacheNotificationHandler(DistributedCache dis
1818
=> _distributedCache = distributedCache;
1919

2020
/// <inheritdoc />
21+
[Obsolete("Scheduled for removal in Umbraco 18.")]
2122
protected override void Handle(IEnumerable<TreeChange<IContent>> entities)
23+
=> Handle(entities, new Dictionary<string, object?>());
24+
25+
/// <inheritdoc />
26+
protected override void Handle(IEnumerable<TreeChange<IContent>> entities, IDictionary<string, object?> state)
2227
=> _distributedCache.RefreshContentCache(entities);
2328
}

src/Umbraco.Core/Cache/NotificationHandlers/Implement/ContentTypeChangedDistributedCacheNotificationHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public ContentTypeChangedDistributedCacheNotificationHandler(DistributedCache di
1818
=> _distributedCache = distributedCache;
1919

2020
/// <inheritdoc />
21+
[Obsolete("Scheduled for removal in Umbraco 18.")]
2122
protected override void Handle(IEnumerable<ContentTypeChange<IContentType>> entities)
23+
=> Handle(entities, new Dictionary<string, object?>());
24+
25+
/// <inheritdoc />
26+
protected override void Handle(IEnumerable<ContentTypeChange<IContentType>> entities, IDictionary<string, object?> state)
2227
=> _distributedCache.RefreshContentTypeCache(entities);
2328
}

src/Umbraco.Core/Cache/NotificationHandlers/Implement/DataTypeDeletedDistributedCacheNotificationHandler.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Umbraco.Cms.Core.Models;
22
using Umbraco.Cms.Core.Notifications;
3+
using Umbraco.Cms.Core.Services.Changes;
34
using Umbraco.Extensions;
45

56
namespace Umbraco.Cms.Core.Cache;
@@ -17,7 +18,12 @@ public DataTypeDeletedDistributedCacheNotificationHandler(DistributedCache distr
1718
=> _distributedCache = distributedCache;
1819

1920
/// <inheritdoc />
21+
[Obsolete("Scheduled for removal in Umbraco 18.")]
2022
protected override void Handle(IEnumerable<IDataType> entities)
23+
=> Handle(entities, new Dictionary<string, object?>());
24+
25+
/// <inheritdoc />
26+
protected override void Handle(IEnumerable<IDataType> entities, IDictionary<string, object?> state)
2127
{
2228
_distributedCache.RemoveDataTypeCache(entities);
2329
_distributedCache.RefreshValueEditorCache(entities);

src/Umbraco.Core/Cache/NotificationHandlers/Implement/DataTypeSavedDistributedCacheNotificationHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@ public DataTypeSavedDistributedCacheNotificationHandler(DistributedCache distrib
1717
=> _distributedCache = distributedCache;
1818

1919
/// <inheritdoc />
20+
[Obsolete("Scheduled for removal in Umbraco 18.")]
2021
protected override void Handle(IEnumerable<IDataType> entities)
22+
=> Handle(entities, new Dictionary<string, object?>());
23+
24+
/// <inheritdoc />
25+
protected override void Handle(IEnumerable<IDataType> entities, IDictionary<string, object?> state)
2126
{
2227
_distributedCache.RefreshDataTypeCache(entities);
2328
_distributedCache.RefreshValueEditorCache(entities);

src/Umbraco.Core/Cache/NotificationHandlers/Implement/DictionaryItemDeletedDistributedCacheNotificationHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ public DictionaryItemDeletedDistributedCacheNotificationHandler(DistributedCache
1717
=> _distributedCache = distributedCache;
1818

1919
/// <inheritdoc />
20+
[Obsolete("Scheduled for removal in Umbraco 18.")]
2021
protected override void Handle(IEnumerable<IDictionaryItem> entities)
22+
=> Handle(entities, new Dictionary<string, object?>());
23+
24+
/// <inheritdoc />
25+
protected override void Handle(IEnumerable<IDictionaryItem> entities, IDictionary<string, object?> state)
2126
=> _distributedCache.RemoveDictionaryCache(entities);
2227
}

src/Umbraco.Core/Cache/NotificationHandlers/Implement/DictionaryItemSavedDistributedCacheNotificationHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ public DictionaryItemSavedDistributedCacheNotificationHandler(DistributedCache d
1717
=> _distributedCache = distributedCache;
1818

1919
/// <inheritdoc />
20+
[Obsolete("Scheduled for removal in Umbraco 18.")]
2021
protected override void Handle(IEnumerable<IDictionaryItem> entities)
22+
=> Handle(entities, new Dictionary<string, object?>());
23+
24+
/// <inheritdoc />
25+
protected override void Handle(IEnumerable<IDictionaryItem> entities, IDictionary<string, object?> state)
2126
=> _distributedCache.RefreshDictionaryCache(entities);
2227
}

src/Umbraco.Core/Cache/NotificationHandlers/Implement/DomainDeletedDistributedCacheNotificationHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ public DomainDeletedDistributedCacheNotificationHandler(DistributedCache distrib
1717
=> _distributedCache = distributedCache;
1818

1919
/// <inheritdoc />
20+
[Obsolete("Scheduled for removal in Umbraco 18.")]
2021
protected override void Handle(IEnumerable<IDomain> entities)
22+
=> Handle(entities, new Dictionary<string, object?>());
23+
24+
/// <inheritdoc />
25+
protected override void Handle(IEnumerable<IDomain> entities, IDictionary<string, object?> state)
2126
=> _distributedCache.RemoveDomainCache(entities);
2227
}

src/Umbraco.Core/Cache/NotificationHandlers/Implement/DomainSavedDistributedCacheNotificationHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ public DomainSavedDistributedCacheNotificationHandler(DistributedCache distribut
1717
=> _distributedCache = distributedCache;
1818

1919
/// <inheritdoc />
20+
[Obsolete("Scheduled for removal in Umbraco 18.")]
2021
protected override void Handle(IEnumerable<IDomain> entities)
22+
=> Handle(entities, new Dictionary<string, object?>());
23+
24+
/// <inheritdoc />
25+
protected override void Handle(IEnumerable<IDomain> entities, IDictionary<string, object?> state)
2126
=> _distributedCache.RefreshDomainCache(entities);
2227
}

0 commit comments

Comments
 (0)