首页 新闻 会员 周边 捐助

MVC自定义缓存,高并发时缓存内容错乱

0
悬赏园豆:200 [已解决问题] 解决于 2015-05-12 15:06

一个个页面打开的时候正常,访问量大的时候缓存就错乱了,找不到解决的方法,参照MVC里的OutputCache源代码写的

 

using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.Mvc;
using System.Reflection;
using Newtonsoft.Json;
using System.Text;
using System.Configuration;
using Benz.Core.Injection;
using Autofac;
using System.Web.UI;
using Benz.Core.Cache;
using Benz.Core.Helper;
using Benz.Core.Log;
using System.Globalization;

namespace Benz.Core.OutputCache
{
    public class ResultCachingAttribute : ActionFilterAttribute, IExceptionFilter
    {
        private readonly static string siteUrl = System.Web.Configuration.WebConfigurationManager.AppSettings["HostMechine"].ToString();
        private readonly static long cacheMaxTime = long.Parse(System.Web.Configuration.WebConfigurationManager.AppSettings["cacheTime"].ToString());

        private ICacheManager cacheMgr = ContainerManager.Engine.Container.Resolve<ICacheManager>();
        private MemoryCacheManager localCache = new MemoryCacheManager();
        private MessageHelper<string> message = new MessageHelper<string>();
        private static string UA = "CacheRefreshService";

        private static object _actionFilterFinishCallbackKey = new object();
        private ILoggerService log = new LoggerService();

        public int Duration { get; set; }

        public ResultCachingAttribute()
        {
        }

        private string CacheKey;
        private string userArgent;

        /// <summary>
        /// 在执行操作方法之前调用。
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            this.CacheKey = CreateKey(filterContext);
            this.userArgent = filterContext.RequestContext.HttpContext.Request.UserAgent.Trim().ToLower();
            bool needRun = false;

            if (!userArgent.Equals(UA.Trim(), StringComparison.OrdinalIgnoreCase))
            {
                if (localCache.HasKey(this.CacheKey))
                {
                    string html = localCache.Get<string>(this.CacheKey);
                    if (html.Length < 50)
                        return;
                    filterContext.Result = new ContentResult { Content = html };
                }
                else
                {
                    if (cacheMgr.HasKey(this.CacheKey))
                    {
                        string html = cacheMgr.Get<string>(this.CacheKey);
                        if (html.Length < 50)
                            return;
                        message.SendMessage(filterContext.HttpContext.Request.Url.ToString());
                        filterContext.Result = new ContentResult { Content = html };
                    }
                    else
                        needRun = true;
                }
            }
            else
                needRun = true;

            if (needRun)
            {
                StringWriter cachingWriter = new StringWriter(CultureInfo.InvariantCulture);
                TextWriter originalWriter = filterContext.HttpContext.Response.Output;
                filterContext.HttpContext.Response.Output = cachingWriter;

                SetActionFilterFinishCallback(filterContext, wasException =>
                {
                    filterContext.HttpContext.Response.Output = originalWriter;

                    string capturedText = cachingWriter.ToString();
                    filterContext.HttpContext.Response.Write(capturedText);

                    //if (!wasException)
                    //{
                        cacheMgr.Set(this.CacheKey, capturedText, cacheMaxTime);
                        localCache.Set(this.CacheKey, capturedText, Duration);
                    //}
                });
            }
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            CompleteAction(filterContext, wasException: filterContext.Exception != null);
        }

        private static void SetActionFilterFinishCallback(ControllerContext controllerContext, Action<bool> callback)
        {
            controllerContext.HttpContext.Items[_actionFilterFinishCallbackKey] = callback;
        }

        private static Action<bool> GetActionFilterFinishCallback(ControllerContext controllerContext)
        {
            return controllerContext.HttpContext.Items[_actionFilterFinishCallbackKey] as Action<bool>;
        }

        private static void ClearActionFilterFinishCallback(ControllerContext controllerContext)
        {
            controllerContext.HttpContext.Items.Remove(_actionFilterFinishCallbackKey);
        }

        private static void CompleteAction(ControllerContext filterContext, bool wasException)
        {
            Action<bool> callback = GetActionFilterFinishCallback(filterContext);

            if (callback != null)
            {
                ClearActionFilterFinishCallback(filterContext);
                callback(wasException);
            }
        }


        /// <summary>
        /// 创建缓存Key
        /// </summary>
        /// <param name="filterContext"></param>
        /// <returns></returns>
        private static string CreateKey(ControllerContext filterContext)
        {
            HttpRequestBase bases = (HttpRequestBase)filterContext.HttpContext.Request;
            string port = ":"+bases.Url.Port.ToString();
            return bases.Url.ToString()
                .ToLower()
                .Replace("://", "__")
                .Replace(siteUrl, "host")
                .Replace(port, "")
                .Replace("/", "_")
                .Replace(".", "_");
        }

        public void OnException(ExceptionContext filterContext)
        {
            if (filterContext == null)
                throw new ArgumentNullException("filterContext");

            CompleteAction(filterContext, wasException: true);
        }
    }
}
问题补充:

之前格式看不清楚,关闭了

凬月的主页 凬月 | 初学一级 | 园豆:21
提问于:2015-05-12 14:00
< >
分享
最佳答案
0

缓存错乱时, string html = cacheMgr.Get<string>(this.CacheKey); 读出来的值是正常的码?

收获园豆:200
dudu | 高人七级 |园豆:30757 | 2015-05-12 14:24

localCache和cacheMgr里读出来的值都不相同

凬月 | 园豆:21 (初学一级) | 2015-05-12 14:40

localCache和cacheMgr里缓存的内容都是错误的

凬月 | 园豆:21 (初学一级) | 2015-05-12 14:42

@凬月: 试试把CacheKey定义为局部变量

dudu | 园豆:30757 (高人七级) | 2015-05-12 14:48

@dudu: 晕~~~~~正确了。。。居然是这里的问题

凬月 | 园豆:21 (初学一级) | 2015-05-12 15:03

 我再验证一下,没问题就结贴:)

凬月 | 园豆:21 (初学一级) | 2015-05-12 15:03
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册