【问题标题】:Managing Httpcache from C# using JSON configuration使用 JSON 配置从 C# 管理 Httpcache
【发布时间】:2016-09-26 16:27:33
【问题描述】:

我已经编写了一种有效的方法来控制数据在 HttpCache 中缓存/不缓存,使用 JSON 和 C# 控制它。

这样做的原因是利用现有的应用服务器来存储缓存,以节省网络延迟和跨进程调用。另一个原因是在我们发现内存或性能问题后尽量减少代码更改(因为您可以控制来自 JSON 的数据)。

该实现使用 C# 代码与 HttpCache 交互,并使用 JSON 对象以类似于我们在 Web 应用程序项目中看到的表单身份验证的方式查找要缓存的内容。

JSON 格式如下:

{
  Key: "Cache",
  Allow: "*",
  Deny: "",
  Keys: [
    {
      Key: "CacheKey",
      Allow: "*",
      Deny: "",
      Keys: [
        {
          Key: "Organization",
          Allow: "*",
          Deny: "",
          Keys: [
            {
              Key: "Department",
              Allow: "*",
            }
          ]
        }
      ]
    },
    {
      Key: "SomeOtherCacheKey",
      Allow: "*",
      Deny: ""
    }
  ]
}

【问题讨论】:

    标签: c# json http caching


    【解决方案1】:

    我以组织和部门搜索的Employee 类为例。

    虽然该解决方案不是完全动态的,但它与存储库密切合作。

    为了实现它,我创建了一个通用的CacheBase 类。该类必须派生自一个门面,该门面将被调用以获取数据,门面将调用GetFromCache 方法从缓存中获取数据。如果 JSON 不允许管理给定 cacheKey 以及参数(组键和值)的缓存,Facade 将直接调用存储库。我假设所需的参数将被注入到构造函数中。

    欢迎编辑和代码审查。

    public class EmployeeFacade: CacheBase<IEnumerable<Employee>>
    {
        private readonly IEmployeeRepository _repository;
        public EmployeeFacade(IEmployeeRepository employeeRepository) : base("3600","Employee_Cache",cacheConfigurationJSON)
        {
            _repository = employeeRepository;
        }
    
      public method GetEmployee(string organization, string department)
      {
            var groupKeyAndValues = new List<Tuple<string, string>>();
            groupKeyAndValues.Add(new Tuple<String, string>("Organization", organization));
            groupKeyAndValues.Add(new Tuple<String, string>("Department", department));
            bool isCacheAllowed;
    
            var employeeInfos = base.GetFromCache(() => _repository.GetEmployee(organization, department), groupKeyAndValues, out isCacheAllowed);
    
            //if cache is not allowed for this combination , return direct from repository.
            if (!isCacheAllowed)
                return _repository.GetEmployee(organization, department);
      }
    }
    
    public abstract class CacheBase<T> where T : class
    {
        private string _cacheTimeoutInSeconds;
        private string _cacheConfiguration;
        private static readonly object CacheLockObject = new object();
        string _cacheKey;
        public CacheBase(string cacheTimeoutInSeconds, string cacheKey, string cacheConfigurationJson)
        {
            _cacheTimeoutInSeconds= cacheTimeoutInSeconds;
            _cacheConfiguration = cacheConfigurationJson;
            _cacheKey = cacheKey;
        }
    
        public T GetFromCache(Func<T> methodToFillCache, IEnumerable<Tuple<string, string>> groupKeyAndValues, out bool isCacheAllowed)
        {
            var baseCacheKey = _cacheKey;
            var detailedCacheKey = GenerateCacheKey(groupKeyAndValues);
            isCacheAllowed = IsSaveToCacheAllowed(baseCacheKey, groupKeyAndValues);
    
            if (!isCacheAllowed) return null;
    
            var result = HttpRuntime.Cache[detailedCacheKey] as T;
    
            if (result == null)
            {
                lock (CacheLockObject)
                {
                    if (result == null)
                    {
                        result = methodToFillCache() as T;
                        SetToCache(result, detailedCacheKey);
                    }
                }
            }
            return result;
        }
    
        private void SetToCache(T data, string detailedCacheKey)
        {
    
            HttpRuntime.Cache.Insert(detailedCacheKey, data, null,
                DateTime.Now.AddSeconds(Convert.ToInt32(cacheTimeoutInSeconds)), TimeSpan.Zero);
        }
    
        private string GenerateCacheKey(IEnumerable<Tuple<string, string>> groupKeyAndValues)
        {
            string detailedCacheKey = _cacheKey;
            if (groupKeyAndValues == null) return detailedCacheKey;
            var groupKeys = groupKeyAndValues.Select(x => x.Item1).ToList();
            if (groupKeys != null && groupKeys.Count > 0)
            {
                foreach (var groupKey in groupKeys)
                {
                    if (!String.IsNullOrWhiteSpace(groupKey))
                        detailedCacheKey += "_" + groupKey;
                }
            }
            return detailedCacheKey;
        }
    
        private bool IsSaveToCacheAllowed(string cacheKey, IEnumerable<Tuple<string, string>> groupKeyAndValues)
        {
            cacheKey = cacheKey.ToUpper();
    
            if (_cacheConfiguration == null) return false;
    
            string valuesAllowed = CacheConstant.All; string valuesDenied = CacheConstant.All;
    
            //CACHE                                                                 
            if (_cacheConfiguration == null) return true;
            valuesAllowed = _cacheConfiguration.Allow;
            valuesDenied = _cacheConfiguration.Deny;
    
            var matchingCacheConfig = _cacheConfiguration.Keys.FirstOrDefault(x => x.Key.ToUpper() == cacheKey);
            if (matchingCacheConfig == null) return IsAllowed(cacheKey, valuesAllowed, valuesDenied); ;
            valuesAllowed = matchingCacheConfig.Allow;
            valuesDenied = matchingCacheConfig.Deny;
    
            bool isAllowed = IsAllowed(cacheKey, valuesAllowed, valuesDenied);                                                                               
            foreach (var groupKeyAndValue in groupKeyAndValues)
            {
                var key = groupKeyAndValue.Item1.ToUpper();
                var value = groupKeyAndValue.Item2.ToUpper();
                matchingCacheConfig = matchingCacheConfig.Keys.FirstOrDefault(x => x.Key.ToUpper() == key);
    
                if (matchingCacheConfig == null) return IsAllowed(key, valuesAllowed, valuesDenied);
                valuesAllowed = matchingCacheConfig.Allow;
                valuesDenied = matchingCacheConfig.Deny;
    
                isAllowed = IsAllowed(value, matchingCacheConfig.Allow, matchingCacheConfig.Deny);
    
                if (!isAllowed) break;
            }
            return isAllowed;
        }
    
        bool IsAllowed(string value, string allowedValues, string deniedValues)
        {
            //Prerequisites: among allowed and denied values , one should contain * and other should contain value or empty string 
            var allowed = allowedValues.ToUpper().Split(',');
            var denied = deniedValues.ToUpper().Split(',');
            if (denied.Contains(CacheConstant.All))
            {
                if (allowed.Contains(value) || allowed.Contains(CacheConstant.All))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else if (denied.Contains(value))
            {
                if (allowed.Contains(value))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else //denied contains nothing
            {
                if (allowed.Contains(value) || allowed.Contains(CacheConstant.All) || allowed.Count() == 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-04-21
      • 1970-01-01
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-27
      • 2012-01-02
      • 1970-01-01
      相关资源
      最近更新 更多