xf 2 lat temu
rodzic
commit
a13a49f835

+ 7 - 7
CallCenter.sln

@@ -35,10 +35,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CallCenter.NewRock", "src\C
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CallCenter.Repository.SqlSugar", "src\CallCenter.Repository.SqlSugar\CallCenter.Repository.SqlSugar.csproj", "{E1762DB1-A366-495D-AE6A-079623E840C9}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CallCenter.CacheManager", "src\CallCenter.CacheManager\CallCenter.CacheManager.csproj", "{C044AA74-C9FA-4754-AB86-0AFDB7032D13}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CallCenter.Application.Contracts", "src\CallCenter.Application.Contracts\CallCenter.Application.Contracts.csproj", "{47361A16-ECC5-40C5-9A58-23D46DCD2A0B}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CallCenter.Caching", "src\CallCenter.Caching\CallCenter.Caching.csproj", "{D5A1C483-8C49-48C1-8582-8DADA32BDF65}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -85,14 +85,14 @@ Global
 		{E1762DB1-A366-495D-AE6A-079623E840C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{E1762DB1-A366-495D-AE6A-079623E840C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{E1762DB1-A366-495D-AE6A-079623E840C9}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C044AA74-C9FA-4754-AB86-0AFDB7032D13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C044AA74-C9FA-4754-AB86-0AFDB7032D13}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C044AA74-C9FA-4754-AB86-0AFDB7032D13}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C044AA74-C9FA-4754-AB86-0AFDB7032D13}.Release|Any CPU.Build.0 = Release|Any CPU
 		{47361A16-ECC5-40C5-9A58-23D46DCD2A0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{47361A16-ECC5-40C5-9A58-23D46DCD2A0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{47361A16-ECC5-40C5-9A58-23D46DCD2A0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{47361A16-ECC5-40C5-9A58-23D46DCD2A0B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D5A1C483-8C49-48C1-8582-8DADA32BDF65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D5A1C483-8C49-48C1-8582-8DADA32BDF65}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D5A1C483-8C49-48C1-8582-8DADA32BDF65}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D5A1C483-8C49-48C1-8582-8DADA32BDF65}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -112,8 +112,8 @@ Global
 		{D75BA722-82C5-4DDF-9F15-B4F53A6A8116} = {61683AC9-2CA4-4E27-BA98-5D2497E21FF6}
 		{FAD0AC30-DA50-47C2-9985-66ABA359F54F} = {61683AC9-2CA4-4E27-BA98-5D2497E21FF6}
 		{E1762DB1-A366-495D-AE6A-079623E840C9} = {61683AC9-2CA4-4E27-BA98-5D2497E21FF6}
-		{C044AA74-C9FA-4754-AB86-0AFDB7032D13} = {61683AC9-2CA4-4E27-BA98-5D2497E21FF6}
 		{47361A16-ECC5-40C5-9A58-23D46DCD2A0B} = {8F5C4C9D-81A7-4BE4-88A3-019100D400EA}
+		{D5A1C483-8C49-48C1-8582-8DADA32BDF65} = {61683AC9-2CA4-4E27-BA98-5D2497E21FF6}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {CD08520D-0F71-435D-89D5-57CC30B1AB94}

+ 0 - 1
src/CallCenter.Api/Controllers/ListsController.cs

@@ -1,5 +1,4 @@
 using CallCenter.BlackLists;
-using CallCenter.CacheManager;
 using CallCenter.Share.Dtos;
 using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;

+ 3 - 3
src/CallCenter.Api/StartupExtensions.cs

@@ -14,7 +14,7 @@ using Microsoft.OpenApi.Models;
 using XF.Domain.Dependency;
 using CallCenter.Application;
 using CallCenter.Application.Contracts;
-using CallCenter.CacheManager;
+using CallCenter.Caching;
 using FluentValidation;
 using FluentValidation.AspNetCore;
 using CallCenter.Settings;
@@ -108,7 +108,7 @@ internal static class StartupExtensions
         services.AddSwaggerGen(c =>
         {
             //添加文档
-            c.SwaggerDoc("v1", new OpenApiInfo() { Title = "CallCenter Api", Version = "v1.0", Description = "呼叫中心api"});
+            c.SwaggerDoc("v1", new OpenApiInfo() { Title = "CallCenter Api", Version = "v1.0", Description = "呼叫中心api" });
             //使用反射获取xml文件,并构造出文件的路径
             var xmlFile = "document.xml";
             //var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
@@ -214,7 +214,7 @@ internal static class StartupExtensions
         //app.UseMiddleware<TempTokenMiddleware>();
 
         app.MapControllers();
-            //.RequireAuthorization();
+        //.RequireAuthorization();
 
         return app;
     }

+ 1 - 1
src/CallCenter.Application/CallCenter.Application.csproj

@@ -12,7 +12,7 @@
 
   <ItemGroup>
     <ProjectReference Include="..\CallCenter.Application.Contracts\CallCenter.Application.Contracts.csproj" />
-    <ProjectReference Include="..\CallCenter.CacheManager\CallCenter.CacheManager.csproj" />
+    <ProjectReference Include="..\CallCenter.Caching\CallCenter.Caching.csproj" />
     <ProjectReference Include="..\CallCenter.NewRock\CallCenter.NewRock.csproj" />
     <ProjectReference Include="..\CallCenter.Repository.SqlSugar\CallCenter.Repository.SqlSugar.csproj" />
     <ProjectReference Include="..\CallCenter\CallCenter.csproj" />

+ 2 - 2
src/CallCenter.Application/Handlers/ExtState/BusyNotificationHandler.cs

@@ -6,7 +6,7 @@ using XF.Domain.Cache;
 
 namespace CallCenter.Application.Handlers
 {
-    public class BusyNotificationHandler:INotificationHandler<BusyNotification>
+    public class BusyNotificationHandler : INotificationHandler<BusyNotification>
     {
         private readonly ITelRepository _telRepository;
         private readonly ITelCacheManager _telCacheManager;
@@ -24,7 +24,7 @@ namespace CallCenter.Application.Handlers
             var telModel = _telCacheManager.GetTel(notification.TelNo);
             telModel.TelStatus = ETelStatus.Active;
             //await _telRepository.UpdateAsync(telModel, cancellationToken);
-            _typedCache.Update(telModel.No,x=>telModel);
+            _typedCache.Set(telModel.No, telModel);
         }
     }
 }

+ 5 - 5
src/CallCenter.Application/Handlers/ExtState/IdleNotificationHandler.cs

@@ -7,16 +7,16 @@ using XF.Domain.Cache;
 
 namespace CallCenter.Application.Handlers
 {
-    public class IdleNotificationHandler:INotificationHandler<IdleNotification>
+    public class IdleNotificationHandler : INotificationHandler<IdleNotification>
     {
         private readonly ITelRepository _telRepository;
         private readonly ITelCacheManager _telCacheManager;
         private readonly ITypedCache<Tel> _typedCache;
         private readonly IUserCacheManager _userCacheManager;
         private readonly IRealtimeService _realtimeService;
-        public IdleNotificationHandler(ITelRepository telRepository, ITelCacheManager telCacheManager, ITypedCache<Tel> typedCache,IUserCacheManager userCacheManager,IRealtimeService realtimeService)
+        public IdleNotificationHandler(ITelRepository telRepository, ITelCacheManager telCacheManager, ITypedCache<Tel> typedCache, IUserCacheManager userCacheManager, IRealtimeService realtimeService)
         {
-            _telRepository=telRepository;
+            _telRepository = telRepository;
             _telCacheManager = telCacheManager;
             _typedCache = typedCache;
             _userCacheManager = userCacheManager;
@@ -28,10 +28,10 @@ namespace CallCenter.Application.Handlers
             var telModel = _telCacheManager.GetTel(notification.TelNo);
             telModel.TelStatus = ETelStatus.Ready;
             //await _telRepository.UpdateAsync(telModel, cancellationToken);
-            _typedCache.Update(notification.TelNo, x => telModel);
+            _typedCache.Set(notification.TelNo, telModel);
 
             var workModel = _userCacheManager.GetWorkByTel(notification.TelNo);
-            if (workModel!=null)
+            if (workModel != null)
             {
                 await _realtimeService.IdleAsync(workModel.UserId, cancellationToken);
             }

+ 1 - 1
src/CallCenter.Application/Handlers/ExtState/OfflineNotificationHandler.cs

@@ -24,7 +24,7 @@ namespace CallCenter.Application.Handlers
             var telModel = _telCacheManager.GetTel(notification.TelNo);
             telModel.TelStatus = ETelStatus.Offline;
             await _telRepository.UpdateAsync(telModel, cancellationToken);
-            _typedCache.Update(notification.TelNo, x => telModel);
+            _typedCache.Set(notification.TelNo, telModel);
         }
 
     }

+ 1 - 1
src/CallCenter.Application/Handlers/ExtState/OnlineNotificationHandler.cs

@@ -27,7 +27,7 @@ namespace CallCenter.Application.Handlers
             telModel.TelStatus = ETelStatus.Ready;
             telModel.RegisterIP = notification.RegisterIP;
             await _telRepository.UpdateAsync(telModel,cancellationToken);
-            _typedCache.Update(notification.TelNo, x => telModel);
+            _typedCache.Set(notification.TelNo, telModel);
         }
     }
 }

