在asp.net web api中利用过滤器设置输出缓存

介绍

 本文将介绍如何在asp.net web api中利用过滤器属性实现缓存。

实现过程

1,首先在web.config文件下appsettings下定义“CacheEnabled”和“CacheTimespan”两个属性,

CacheEnabled属性决定是否启用缓存

CacheTimespan决定缓存过期时间戳

如下代码所示:

   

复制代码
  <appSettings>
    <!--<add key="webpages:Version" value="2.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="PreserveLoginUrl" value="true" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />-->
    <add key="CacheEnabled" value="true"/>
    <add key="CacheTimespan" value="12000"/>
  </appSettings>
复制代码

 

2,添加WebApiOutputCacheAttribute类并继承ActionFilterAttribute ,需要添加引用:

using System.Net.Http;
using System.Web.Configuration;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;

代码相当简单和直白,就是在get方法执行前判断缓存key存在不存在,如果存在读取value,并输出,在过滤器执行完后更新缓存,如果不存在刚直接调用api中get方法,输出结果。

复制代码
    public class WebApiOutputCacheAttribute :System.Web.Http.Filters.ActionFilterAttribute
    {
        // cache length in seconds
        private int _timespan;
        // true to enable cache
        private bool _cacheEnabled = false;
        // true if the cache depends on the caller user
        private readonly bool _dependsOnIdentity;
        // cache repository
        private static readonly ObjectCache WebApiCache = MemoryCache.Default;
        //private readonly SecurityHelper _securityHelper;
        private readonly bool _invalidateCache;

        /// <summary>
        /// Constructor
        /// </summary>
        public WebApiOutputCacheAttribute()
            : this(true)
        {
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="dependsOnIdentity"></param>
        public WebApiOutputCacheAttribute(bool dependsOnIdentity)
            : this(dependsOnIdentity, false)
        {
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="dependsOnIdentity"></param>
        /// <param name="invalidateCache">true to invalidate cache object</param>
        public WebApiOutputCacheAttribute(bool dependsOnIdentity, bool invalidateCache)
        {
            //_securityHelper = new SecurityHelper();
            _dependsOnIdentity = dependsOnIdentity;
            _invalidateCache = invalidateCache;

            ReadConfig();
        }

        /// <summary>
        /// Called by the ASP.NET MVC framework before the action method executes.
        /// </summary>
        /// <param name="filterContext">The filter context.</param>
        public override void OnActionExecuting(HttpActionContext filterContext)
        {
            if (_cacheEnabled)
            {
                if (filterContext != null)
                {
                    if (IsCacheable(filterContext))
                    {
                        string _cachekey = string.Join(":", new string[] 
                        { 
                            filterContext.Request.RequestUri.OriginalString,
                            filterContext.Request.Headers.Accept.FirstOrDefault().ToString(), 
                        });

                        //if (_dependsOnIdentity)
                        //    _cachekey = _cachekey.Insert(0, _securityHelper.GetUser());

                        if (WebApiCache.Contains(_cachekey))
                        {
                            //TraceManager.TraceInfo(String.Format("Cache contains key: {0}", _cachekey));

                            var val = (string)WebApiCache.Get(_cachekey);
                            if (val != null)
                            {
                                filterContext.Response = filterContext.Request.CreateResponse();
                                filterContext.Response.Content = new StringContent(val);
                                var contenttype = (MediaTypeHeaderValue)WebApiCache.Get(_cachekey + ":response-ct");
                                if (contenttype == null)
                                    contenttype = new MediaTypeHeaderValue(_cachekey.Split(':')[1]);
                                filterContext.Response.Content.Headers.ContentType = contenttype;
                                return;
                            }
                        }
                    }
                }
                else
                {
                    throw new ArgumentNullException("actionContext");
                }
            }
        }

        /// <summary>
        /// Called by the ASP.NET MVC framework after the action method executes.
        /// </summary>
        /// <param name="filterContext">The filter context.</param>
        public override void OnActionExecuted(HttpActionExecutedContext filterContext)
        {
            try
            {
                if (_cacheEnabled)
                {
                    if (WebApiCache != null)
                    {
                        string _cachekey = string.Join(":", new string[] 
                        { 
                            filterContext.Request.RequestUri.OriginalString,
                            filterContext.Request.Headers.Accept.FirstOrDefault().ToString(), 
                        });

                        //if (_dependsOnIdentity)
                        //    _cachekey = _cachekey.Insert(0, _securityHelper.GetUser());

                        if (filterContext.Response != null && filterContext.Response.Content != null)
                        {
                            string body = filterContext.Response.Content.ReadAsStringAsync().Result;

                            if (WebApiCache.Contains(_cachekey))
                            {
                                WebApiCache.Set(_cachekey, body, DateTime.Now.AddSeconds(_timespan));
                                WebApiCache.Set(_cachekey + ":response-ct", filterContext.Response.Content.Headers.ContentType, DateTime.Now.AddSeconds(_timespan));
                            }
                            else
                            {
                                WebApiCache.Add(_cachekey, body, DateTime.Now.AddSeconds(_timespan));
                                WebApiCache.Add(_cachekey + ":response-ct", filterContext.Response.Content.Headers.ContentType, DateTime.Now.AddSeconds(_timespan));
                            }
                        }
                    }
                }

                if (_invalidateCache)
                {
                    CleanCache();
                }
            }
            catch (Exception ex)
            {
                //TraceManager.TraceError(ex);
            }
        }

        /// <summary>
        /// Removes all items from the cache
        /// </summary>
        private static void CleanCache()
        {
            if (WebApiCache != null)
            {
                List<string> keyList = WebApiCache.Select(w => w.Key).ToList();
                foreach (string key in keyList)
                {
                    WebApiCache.Remove(key);
                }
            }
        }

        private void ReadConfig()
        {
            if (!Boolean.TryParse(WebConfigurationManager.AppSettings["CacheEnabled"], out _cacheEnabled))
                _cacheEnabled = false;

            if (!Int32.TryParse(WebConfigurationManager.AppSettings["CacheTimespan"], out _timespan))
                _timespan = 1800; // seconds
        }

        private bool IsCacheable(HttpActionContext ac)
        {
            if (_timespan > 0)
            {
                if (ac.Request.Method == HttpMethod.Get)
                    return true;
            }
            else
            {
                throw new InvalidOperationException("Wrong Arguments");
            }
            return false;
        }
    }
复制代码

 

在api中:

        // GET api/values/5
        [WebApiOutputCacheAttribute(true)]
        public string Get(int id)
        {
            return DateTime.Now.ToString();
        }

 

 

 
posted @ 2018-12-26 13:57  野狼谷  阅读(247)  评论(0编辑  收藏  举报