zoukankan      html  css  js  c++  java
  • MVC中配置OutputCache的VaryByParam参数无效的问题

    在项目使用OutputCacheAttribute是遇到了问题,当我想在配置文件web.config中配置OutputCache的VaryByParam时竟然不起作用,下面是相关代码:
    文件FaceController.cs

        [OutputCache(CacheProfile = "faceProfile")] 
        public ActionResult Index() 
        { 
            return View(); 
        } 
    

    文件index.cshtml

    <h2>@DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")</h2> 
    

    web.config的cache配置

      <system.web> 
        <caching> 
          <outputCacheSettings> 
            <outputCacheProfiles> 
              <add  name="faceProfile" duration ="180"  varyByParam="none" enabled="true"/> 
            </outputCacheProfiles> 
          </outputCacheSettings> 
        </caching> 
    <system.web> 
    

    下面是我的测试:
    请求 /face/index 页面,输出: 2014-08-02 18:40:56.184
    再次请求 /face/index 页面,输出: 2014-08-02 18:40:56.184 (不变)
    因为我指定了varyByParam="none",所以我添加参数或改变参数,输出的时间应该不变才对,可是:
    请求 /face/index/?p=19999 页面,输出: 2014-08-02 18:42:29.720 (变了)
    请求 /face/index/?p=10000 页面,输出: 2014-08-02 18:43:30.981 (变了)
    请求 /face/index/?abcd 页面,输出: 2014-08-02 18:44:00.440 (变了)
    请求结果随着参数的变化而变化,所以它应该是为每个参数都缓存了一个版本相当于设置了varyByParam="*"
    从测试结果可以看出配置文件中设置的duration ="180"有起到作用,而varyByParam="none"没有起到作用.
    然后我试着把varyByParam="none"直接写到代码里:

        [OutputCache( Duration=180,VaryByParam="none")] 
        public ActionResult Index() 
        { 
            return View(); 
        } 
    

    这次结果它正确进行缓存页面,没有为每个参数缓存一个版本,这使我很困惑,然后我看了一下OutputCacheAttribute的源码,这里我贴出的是部分关键源码:

    public class OutputCacheAttribute : ActionFilterAttribute, IExceptionFilter 
        {
    
            private OutputCacheParameters _cacheSettings = new OutputCacheParameters { VaryByParam = "*" }; 
            //_cacheSettings中的每个属性都以  CacheProfile 属性的方式再包装了一遍 
            //其余类似的属性我就不贴出来了 
            public string CacheProfile 
            { 
                get{return _cacheSettings.CacheProfile ?? String.Empty; } 
                set{_cacheSettings.CacheProfile = value;} 
            } 
            //省去了无关代码 
            public override void OnResultExecuting(ResultExecutingContext filterContext) 
            { 
                    //省去了无关代码 
                    
                    using (OutputCachedPage page = new OutputCachedPage(_cacheSettings)) 
                    { 
                        page.ProcessRequest(HttpContext.Current); 
                    } 
            } 
            private sealed class OutputCachedPage : Page 
            { 
                private OutputCacheParameters _cacheSettings; 
                public OutputCachedPage(OutputCacheParameters cacheSettings) 
                { 
                    // Tracing requires Page IDs to be unique. 
                    ID = Guid.NewGuid().ToString(); 
                    _cacheSettings = cacheSettings; 
                } 
                protected override void FrameworkInitialize() 
                { 
                    // when you put the <%@ OutputCache %> directive on a page, the generated code calls InitOutputCache() from here 
                    base.FrameworkInitialize(); 
                    InitOutputCache(_cacheSettings); 
                } 
            } 
            } 
    

    由上面的代码可以看出_cacheSettings根本就没从配置文件里读取,而是直接由 OutputCache( Duration=180,VaryByParam="none") 这样设置进去的,然后直接传人Page.InitOutputCache(cacheSettings)中,可见它直接使用asp.net以前的方式OutputCacheModule来实现缓存的,InitOutputCache中应该有去加载配置里面的设置, 然后看看cacheSettings的相应字段是否已经有合适的值了,如果没有则使用配置里边的值。而我们在使用OutputCache时,如果没有传人VaryByParam值,则它默认的值就为"*"(从cacheSettings初始化时看出来的) 。故代码:

        [OutputCache(CacheProfile = "faceProfile")] 
        public ActionResult Index() 
        { 
            return View(); 
        } 
    

    相当于

        [OutputCache(CacheProfile = "faceProfile",VaryByParam = "*")] 
        public ActionResult Index() 
        { 
            return View(); 
        } 
    

    配置里的VaryByParam的值是不会覆盖代码里面的VaryByParam的值的,所以才会出现我们测试时,对每个参数都进行缓存的情况。

    解决办法:

    1. 把VaryByParam 就直接写入代码, 其他的参数在配置中来完成如:OutputCache(CacheProfile = "faceProfile", VaryByParam = "none")
    2. 自己实现一个OutputCacheAttritube
      下面就是我把OutputCacheAttritube源码做一些修改后满足自己需求的MySimpleCacheAttribute,不过它不适用于ChildAction,但我可以在配置文件中控制VaryByParam参数,改造后的代码如下:
    namespace Mvc.Cache 
    { 
        using System.Web.Mvc; 
        using System.Web.UI; 
        using System; 
        using System.Web; 
        public class MySimpleCacheAttribute : ActionFilterAttribute 
        { 
            private OutputCacheParameters _cacheSettings = new OutputCacheParameters(); 
            public MySimpleCacheAttribute() 
            { 
            } 
            public string CacheProfile 
            { 
                get 
                { 
                    return _cacheSettings.CacheProfile ?? String.Empty; 
                } 
                set 
                { 
                    _cacheSettings.CacheProfile = value; 
                } 
            }
    
            internal OutputCacheParameters CacheSettings 
            { 
                get 
                { 
                    return _cacheSettings; 
                } 
            } 
            public int Duration 
            { 
                get 
                { 
                    return _cacheSettings.Duration; 
                } 
                set 
                { 
                    _cacheSettings.Duration = value; 
                } 
            } 
            public OutputCacheLocation Location 
            { 
                get 
                { 
                    return _cacheSettings.Location; 
                } 
                set 
                { 
                    _cacheSettings.Location = value; 
                    
                } 
            } 
            public bool NoStore 
            { 
                get 
                { 
                    return _cacheSettings.NoStore; 
                } 
                set 
                { 
                    _cacheSettings.NoStore = value; 
                    
                } 
            } 
            public string SqlDependency 
            { 
                get 
                { 
                    return _cacheSettings.SqlDependency ?? String.Empty; 
                } 
                set 
                { 
                    _cacheSettings.SqlDependency = value; 
                } 
            } 
            public string VaryByContentEncoding 
            { 
                get 
                { 
                    return _cacheSettings.VaryByContentEncoding ?? String.Empty; 
                } 
                set 
                { 
                    _cacheSettings.VaryByContentEncoding = value; 
                } 
            } 
            public string VaryByCustom 
            { 
                get 
                { 
                    return _cacheSettings.VaryByCustom ?? String.Empty; 
                } 
                set 
                { 
                    _cacheSettings.VaryByCustom = value; 
                } 
            } 
            public string VaryByHeader 
            { 
                get 
                { 
                    return _cacheSettings.VaryByHeader ?? String.Empty; 
                } 
                set 
                { 
                    _cacheSettings.VaryByHeader = value; 
                } 
            } 
            public string VaryByParam 
            { 
                get 
                { 
                    return _cacheSettings.VaryByParam ?? String.Empty; 
                } 
                set 
                { 
                    _cacheSettings.VaryByParam = value; 
                } 
            } 
            public override void OnResultExecuting(ResultExecutingContext filterContext) 
            { 
                if (filterContext == null) 
                { 
                    throw new ArgumentNullException("filterContext"); 
                } 
                if (!filterContext.IsChildAction) 
                { 
                    using (OutputCachedPage page = new OutputCachedPage(_cacheSettings)) 
                    { 
                        page.ProcessRequest(HttpContext.Current); 
                    } 
                } 
            }
            private sealed class OutputCachedPage : Page 
            { 
                private OutputCacheParameters _cacheSettings;
    
                public OutputCachedPage(OutputCacheParameters cacheSettings) 
                { 
                    // Tracing requires Page IDs to be unique. 
                    ID = Guid.NewGuid().ToString(); 
                    _cacheSettings = cacheSettings; 
                }
    
                protected override void FrameworkInitialize() 
                { 
                    base.FrameworkInitialize(); 
                    InitOutputCache(_cacheSettings); 
                } 
            } 
        } 
    } 
    

    使用:

        [MySimpleCache(CacheProfile = "faceProfile")] 
        public ActionResult Index() 
        { 
            return View(); 
        } 
    
  • 相关阅读:
    【EF学习笔记11】----------查询中常用的扩展方法
    .NET 扩展方法
    【EF学习笔记10】----------主从表级联操作
    【EF学习笔记09】----------使用 EntityState 枚举标记实体状态,实现增删改查
    【EF学习笔记08】----------加载关联表的数据 显式加载
    【EF学习笔记07】----------加载关联表的数据 贪婪加载
    【EF学习笔记06】----------加载关联表的数据 延迟加载
    Linux内核ROP姿势详解(二)
    见微知著(三):解析ctf中的pwn--Fastbin和bins的溢出
    见微知著(二):解析ctf中的pwn--怎么利用double free
  • 原文地址:https://www.cnblogs.com/taliu/p/3888130.html
Copyright © 2011-2022 走看看