How to retrieve already cached data inside webapi controller method C#

允我心安 提交于 2019-12-23 05:30:35

问题


I have created a OutputCacheFilter attribute by inheriting ActionFilterAttribute to get the caching functionality for the controller method.

This is my OutputCacheFilter class

public class OutputCacheFilter : 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;

    public OutputCacheFilter()
        : this(true)
    {
    }

    public OutputCacheFilter(bool dependsOnIdentity)
        : this(dependsOnIdentity, false)
    {
    }

    public OutputCacheFilter(bool dependsOnIdentity, bool invalidateCache)
    {
        //_securityHelper = new SecurityHelper();
        _dependsOnIdentity = dependsOnIdentity;
        _invalidateCache = invalidateCache;

        ReadConfig();
    }

    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");
            }
        }
    }

    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);
        }
    }

    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;
    }

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

This is My controller

public class MessageController : ApiController
{
    [OutputCacheFilter()]
    public IHttpActionResult GetMessages()
    {
        MesssageManager msgManager = null;
        try
        {
            msgManager = new MesssageManager();
            List<Message> messages = msgManager.GetMessages();
            return Ok(messages);
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            msgManager = null;
        }
    }


    public IHttpActionResult GetMessage(string messageCode)
    {
        Message msg = null;
        MesssageManager msgManager = null;
        try
        {
            if(string.IsNullOrEmpty(messageCode))
            {
                throw new Exception("Plase pass the messageCode in order to get the message.");
            }
            msgManager = new MesssageManager();
            List<Message> messages = msgManager.GetMessages();
            msg = messages.FirstOrDefault(o => o.Code.Equals(messageCode, StringComparison.InvariantCultureIgnoreCase));
            return Ok(msg);
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            msgManager = null;
        }
    }

}

DTO Model

public class Message
{
    public int ID { get; set; }
    public string Code { get; set; }
    public string Description { get; set; }
    public string Type { get; set; }
    public char IsActive { get; set; }
}

In my collroller there are two methods

  1. GetMessages - This method retrieves the all messaged from database and store in cache so it is decorated by OutputCacheFilter attribute to accomplish it.

  2. GetMessage - This method is used to get the single message by messageCode, this is currently calling the database method to get the all code and then in result it search the message by messageCode. Here I want to retrieve the message from cache it self by calling the same controller method "GetMessages()" so if cache is available then get from cache result else from database as GetMessages() is doing.

To do so I called the GetMessages() controller method in my GetMessage() but is always retrieve the message from database, it does not consider cached message.

Please help me to implement the correct approach for this scenario.

来源:https://stackoverflow.com/questions/50288351/how-to-retrieve-already-cached-data-inside-webapi-controller-method-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!