问题
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
GetMessages - This method retrieves the all messaged from database and store in
cache
so it is decorated byOutputCacheFilter
attribute to accomplish it.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