+ 21 - 0
src/CallCenter.Caching/CallCenter.Caching.csproj

@@ -0,0 +1,21 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+  
+      <ItemGroup>
+    <PackageReference Include="EasyCaching.Bus.Redis" Version="1.9.0" />
+    <PackageReference Include="EasyCaching.HybridCache" Version="1.9.0" />
+    <PackageReference Include="EasyCaching.InMemory" Version="1.9.0" />
+    <PackageReference Include="EasyCaching.Redis" Version="1.9.0" />
+    <PackageReference Include="EasyCaching.Serialization.SystemTextJson" Version="1.9.0" />
+  </ItemGroup>  
+
+  <ItemGroup>
+    <ProjectReference Include="..\CallCenter\CallCenter.csproj" />
+  </ItemGroup>
+
+</Project>

+ 204 - 0
src/CallCenter.Caching/DefaultTypedCache.cs

@@ -0,0 +1,204 @@
+using System.Collections;
+using EasyCaching.Core;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using XF.Domain.Cache;
+
+namespace CallCenter.Caching
+{
+    public class DefaultTypedCache<TValue> : ITypedCache<TValue>
+    {
+        private readonly IServiceScopeFactory _serviceScopeFactory;
+        private readonly IHybridCachingProvider _hybridCaching;
+        private readonly IRedisCachingProvider _redisCaching;
+        private readonly IEasyCachingProvider _caching;
+        private readonly TimeSpan _expirationDefault = TimeSpan.FromDays(1);
+
+        public DefaultTypedCache(
+            IServiceScopeFactory serviceScopeFactory,
+            IHybridCachingProvider hybridCaching,
+            IRedisCachingProvider redisCaching,
+            IEasyCachingProvider caching)
+        {
+            _serviceScopeFactory = serviceScopeFactory;
+            _hybridCaching = hybridCaching;
+            _redisCaching = redisCaching;
+            _caching = caching;
+        }
+
+        public void Set(string key, TValue value, TimeSpan? expiration = null) =>
+            _hybridCaching.Set(CombinePrefix(key), value, expiration.GetValueOrDefault(_expirationDefault));
+
+        public async Task SetAsync(string key, TValue value, TimeSpan? expiration = null, CancellationToken cancellationToken = default) =>
+            await _hybridCaching.SetAsync(CombinePrefix(key), value, expiration.GetValueOrDefault(_expirationDefault), cancellationToken);
+
+        public TValue? Get(string key) => _hybridCaching.Get<TValue>(CombinePrefix(key)).Value;
+
+        public async Task<TValue> GetAsync(string key, CancellationToken cancellationToken) =>
+            (await _hybridCaching.GetAsync<TValue>(CombinePrefix(key), cancellationToken)).Value;
+
+        public void Remove(string key) => _hybridCaching.Remove(CombinePrefix(key));
+
+        public async Task RemoveAsync(string key, CancellationToken cancellationToken) =>
+            await _hybridCaching.RemoveAsync(CombinePrefix(key), cancellationToken);
+
+        public bool Exists(string key) => _hybridCaching.Exists(CombinePrefix(key));
+
+        public async Task<bool> ExistsAsync(string key, CancellationToken cancellationToken) =>
+            await _hybridCaching.ExistsAsync(CombinePrefix(key), cancellationToken);
+
+        public bool TrySet(string key, TValue value, TimeSpan? expiration = null) =>
+            _hybridCaching.TrySet(CombinePrefix(key), value, expiration.GetValueOrDefault(_expirationDefault));
+
+        public async Task<bool> TrySetAsync(string key, TValue value, TimeSpan? expiration = null, CancellationToken cancellationToken = default) =>
+            await _hybridCaching.TrySetAsync(CombinePrefix(key), value, expiration.GetValueOrDefault(_expirationDefault), cancellationToken);
+
+        public void SetAll(IDictionary<string, TValue> values, TimeSpan? expiration = null)
+        {
+            var newDic = new Dictionary<string, TValue>();
+            foreach (var kvp in values)
+            {
+                newDic.Add(CombinePrefix(kvp.Key), kvp.Value);
+            }
+            _hybridCaching.SetAll(newDic, expiration.GetValueOrDefault(_expirationDefault));
+        }
+
+        public async Task SetAllAsync(IDictionary<string, TValue> values, TimeSpan? expiration = null, CancellationToken cancellationToken = default)
+        {
+            var newDic = new Dictionary<string, TValue>();
+            foreach (var kvp in values)
+            {
+                newDic.Add(CombinePrefix(kvp.Key), kvp.Value);
+            }
+
+            await _hybridCaching.SetAllAsync(newDic, expiration.GetValueOrDefault(_expirationDefault), cancellationToken);
+        }
+
+        public IDictionary<string, TValue> GetByPrefix()
+        {
+            var cacheValueDic = _caching.GetByPrefix<TValue>(CreateRegion());
+            if (cacheValueDic == null) return new Dictionary<string, TValue>();
+            return cacheValueDic.ToDictionary(cacheValue => cacheValue.Key, cacheValue => cacheValue.Value.Value);
+        }
+
+        public async Task<IDictionary<string, TValue>> GetByPrefixAsync(CancellationToken cancellationToken)
+        {
+            var cacheValueDic = await _caching.GetByPrefixAsync<TValue>(CreateRegion(), cancellationToken);
+            if (cacheValueDic == null) return new Dictionary<string, TValue>();
+            return cacheValueDic.ToDictionary(cacheValue => cacheValue.Key, cacheValue => cacheValue.Value.Value);
+        }
+
+        public IReadOnlyList<TValue> GetListByPrefix()
+        {
+            var cacheValueDic = _caching.GetByPrefix<TValue>(CreateRegion());
+            if (cacheValueDic == null) return new List<TValue>();
+            return cacheValueDic.Values.Select(d => d.Value).ToList();
+        }
+
+        public async Task<IReadOnlyList<TValue>> GetListByPrefixAsync(CancellationToken cancellationToken)
+        {
+            var cacheValueDic = await _caching.GetByPrefixAsync<TValue>(CreateRegion(), cancellationToken);
+            if (cacheValueDic == null) return new List<TValue>();
+            return cacheValueDic.Values.Select(d => d.Value).ToList();
+        }
+
+        /// <summary>
+        /// get the cache value, if cache not exists, set the value to cache then return
+        /// </summary>
+        public TValue GetOrSet(string key, TValue value, TimeSpan? expiration = null)
+        {
+            var cacheValue = Get(key);
+            if (cacheValue != null) return cacheValue;
+
+            Set(key, value, expiration);
+            return value;
+
+        }
+
+        public TValue? GetOrSet(string key, Func<string, TValue> valueFactory, TimeSpan? expiration = null)
+        {
+            var cacheValue = Get(key);
+            if (cacheValue != null) return cacheValue;
+
+            var value = valueFactory.Invoke(key);
+            if (value == null) return default;
+            Set(key, value, expiration);
+            return value;
+        }
+
+        public async Task<TValue> GetOrSetAsync(string key, TValue value, TimeSpan? expiration = null, CancellationToken cancellationToken = default)
+        {
+            var cacheValue = await GetAsync(key, cancellationToken);
+            if (cacheValue != null) return cacheValue;
+
+            await SetAsync(key, value, expiration, cancellationToken);
+            return value;
+        }
+
+        public async Task<TValue?> GetOrSetAsync(string key, Func<string, TValue> valueFactory, TimeSpan? expiration = null, CancellationToken cancellationToken = default)
+        {
+            var cacheValue = await GetAsync(key, cancellationToken);
+            if (cacheValue != null) return cacheValue;
+
+            var value = valueFactory.Invoke(key);
+            if (value == null) return default;
+            await SetAsync(key, value, expiration, cancellationToken);
+            return value;
+        }
+
+        public string CombinePrefix(string key) => CreateRegion() + key;
+
+
+        private string CreateRegion()
+        {
+            var valueType = typeof(TValue);
+            //if (valueType.IsGenericType)
+            //{
+            //    throw new NotSupportedException("TCachedValue can not be a Generic Type");
+            //}
+
+            //if (valueType == typeof(string))
+            //{
+            //    throw new NotSupportedException("TCachedValue can not be a string");
+            //}
+
+            if (string.IsNullOrWhiteSpace(valueType.FullName))
+            {
+                throw new NotSupportedException("FullName of type TCachedValue can not be null");
+            }
+
+            using var scope = _serviceScopeFactory.CreateScope();
+            var options = scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<CacheOptions>>();
+            var prefix = options.Value.Prefix;
+
+            //if (valueType.TryGetCustomAttribute<CacheAttribute>(false, out var attr))
+            //{
+            //    if (!string.IsNullOrEmpty(attr.Region))
+            //    {
+            //        return attr.Region;
+            //    }
+            //}
+
+            string region;
+
+            if (valueType.IsGenericType && valueType.GetInterfaces().Any(d => d == typeof(IEnumerable)))
+            {
+                region = "Collection";
+            }
+            else
+            {
+                region = valueType.FullName.Replace('.', ':');
+            }
+
+            if (!string.IsNullOrEmpty(prefix))
+            {
+                prefix += ':';
+                if (!region.StartsWith(prefix))
+                {
+                    region = prefix + region;
+                }
+            }
+            return region;
+        }
+    }
+}

