Skip to content

Commit 63f4bb8

Browse files
authored
feat(Caching) : Support cache key formatting (#285)
* fix(Caching): Fix Caching * refactor: Refactored cache to support aliases * fix(Caching): Fix support TypeNameAlias * doc(Caching): Modify Caching Documents * fix: fix IdGenerator Error * fix: Fix unit test errors * test: fix unit test error * fix(Caching): Fix bad code smells * feat(Caching): Modify annotations to support IConfiguration * doc(Caching): Add documentation By UseDcc * chore: remove extra spaces * doc: Repair documentation
1 parent 4c89d76 commit 63f4bb8

File tree

69 files changed

+2264
-688
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+2264
-688
lines changed

src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/CacheClientBase.cs

+48-24
Original file line numberDiff line numberDiff line change
@@ -5,51 +5,75 @@ namespace Masa.BuildingBlocks.Caching;
55

66
public abstract class CacheClientBase : ICacheClient
77
{
8-
public abstract T? Get<T>(string key);
8+
public abstract T? Get<T>(string key, Action<CacheOptions>? action = null);
99

10-
public abstract Task<T?> GetAsync<T>(string key);
10+
public abstract Task<T?> GetAsync<T>(string key, Action<CacheOptions>? action = null);
1111

1212
public IEnumerable<T?> GetList<T>(params string[] keys)
1313
=> GetList<T>(GetKeys(keys));
1414

15-
public abstract IEnumerable<T?> GetList<T>(IEnumerable<string> keys);
15+
public abstract IEnumerable<T?> GetList<T>(IEnumerable<string> keys, Action<CacheOptions>? action = null);
1616

1717
public Task<IEnumerable<T?>> GetListAsync<T>(params string[] keys)
1818
=> GetListAsync<T>(GetKeys(keys));
1919

20-
public abstract Task<IEnumerable<T?>> GetListAsync<T>(IEnumerable<string> keys);
20+
public abstract Task<IEnumerable<T?>> GetListAsync<T>(IEnumerable<string> keys, Action<CacheOptions>? action = null);
2121

22-
public virtual void Set<T>(string key, T value, DateTimeOffset? absoluteExpiration)
23-
=> Set(key, value, new CacheEntryOptions(absoluteExpiration));
22+
public virtual void Set<T>(string key, T value, DateTimeOffset? absoluteExpiration, Action<CacheOptions>? action = null)
23+
=> Set(key, value, new CacheEntryOptions(absoluteExpiration), action);
2424

25-
public virtual void Set<T>(string key, T value, TimeSpan? absoluteExpirationRelativeToNow)
26-
=> Set(key, value, new CacheEntryOptions(absoluteExpirationRelativeToNow));
25+
public virtual void Set<T>(string key, T value, TimeSpan? absoluteExpirationRelativeToNow, Action<CacheOptions>? action = null)
26+
=> Set(key, value, new CacheEntryOptions(absoluteExpirationRelativeToNow), action);
2727

28-
public abstract void Set<T>(string key, T value, CacheEntryOptions? options = null);
28+
public abstract void Set<T>(string key, T value, CacheEntryOptions? options = null, Action<CacheOptions>? action = null);
2929

30-
public virtual Task SetAsync<T>(string key, T value, DateTimeOffset? absoluteExpiration)
31-
=> SetAsync(key, value, new CacheEntryOptions(absoluteExpiration));
30+
public virtual Task SetAsync<T>(string key, T value, DateTimeOffset? absoluteExpiration, Action<CacheOptions>? action = null)
31+
=> SetAsync(key, value, new CacheEntryOptions(absoluteExpiration), action);
3232

33-
public virtual Task SetAsync<T>(string key, T value, TimeSpan? absoluteExpirationRelativeToNow)
34-
=> SetAsync(key, value, new CacheEntryOptions(absoluteExpirationRelativeToNow));
33+
public virtual Task SetAsync<T>(string key, T value, TimeSpan? absoluteExpirationRelativeToNow, Action<CacheOptions>? action = null)
34+
=> SetAsync(key, value, new CacheEntryOptions(absoluteExpirationRelativeToNow), action);
3535

36-
public abstract Task SetAsync<T>(string key, T value, CacheEntryOptions? options = null);
36+
public abstract Task SetAsync<T>(string key, T value, CacheEntryOptions? options = null, Action<CacheOptions>? action = null);
3737

38-
public virtual void SetList<T>(Dictionary<string, T?> keyValues, DateTimeOffset? absoluteExpiration)
39-
=> SetList(keyValues, new CacheEntryOptions(absoluteExpiration));
38+
public virtual void SetList<T>(Dictionary<string, T?> keyValues,
39+
DateTimeOffset? absoluteExpiration,
40+
Action<CacheOptions>? action = null)
41+
=> SetList(keyValues, new CacheEntryOptions(absoluteExpiration), action);
4042

41-
public virtual void SetList<T>(Dictionary<string, T?> keyValues, TimeSpan? absoluteExpirationRelativeToNow)
42-
=> SetList(keyValues, new CacheEntryOptions(absoluteExpirationRelativeToNow));
43+
public virtual void SetList<T>(Dictionary<string, T?> keyValues,
44+
TimeSpan? absoluteExpirationRelativeToNow,
45+
Action<CacheOptions>? action = null)
46+
=> SetList(keyValues, new CacheEntryOptions(absoluteExpirationRelativeToNow), action);
4347

44-
public abstract void SetList<T>(Dictionary<string, T?> keyValues, CacheEntryOptions? options = null);
48+
public abstract void SetList<T>(Dictionary<string, T?> keyValues,
49+
CacheEntryOptions? options = null,
50+
Action<CacheOptions>? action = null);
4551

46-
public virtual Task SetListAsync<T>(Dictionary<string, T?> keyValues, DateTimeOffset? absoluteExpiration)
47-
=> SetListAsync(keyValues, new CacheEntryOptions(absoluteExpiration));
52+
public virtual Task SetListAsync<T>(Dictionary<string, T?> keyValues,
53+
DateTimeOffset? absoluteExpiration,
54+
Action<CacheOptions>? action = null)
55+
=> SetListAsync(keyValues, new CacheEntryOptions(absoluteExpiration), action);
4856

49-
public virtual Task SetListAsync<T>(Dictionary<string, T?> keyValues, TimeSpan? absoluteExpirationRelativeToNow)
50-
=> SetListAsync(keyValues, new CacheEntryOptions(absoluteExpirationRelativeToNow));
57+
public virtual Task SetListAsync<T>(Dictionary<string, T?> keyValues,
58+
TimeSpan? absoluteExpirationRelativeToNow,
59+
Action<CacheOptions>? action = null)
60+
=> SetListAsync(keyValues, new CacheEntryOptions(absoluteExpirationRelativeToNow), action);
5161

52-
public abstract Task SetListAsync<T>(Dictionary<string, T?> keyValues, CacheEntryOptions? options = null);
62+
public abstract Task SetListAsync<T>(Dictionary<string, T?> keyValues,
63+
CacheEntryOptions? options = null,
64+
Action<CacheOptions>? action = null);
65+
66+
public abstract void Remove<T>(string key, Action<CacheOptions>? action = null);
67+
68+
public abstract void Remove<T>(IEnumerable<string> keys, Action<CacheOptions>? action = null);
69+
70+
public abstract Task RemoveAsync<T>(string key, Action<CacheOptions>? action = null);
71+
72+
public abstract Task RemoveAsync<T>(IEnumerable<string> keys, Action<CacheOptions>? action = null);
73+
74+
public abstract void Refresh<T>(IEnumerable<string> keys, Action<CacheOptions>? action = null);
75+
76+
public abstract Task RefreshAsync<T>(IEnumerable<string> keys, Action<CacheOptions>? action = null);
5377

5478
protected static IEnumerable<string> GetKeys(params string[] keys) => keys;
5579
}

src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/DistributedCacheClientBase.cs

+55-17
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,44 @@ namespace Masa.BuildingBlocks.Caching;
55

66
public abstract class DistributedCacheClientBase : CacheClientBase, IDistributedCacheClient
77
{
8-
public abstract T? GetOrSet<T>(string key, Func<CacheEntry<T>> setter);
8+
public abstract T? GetOrSet<T>(string key, Func<CacheEntry<T>> setter, Action<CacheOptions>? action = null);
99

10-
public abstract Task<T?> GetOrSetAsync<T>(string key, Func<CacheEntry<T>> setter);
10+
public abstract Task<T?> GetOrSetAsync<T>(string key, Func<CacheEntry<T>> setter, Action<CacheOptions>? action = null);
1111

12-
public void Refresh(params string[] keys) => Refresh(GetKeys(keys));
12+
public abstract void Refresh(params string[] keys);
1313

14-
public abstract void Refresh(IEnumerable<string> keys);
14+
public abstract Task RefreshAsync(params string[] keys);
1515

16-
public Task RefreshAsync(params string[] keys) => RefreshAsync(GetKeys(keys));
16+
public abstract void Remove(params string[] keys);
1717

18-
public abstract Task RefreshAsync(IEnumerable<string> keys);
18+
public override void Remove<T>(string key, Action<CacheOptions>? action = null)
19+
=> Remove<T>(new[] { key }, action);
1920

20-
public virtual void Remove(params string[] keys) => Remove(GetKeys(keys));
21+
public abstract Task RemoveAsync(params string[] keys);
2122

22-
public abstract void Remove(IEnumerable<string> keys);
23-
24-
public Task RemoveAsync(params string[] keys) => RemoveAsync(GetKeys(keys));
25-
26-
public abstract Task RemoveAsync(IEnumerable<string> keys);
23+
public override Task RemoveAsync<T>(string key, Action<CacheOptions>? action = null)
24+
=> RemoveAsync<T>(new[] { key }, action);
2725

2826
public abstract bool Exists(string key);
2927

28+
public abstract bool Exists<T>(string key, Action<CacheOptions>? action = null);
29+
3030
public abstract Task<bool> ExistsAsync(string key);
3131

32+
public abstract Task<bool> ExistsAsync<T>(string key, Action<CacheOptions>? action = null);
33+
3234
public abstract IEnumerable<string> GetKeys(string keyPattern);
3335

36+
public abstract IEnumerable<string> GetKeys<T>(string keyPattern, Action<CacheOptions>? action = null);
37+
3438
public abstract Task<IEnumerable<string>> GetKeysAsync(string keyPattern);
3539

36-
public abstract IEnumerable<KeyValuePair<string, T?>> GetByKeyPattern<T>(string keyPattern);
40+
public abstract Task<IEnumerable<string>> GetKeysAsync<T>(string keyPattern, Action<CacheOptions>? action = null);
41+
42+
public abstract IEnumerable<KeyValuePair<string, T?>> GetByKeyPattern<T>(string keyPattern, Action<CacheOptions>? action = null);
3743

38-
public abstract Task<IEnumerable<KeyValuePair<string, T?>>> GetByKeyPatternAsync<T>(string keyPattern);
44+
public abstract Task<IEnumerable<KeyValuePair<string, T?>>> GetByKeyPatternAsync<T>(string keyPattern,
45+
Action<CacheOptions>? action = null);
3946

4047
public abstract void Publish(string channel, Action<PublishOptions> options);
4148

@@ -45,27 +52,58 @@ public abstract class DistributedCacheClientBase : CacheClientBase, IDistributed
4552

4653
public abstract Task SubscribeAsync<T>(string channel, Action<SubscribeOptions<T>> options);
4754

48-
public abstract Task<long> HashIncrementAsync(string key, long value = 1);
55+
public abstract Task<long> HashIncrementAsync(
56+
string key,
57+
long value = 1,
58+
Action<CacheOptions>? action = null);
4959

50-
public abstract Task<long> HashDecrementAsync(string key, long value = 1, long defaultMinVal = 0);
60+
public abstract Task<long> HashDecrementAsync(string key,
61+
long value = 1L,
62+
long defaultMinVal = 0L,
63+
Action<CacheOptions>? action = null);
5164

5265
public virtual bool KeyExpire(string key, TimeSpan? absoluteExpirationRelativeToNow)
5366
=> KeyExpire(key, new CacheEntryOptions(absoluteExpirationRelativeToNow));
5467

68+
public virtual bool KeyExpire<T>(string key, TimeSpan? absoluteExpirationRelativeToNow, Action<CacheOptions>? action = null)
69+
=> KeyExpire<T>(key, new CacheEntryOptions(absoluteExpirationRelativeToNow), action);
70+
5571
public virtual bool KeyExpire(string key, DateTimeOffset absoluteExpiration)
5672
=> KeyExpire(key, new CacheEntryOptions(absoluteExpiration));
5773

74+
public virtual bool KeyExpire<T>(string key, DateTimeOffset absoluteExpiration, Action<CacheOptions>? action = null)
75+
=> KeyExpire<T>(key, new CacheEntryOptions(absoluteExpiration), action);
76+
5877
public abstract bool KeyExpire(string key, CacheEntryOptions? options = null);
5978

79+
public abstract bool KeyExpire<T>(string key, CacheEntryOptions? options = null, Action<CacheOptions>? action = null);
80+
6081
public abstract long KeyExpire(IEnumerable<string> keys, CacheEntryOptions? options = null);
6182

83+
public abstract long KeyExpire<T>(IEnumerable<string> keys, CacheEntryOptions? options = null, Action<CacheOptions>? action = null);
84+
6285
public virtual Task<bool> KeyExpireAsync(string key, DateTimeOffset absoluteExpiration)
6386
=> KeyExpireAsync(key, new CacheEntryOptions(absoluteExpiration));
6487

88+
public virtual Task<bool> KeyExpireAsync<T>(string key, DateTimeOffset absoluteExpiration, Action<CacheOptions>? action = null)
89+
=> KeyExpireAsync<T>(key, new CacheEntryOptions(absoluteExpiration), action);
90+
6591
public virtual Task<bool> KeyExpireAsync(string key, TimeSpan? absoluteExpirationRelativeToNow)
6692
=> KeyExpireAsync(key, new CacheEntryOptions(absoluteExpirationRelativeToNow));
6793

94+
public virtual Task<bool> KeyExpireAsync<T>(string key, TimeSpan? absoluteExpirationRelativeToNow, Action<CacheOptions>? action = null)
95+
=> KeyExpireAsync<T>(key, new CacheEntryOptions(absoluteExpirationRelativeToNow), action);
96+
6897
public abstract Task<bool> KeyExpireAsync(string key, CacheEntryOptions? options = null);
6998

70-
public abstract Task<long> KeyExpireAsync(IEnumerable<string> keys, CacheEntryOptions? options = null);
99+
public abstract Task<bool> KeyExpireAsync<T>(string key, CacheEntryOptions? options = null, Action<CacheOptions>? action = null);
100+
101+
public abstract Task<long> KeyExpireAsync(
102+
IEnumerable<string> keys,
103+
CacheEntryOptions? options = null);
104+
105+
public abstract Task<long> KeyExpireAsync<T>(
106+
IEnumerable<string> keys,
107+
CacheEntryOptions? options = null,
108+
Action<CacheOptions>? action = null);
71109
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) MASA Stack All rights reserved.
2+
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
3+
4+
namespace Masa.BuildingBlocks.Caching;
5+
6+
public enum CacheKeyType
7+
{
8+
/// <summary>
9+
/// Keep it the same, use the key directly
10+
/// </summary>
11+
None = 1,
12+
13+
/// <summary>
14+
/// Type's name(Type's full name with generic type name) and key combination
15+
/// </summary>
16+
TypeName,
17+
18+
/// <summary>
19+
/// Type Alias and key combination, Format: ${TypeAliasName}{:}{key}
20+
/// </summary>
21+
TypeAlias
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) MASA Stack All rights reserved.
2+
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
3+
4+
namespace Masa.BuildingBlocks.Caching.Extensions;
5+
6+
/// <summary>
7+
/// It is only used for inheritance by Contrib implementation, and does not support the extension of IServiceCollection to avoid reference barriers
8+
/// </summary>
9+
public static class ServiceCollectionExtensions
10+
{
11+
public static IServiceCollection TryAddDistributedCacheCore(IServiceCollection services, string name)
12+
{
13+
MasaApp.TrySetServiceCollection(services);
14+
services.TryAddSingleton<IDistributedCacheClientFactory, DistributedCacheClientFactoryBase>();
15+
services.TryAddSingleton(serviceProvider
16+
=> serviceProvider.GetRequiredService<IDistributedCacheClientFactory>().Create());
17+
18+
services.TryAddSingleton<ITypeAliasFactory, DefaultTypeAliasFactory>();
19+
services.TryAddSingleton<ITypeAliasProvider, DefaultTypeAliasProvider>();
20+
services.Configure<TypeAliasFactoryOptions>(options => options.TryAdd(name));
21+
return services;
22+
}
23+
24+
public static IServiceCollection TryAddMultilevelCacheCore(IServiceCollection services, string name)
25+
{
26+
MasaApp.TrySetServiceCollection(services);
27+
services.TryAddSingleton<IMultilevelCacheClientFactory, MultilevelCacheClientFactoryBase>();
28+
services.TryAddSingleton(serviceProvider
29+
=> serviceProvider.GetRequiredService<IMultilevelCacheClientFactory>().Create());
30+
31+
services.TryAddSingleton<ITypeAliasFactory, DefaultTypeAliasFactory>();
32+
services.TryAddSingleton<ITypeAliasProvider, DefaultTypeAliasProvider>();
33+
services.Configure<TypeAliasFactoryOptions>(options => options.TryAdd(name));
34+
35+
TryAddDistributedCacheCore(services, name);
36+
return services;
37+
}
38+
}

src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Extensions/ServiceCollectionExtensions.cs

+17-13
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,25 @@ namespace Microsoft.Extensions.DependencyInjection;
66

77
public static class ServiceCollectionExtensions
88
{
9-
public static IServiceCollection TryAddDistributedCacheCore(this IServiceCollection services)
10-
{
11-
MasaApp.TrySetServiceCollection(services);
12-
services.TryAddSingleton<IDistributedCacheClientFactory, DistributedCacheClientFactoryBase>();
13-
services.TryAddSingleton(serviceProvider
14-
=> serviceProvider.GetRequiredService<IDistributedCacheClientFactory>().Create());
15-
return services;
16-
}
9+
public static IServiceCollection AddDistributedCache(
10+
this IServiceCollection services,
11+
Action<DistributedCacheOptions> action,
12+
Action<TypeAliasOptions>? typeAliasOptionsAction = null)
13+
=> services.AddDistributedCache(Microsoft.Extensions.Options.Options.DefaultName, action, typeAliasOptionsAction);
1714

18-
public static IServiceCollection TryAddMultilevelCacheCore(this IServiceCollection services)
15+
public static IServiceCollection AddDistributedCache(
16+
this IServiceCollection services,
17+
string name,
18+
Action<DistributedCacheOptions> action,
19+
Action<TypeAliasOptions>? typeAliasOptionsAction = null)
1920
{
20-
MasaApp.TrySetServiceCollection(services);
21-
services.TryAddSingleton<IMultilevelCacheClientFactory, MultilevelCacheClientFactoryBase>();
22-
services.TryAddSingleton(serviceProvider
23-
=> serviceProvider.GetRequiredService<IMultilevelCacheClientFactory>().Create());
21+
Masa.BuildingBlocks.Caching.Extensions.ServiceCollectionExtensions.TryAddDistributedCacheCore(services, name);
22+
DistributedCacheOptions options = new(services, name);
23+
action.Invoke(options);
24+
25+
if (typeAliasOptionsAction != null)
26+
services.Configure(name, typeAliasOptionsAction);
27+
2428
return services;
2529
}
2630
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) MASA Stack All rights reserved.
2+
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
3+
4+
namespace Masa.BuildingBlocks.Caching;
5+
6+
public static class CacheKeyHelper
7+
{
8+
public static string FormatCacheKey<T>(string key, CacheKeyType cacheKeyType, Func<string, string>? typeAliasFunc = null)
9+
{
10+
switch (cacheKeyType)
11+
{
12+
case CacheKeyType.None:
13+
return key;
14+
case CacheKeyType.TypeName:
15+
return $"{GetTypeName<T>()}.{key}";
16+
case CacheKeyType.TypeAlias:
17+
if (typeAliasFunc == null)
18+
throw new NotImplementedException();
19+
20+
var typeName = GetTypeName<T>();
21+
return $"{typeAliasFunc.Invoke(typeName)}:{key}";
22+
default:
23+
throw new NotImplementedException();
24+
}
25+
}
26+
27+
public static string GetTypeName<T>()
28+
{
29+
var type = typeof(T);
30+
if (type.IsGenericType)
31+
{
32+
var dictType = typeof(Dictionary<,>);
33+
if (type.GetGenericTypeDefinition() == dictType)
34+
return type.Name + "[" + type.GetGenericArguments()[1].Name + "]";
35+
36+
return type.Name + "[" + type.GetGenericArguments()[0].Name + "]";
37+
}
38+
39+
return typeof(T).Name;
40+
}
41+
}

src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Helper/SubscribeHelper.cs

-24
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,6 @@ namespace Masa.BuildingBlocks.Caching;
55

66
public static class SubscribeHelper
77
{
8-
/// <summary>
9-
/// Formats the memory cache key.
10-
/// </summary>
11-
/// <param name="key">The key.</param>
12-
/// <returns>A string.</returns>
13-
public static string FormatMemoryCacheKey<T>(string key)
14-
{
15-
var type = typeof(T);
16-
if (type.IsGenericType)
17-
{
18-
var dictType = typeof(Dictionary<,>);
19-
if (type.GetGenericTypeDefinition() == dictType)
20-
key += type.Name + "[" + type.GetGenericArguments()[1].Name + "]";
21-
else
22-
key += type.Name + "[" + type.GetGenericArguments()[0].Name + "]";
23-
}
24-
else
25-
{
26-
key += typeof(T).Name;
27-
}
28-
29-
return key;
30-
}
31-
328
/// <summary>
339
/// Formats the subscribe channel.
3410
/// </summary>

0 commit comments

Comments
 (0)