zoukankan      html  css  js  c++  java
  • 创建一个ASP.NET MVC OutputCache ActionFilterAttribute

     

    使用ASP.NET MVC 框架, 简单的指定OutputCache 指令并不能达到理想的效果. 幸好, ActionFilterAttribute让你能够在 controller action执行的前后运行代码.

    让我们使用类似的方法来创建OutputCache ActionFilterAttribute

    [OutputCache(Duration = 60, VaryByParam = "*", CachePolicy = CachePolicy.Server)]
    public ActionResult Index()
    {
        // ...
    } 

    我们将使用命名为CachePolicy的枚举类型来指定OutputCache 特性应怎样以及在哪里进行缓存:

    public enum CachePolicy
    {
        NoCache = 0,
        Client = 1,
        Server = 2,
        ClientAndServer = 3
    } 

    1.实现client-side缓存

    事实上,这是很容易的。在view呈现前,我们将增加一些HTTP头到响应流。网页浏览器将获得这些头部,并且通过使用正确的缓存设置来回应请求。如果我们设置duration为60,浏览器将首页缓存一分钟。

    using System.Web.Mvc;
    
    namespace MVCActionFilters.Web.Models
    {
        public class OutputCache:System.Web.Mvc.ActionFilterAttribute 
        {
            public int Duration { get; set; }
            public CachePolicy CachePolicy { get; set; }
    
            public override void OnActionExecuted(ActionExecutedContext filterContext)
            {
                if (CachePolicy == CachePolicy.Client || CachePolicy == CachePolicy.ClientAndServer)
                {
                    if (Duration <= 0) return;
    
                    //用于设置特定于缓存的 HTTP 标头以及用于控制 ASP.NET 页输出缓存
                    HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
                    TimeSpan cacheDuration = TimeSpan.FromSeconds(Duration);
    
                    cache.SetCacheability(HttpCacheability.Public);
                    cache.SetExpires(DateTime.Now.Add(cacheDuration));
                    cache.SetMaxAge(cacheDuration);
                    cache.AppendCacheExtension("must-revalidate, proxy-revalidate");
                }
            }
        }
    }

    2. 实现server-side缓存

    Server-side 缓存有一点难度. 首要的,在输出缓存系统中,我们将不得不准备HTTP 响应为可读的。为了这样做,我们首先保存当前的HTTP context到类的一个变量中. 然后, 我们创建一个新的httpcontext ,通过它将数据写入StringWriter,同时允许读操作可以发生:

    existingContext = System.Web.HttpContext.Current;//保存当前的HTTP context到类的一个变量中
    writer = new StringWriter();
    HttpResponse response = new HttpResponse(writer);
    HttpContext context = new HttpContext(existingContext.Request, response)
    {
        User = existingContext.User
    };
    System.Web.HttpContext.Current = context; 
     
     
     
    
     public override void OnResultExecuting(ResultExecutingContext filterContext)
            {
                if (CachePolicy == CachePolicy.Server || CachePolicy == CachePolicy.ClientAndServer)
                {
                    //获取缓存实例
                    cache = filterContext.HttpContext.Cache;
    
                    // 获取缓存数据
                    object cachedData = cache.Get(GenerateKey(filterContext));
                    if (cachedData != null)
                    {
                        // 返回缓存数据
                        cacheHit = true;
                        filterContext.HttpContext.Response.Write(cachedData);
                        filterContext.Cancel = true;
                    }
                    else
                    {  //重新设置缓存数据
                        existingContext = System.Web.HttpContext.Current;
                        writer = new StringWriter();
                        HttpResponse response = new HttpResponse(writer);
                        HttpContext context = new HttpContext(existingContext.Request, response)
                        {
                            User = existingContext.User
                        };
                        foreach (var key in existingContext.Items.Keys)
                        {
                            context.Items[key] = existingContext.Items[key];
                        }
                        System.Web.HttpContext.Current = context;
                    }
                }
            }

    利用该代码,我们能从高速缓存中检索现有项,并设置了HTTP响应能够被读取。在视图呈现之后,将数据存储在高速缓存中:

    public override void OnResultExecuted(ResultExecutedContext filterContext)
            {
                // 服务器端缓存?
                if (CachePolicy == CachePolicy.Server || CachePolicy == CachePolicy.ClientAndServer)
                {
                    if (!cacheHit)
                    {
                        // 存储原有的context
                        System.Web.HttpContext.Current = existingContext;
    
                        // 返回呈现的数据
                        existingContext.Response.Write(writer.ToString());
    
                        //增加数据到缓存
                        cache.Add(
                            GenerateKey(filterContext),
                            writer.ToString(),
                            null,
                            DateTime.Now.AddSeconds(Duration),
                            Cache.NoSlidingExpiration,
                            CacheItemPriority.Normal,
                             null);
                    }
                }
            } 
     
     

    你现在注意到添加了一个VaryByParam到 OutputCache ActionFilterAttribute。当缓存server-side时,我可以通过传入的参数来改变缓存存储。这个GenerateKey方法会产生一个依赖于controller,action和VaryByParam的键。

     private string GenerateKey(ControllerContext filterContext)
            {
                StringBuilder cacheKey = new StringBuilder();
    
                // Controller + action
                cacheKey.Append(filterContext.Controller.GetType().FullName);
                if (filterContext.RouteData.Values.ContainsKey("action"))
                {
                    cacheKey.Append("_");
                    cacheKey.Append(filterContext.RouteData.Values["action"].ToString());
                }
    
                // Variation by parameters
                List<string> varyByParam = VaryByParam.Split(';').ToList();
    
                if (!string.IsNullOrEmpty(VaryByParam))
                {
                    foreach (KeyValuePair<string, object> pair in filterContext.RouteData.Values)
                    {
                        if (VaryByParam == "*" || varyByParam.Contains(pair.Key))
                        {
                            cacheKey.Append("_");
                            cacheKey.Append(pair.Key);
                            cacheKey.Append("=");
                            cacheKey.Append(pair.Value.ToString());
                        }
                    }
                }
                return cacheKey.ToString();
            }
     
     

    现在你可以增加 OutputCache attribute 到应用程序的任何一个controller 与controller action中 。

    [MVCActionFilters.Web.Common.OutputCache(Duration = 20, VaryByParam = "*",CachePolicy=Common.CachePolicy.Client)]
            public string Cache()
            {
                return DateTime.Now.ToString();
            }
     
     

    设置CachePolicy为Common.CachePolicy.Client时,将直接在客户端缓存中读取数据。

  • 相关阅读:
    教你一招Linux下文本比对方法
    Linux下find与exec的联手干大事
    Linux下Shell日期的格式,你知道几种?
    Linux下Python3.6的安装及避坑指南
    多线程中使用CompletableFuture
    ElasticSearch7.6.2中语法使用(更新中)
    ElasticSearch7.6.2使用_update_by_query语法
    ElasticSearch7.6.2使用_delete_by_query产生版本冲突问题
    filebeat7.6.2进程运行一段时间后自动退出问题解决
    把本地项目提交到gitLab
  • 原文地址:https://www.cnblogs.com/yxlblogs/p/3597842.html
Copyright © 2011-2022 走看看