+ 69 - 0
src/CallCenter.Caching/StartupExtensions.cs

@@ -0,0 +1,69 @@
+using EasyCaching.Core.Configurations;
+using EasyCaching.Serialization.SystemTextJson.Configurations;
+using Microsoft.Extensions.DependencyInjection;
+using XF.Domain.Cache;
+
+namespace CallCenter.Caching
+{
+    public static class StartupExtensions
+    {
+        public static IServiceCollection AddCache(this IServiceCollection services, Action<CacheOptions> action)
+        {
+            var options = new CacheOptions();
+            action(options);
+
+            services.AddEasyCaching(d =>
+            {
+                d.WithSystemTextJson("xjson");
+
+                // local
+                d.UseInMemory("m1");
+
+                d.UseRedis(config =>
+                {
+                    config.DBConfig.Endpoints.Add(new ServerEndPoint(options.ConnectionString, options.Port));
+                    config.DBConfig.Database = options.Database;
+                    config.SerializerName = "xjson";
+                }, "r1");
+
+                // combine local and distributed
+                d.UseHybrid(config =>
+                    {
+                        config.TopicName = "callcenter-topic";
+                        config.EnableLogging = false;
+
+                        // specify the local cache provider name after v0.5.4
+                        config.LocalCacheProviderName = "m1";
+                        // specify the distributed cache provider name after v0.5.4
+                        config.DistributedCacheProviderName = "r1";
+                    }, "h1")
+                    // use redis bus
+                    .WithRedisBus(busConf =>
+                    {
+                        busConf.Endpoints.Add(new ServerEndPoint(options.ConnectionString, options.Port));
+
+                        // do not forget to set the SerializerName for the bus here !!
+                        busConf.SerializerName = "xjson";
+                    });
+            })
+                    .Configure(action)
+                    .AddSingleton(typeof(ITypedCache<>), typeof(DefaultTypedCache<>))
+                ;
+
+            return services;
+        }
+    }
+
+    public class CacheOptions
+    {
+        public string ConnectionString { get; set; }
+
+        public int Port { get; set; }
+
+        public int Database { get; set; }
+
+        public string Prefix { get; set; }
+
+        public int MaxRdSecond { get; set; }
+    }
+}

+ 1 - 1
src/CallCenter/BlackLists/IBlacklistDomainService.cs

@@ -46,7 +46,7 @@ namespace CallCenter.BlackLists
         public async Task AddAsync(Blacklist blacklist, CancellationToken cancellationToken = default)
         {
             blacklist.Id = await _blacklistRepository.AddAsync(blacklist, cancellationToken);
-            _blackCache.GetOrAdd(Blacklist.GetKey(blacklist.PhoneNo), blacklist, ExpireMode.Absolute, TimeSpan.FromSeconds(blacklist.Duration));
+            _blackCache.GetOrSet(Blacklist.GetKey(blacklist.PhoneNo), blacklist, TimeSpan.FromSeconds(blacklist.Duration));
         }
 
         /// <summary>

+ 3 - 3
src/CallCenter/Caches/CallCacheManager.cs

@@ -22,12 +22,12 @@ namespace CallCenter.Caches
                 list = new List<Call>();
             }
             list.Add(call);
-            _cacheCall.AddOrUpdate(CallKey, list);
+            _cacheCall.Set(CallKey, list);
         }
 
         public List<Call>? GetCallQueueList()
         {
-            var list = _cacheCall.GetOrAdd(CallKey, k =>
+            var list = _cacheCall.GetOrSet(CallKey, k =>
             {
                 return new List<Call>();
             });
@@ -43,7 +43,7 @@ namespace CallCenter.Caches
                 if (model != null)
                 {
                     list.Remove(model);
-                    _cacheCall.AddOrUpdate(CallKey, list);
+                    _cacheCall.Set(CallKey, list);
                 }
             }
         }

+ 1 - 1
src/CallCenter/Caches/IvrCacheManager.cs

@@ -17,6 +17,6 @@ public class IvrCacheManager : IIvrCacheManager, IScopeDependency
 
     public IReadOnlyList<Ivr> GetIvrs()
     {
-        return _ivrCache.GetOrAdd(Ivr.Key, x => _ivrRepository.QueryAsync().GetAwaiter().GetResult());
+        return _ivrCache.GetOrSet(Ivr.Key, x => _ivrRepository.QueryAsync().GetAwaiter().GetResult()) ?? new List<Ivr>();
     }
 }

+ 1 - 1
src/CallCenter/Caches/SystemSettingCacheManager.cs

@@ -24,7 +24,7 @@ namespace CallCenter.Caches
 
         public SystemSetting GetSetting(string code)
         {
-            var setting = _cacheSystemSetting.GetOrAdd(code, x =>
+            var setting = _cacheSystemSetting.GetOrSet(code, x =>
             {
                 var dbsetting = _systemSettingRepository.GetAsync(d => d.Code == code).GetAwaiter().GetResult();
                 if (dbsetting==null)

+ 3 - 3
src/CallCenter/Caches/TelCacheManager.cs

@@ -30,7 +30,7 @@ public class TelCacheManager : ITelCacheManager, IScopeDependency
 
     public Tel GetTel(string telNo)
     {
-        var tel = _cacheTel.GetOrAdd(telNo, k =>
+        var tel = _cacheTel.GetOrSet(telNo, k =>
         {
             var dbTel = _telRepository.GetExtAsync(d => d.No == telNo, d => d.Includes(x => x.Groups))
                 .GetAwaiter().GetResult();
@@ -43,7 +43,7 @@ public class TelCacheManager : ITelCacheManager, IScopeDependency
 
     public TelGroup GetTelGroup(string groupNo)
     {
-        var group = _cacheTelGroup.GetOrAdd(groupNo, k =>
+        var group = _cacheTelGroup.GetOrSet(groupNo, k =>
         {
             var telGroup = _telGroupRepository.GetExtAsync(d => d.No == groupNo, d => d.Includes(x => x.Tels))
                 .GetAwaiter().GetResult();
@@ -56,6 +56,6 @@ public class TelCacheManager : ITelCacheManager, IScopeDependency
 
     public IReadOnlyList<Tel> GetTels()
     {
-        return _cacheTelList.GetOrAdd("tellist", d => _telRepository.QueryAsync(x=>!x.IsDeleted).GetAwaiter().GetResult());
+        return _cacheTelList.GetOrSet("tellist", d => _telRepository.QueryAsync(x => !x.IsDeleted).GetAwaiter().GetResult()) ?? new List<Tel>();
     }
 }

+ 10 - 10
src/CallCenter/Caches/UserCacheManager.cs

@@ -29,7 +29,7 @@ public class UserCacheManager : IUserCacheManager, IScopeDependency
     /// <returns></returns>
     public Work GetWorkByUser(string userId)
     {
-        var work = _cacheWork.GetOrAdd(Work.GetKey(KeyMode.UserId, userId), k =>
+        var work = _cacheWork.GetOrSet(Work.GetKey(KeyMode.UserId, userId), k =>
         {
             var dbWork = _workRepository.GetCurrentWorkByUserAsync(userId)
                 .GetAwaiter().GetResult();
@@ -48,7 +48,7 @@ public class UserCacheManager : IUserCacheManager, IScopeDependency
     /// <exception cref="UserFriendlyException"></exception>
     public Work GetWorkByTel(string telNo)
     {
-        var work = _cacheWork.GetOrAdd(Work.GetKey(KeyMode.TelNo, telNo), k =>
+        var work = _cacheWork.GetOrSet(Work.GetKey(KeyMode.TelNo, telNo), k =>
         {
             var dbWork = _workRepository.GetCurrentWorkByTelAsync(telNo)
                 .GetAwaiter().GetResult();
@@ -65,7 +65,7 @@ public class UserCacheManager : IUserCacheManager, IScopeDependency
     /// <returns></returns>
     public List<Work>? GetWorks()
     {
-        var works = _cacheWorks.GetOrAdd(WorkKey, k =>
+        var works = _cacheWorks.GetOrSet(WorkKey, k =>
         {
             var works = _workRepository.QueryAsync(x => x.EndTime == null).GetAwaiter().GetResult();
             return works;
@@ -81,7 +81,7 @@ public class UserCacheManager : IUserCacheManager, IScopeDependency
             list = new List<Work>();
         }
         list.Add(work);
-        _cacheWorks.AddOrUpdate(WorkKey, list);
+        _cacheWorks.Set(WorkKey, list);
     }
 
     public void UpdateWorksCache(Work work)
@@ -93,7 +93,7 @@ public class UserCacheManager : IUserCacheManager, IScopeDependency
             list.Remove(model);
         }
         list.Add(work);
-        _cacheWorks.AddOrUpdate(WorkKey, list);
+        _cacheWorks.Set(WorkKey, list);
     }
 
 
@@ -106,7 +106,7 @@ public class UserCacheManager : IUserCacheManager, IScopeDependency
             if (model!=null)
             {
                 list.Remove(model);
-                _cacheWorks.AddOrUpdate(WorkKey, list);
+                _cacheWorks.Set(WorkKey, list);
             }
         }
     }
@@ -127,7 +127,7 @@ public class UserCacheManager : IUserCacheManager, IScopeDependency
             var dbWork = await _workRepository.GetCurrentWorkByTelAsync(telNo, cancellationToken);
             if (dbWork != null)
             {
-                _cacheWork.Add(Work.GetKey(KeyMode.TelNo, telNo), dbWork);
+                _cacheWork.Set(Work.GetKey(KeyMode.TelNo, telNo), dbWork);
                 return true;
             }
             return false;
@@ -151,7 +151,7 @@ public class UserCacheManager : IUserCacheManager, IScopeDependency
         {
             var dbWork = await _workRepository.GetCurrentWorkByUserAsync(userId, cancellationToken);
             if (dbWork is null) return false;
-            _cacheWork.Add(Work.GetKey(KeyMode.UserId, userId), dbWork);
+            _cacheWork.Set(Work.GetKey(KeyMode.UserId, userId), dbWork);
         }
 
         return true;
@@ -164,8 +164,8 @@ public class UserCacheManager : IUserCacheManager, IScopeDependency
     /// <returns></returns>
     public void UpdateWorkByUser(Work work)
     {
-        _cacheWork.Update(Work.GetKey(KeyMode.UserId, work.UserId), d => work);
-        _cacheWork.Update(Work.GetKey(KeyMode.TelNo, work.TelNo), d => work);
+        _cacheWork.Set(Work.GetKey(KeyMode.UserId, work.UserId), work);
+        _cacheWork.Set(Work.GetKey(KeyMode.TelNo, work.TelNo), work);
     }
 
     

+ 7 - 7
src/CallCenter/Ivrs/IvrDomainService.cs

@@ -295,23 +295,23 @@ public class IvrDomainService : IIvrDomainService, IScopeDependency
 
     private Ivr GetCorrectIvr()
     {
-        var worktimeSettings = _worktimeCache.GetOrAdd("worktimesettings", d => _worktimeOptions.Value, ExpireMode.Absolute, TimeSpan.FromDays(1));
+        var worktimeSettings = _worktimeCache.GetOrSet("worktimesettings", d => _worktimeOptions.Value, TimeSpan.FromDays(1));
         var categoryId = GetCorrectCategory(worktimeSettings);
         var ivrList = _ivrCacheManager.GetIvrs();
         var ivr = ivrList.First(x => x.IvrCategoryId == categoryId && x.IsRoot);
         return ivr;
     }
 
-    public CorrectIvr GetCorrectIvr(string to,bool isEvaluate = false)
+    public CorrectIvr GetCorrectIvr(string to, bool isEvaluate = false)
     {
-        var worktimeSettings = _worktimeCache.GetOrAdd("worktimesettings", d => _worktimeOptions.Value, ExpireMode.Absolute, TimeSpan.FromDays(1));
-        var correct = GetCorrectCategory(worktimeSettings.LineSetting.First(x => x.NumNo == to),isEvaluate);
+        var worktimeSettings = _worktimeCache.GetOrSet("worktimesettings", d => _worktimeOptions.Value, TimeSpan.FromDays(1));
+        var correct = GetCorrectCategory(worktimeSettings.LineSetting.First(x => x.NumNo == to), isEvaluate);
         return correct;
     }
 
 
 
-    private CorrectIvr GetCorrectCategory(LineSetting settings,bool isEvaluate)
+    private CorrectIvr GetCorrectCategory(LineSetting settings, bool isEvaluate)
     {
         if (isEvaluate)
         {
@@ -319,7 +319,7 @@ public class IvrDomainService : IIvrDomainService, IScopeDependency
         }
 
         if (!settings.WorkDay.Contains((int)DateTime.Now.DayOfWeek))
-            return new CorrectIvr() { eCorrectIvr = ECorrectIvr.Group, ReturnValue = settings.RestToGroup }; 
+            return new CorrectIvr() { eCorrectIvr = ECorrectIvr.Group, ReturnValue = settings.RestToGroup };
         var time = TimeOnly.FromDateTime(DateTime.Now);
         if ((time >= TimeOnly.Parse(settings.MorningBegin) && time <= TimeOnly.Parse(settings.MorningEnd))
             || (time >= TimeOnly.Parse(settings.AfterBegin) && time <= TimeOnly.Parse(settings.AfterEnd)))
@@ -353,7 +353,7 @@ public class IvrDomainService : IIvrDomainService, IScopeDependency
         public ECorrectIvr eCorrectIvr { get; set; }
     }
 
-    
+
 
     private string GetCorrectCategory(WorkTimeSettings settings)
     {

+ 45 - 21
src/XF.Domain/Cache/ITypedCache.cs

@@ -6,42 +6,66 @@ using System.Threading.Tasks;
 
 namespace XF.Domain.Cache
 {
-    public interface ITypedCache<TValue> where TValue : class
+    public interface ITypedCache<TValue> //where TValue : class
     {
-        bool Add(string key, TValue value, ExpireMode? expireMode = ExpireMode.None, TimeSpan? timeout = null);
-
-        void Put(string key, TValue value, ExpireMode? expireMode = ExpireMode.None, TimeSpan? timeout = null);
-
-        TValue Update(string key, Func<TValue, TValue> updateValue);
+        /*
+TrySet/TrySetAsync
+Set/SetAsync
+SetAll/SetAllAsync
+Get/GetAsync(with data retriever)
+Get/GetAsync(without data retriever)
+GetByPrefix/GetByPrefixAsync
+GetAll/GetAllAsync
+Remove/RemoveAsync
+RemoveByPrefix/RemoveByPrefixAsync
+RemoveAll/RemoveAllAsync
+Flush/FlushAsync
+GetCount
+GetExpiration/GetExpirationAsync
+         */
+
+        void Set(string key, TValue value, TimeSpan? expiration = null);
+        Task SetAsync(string key, TValue value, TimeSpan? expiration = null, CancellationToken cancellationToken = default);
 
         TValue? Get(string key);
+        Task<TValue?> GetAsync(string key, CancellationToken cancellationToken);
 
-        void Expire(string key, DateTime absoluteExpiration);
+        void Remove(string key);
+        Task RemoveAsync(string key, CancellationToken cancellationToken);
 
-        void Expire(string key, TimeSpan slidingExpiration);
-
-        void Expire(string key, ExpireMode? expireMode = ExpireMode.None, TimeSpan? timeout = null);
+        bool Exists(string key);
+        Task<bool> ExistsAsync(string key, CancellationToken cancellationToken);
 
-        TValue AddOrUpdate(string key, TValue addValue, Func<TValue, TValue> updateValue, ExpireMode? expireMode = ExpireMode.None, TimeSpan? timeout = null);
+        bool TrySet(string key, TValue value, TimeSpan? expiration = null);
+        Task<bool> TrySetAsync(string key, TValue value, TimeSpan? expiration = null, CancellationToken cancellationToken = default);
 
-        TValue AddOrUpdate(string key, TValue addValue, ExpireMode? expireMode = ExpireMode.None, TimeSpan? timeout = null)
-            => AddOrUpdate(key, addValue, _ => addValue, expireMode, timeout);
+        void SetAll(IDictionary<string, TValue> values, TimeSpan? expiration = null);
+        Task SetAllAsync(IDictionary<string, TValue> values, TimeSpan? expiration = null, CancellationToken cancellationToken = default);
 
-        TValue GetOrAdd(string key, TValue value, ExpireMode? expireMode = ExpireMode.None, TimeSpan? timeout = null);
+        IDictionary<string, TValue> GetByPrefix();
+        Task<IDictionary<string, TValue>> GetByPrefixAsync(CancellationToken cancellationToken);
 
-        TValue GetOrAdd(string key, Func<string, TValue> valueFactory, ExpireMode? expireMode = ExpireMode.None, TimeSpan? timeout = null);
+        IReadOnlyList<TValue> GetListByPrefix();
+        Task<IReadOnlyList<TValue>> GetListByPrefixAsync(CancellationToken cancellationToken);
 
-        bool TryGetOrAdd(string key, Func<string, TValue> valueFactory, out TValue? value, ExpireMode? expireMode = ExpireMode.None, TimeSpan? timeout = null);
+        //void RemoveByPrefix(string prefix);
+        //Task RemoveByPrefixAsync(string prefix, CancellationToken cancellationToken);
 
-        bool TryUpdate(string key, Func<TValue, TValue> updateValue, out TValue? value);
+        /// <summary>
+        /// get the cache value, if cache not exists, set the value to cache then return
+        /// </summary>
+        TValue GetOrSet(string key, TValue value, TimeSpan? expiration = null);
+        TValue? GetOrSet(string key, Func<string, TValue> valueFactory, TimeSpan? expiration = null);
+        Task<TValue> GetOrSetAsync(string key, TValue value, TimeSpan? expiration = null, CancellationToken cancellationToken = default);
+        Task<TValue?> GetOrSetAsync(string key, Func<string, TValue> valueFactory, TimeSpan? expiration = null, CancellationToken cancellationToken = default);
 
-        bool Remove(string key);
+        //TValue GetOrAdd(string key, TValue value, ExpireMode? expireMode = ExpireMode.None, TimeSpan? timeout = null);
 
-        bool Exists(string key);
+        //TValue GetOrAdd(string key, Func<string, TValue> valueFactory, ExpireMode? expireMode = ExpireMode.None, TimeSpan? timeout = null);
 
-        string CreateRegion();
+        string CombinePrefix(string key);
     }
-    
+
     public enum ExpireMode
     {
         /// <summary>Defines no expiration.</summary>