Introduction
In this post, we will learn how to implement output cache action filter attribute in ASP.NET Web API.
Implementation
First, we will define the CacheEnabled
and CacheTimespan
properties in the appSettings
.
CacheEnabled
will be used to enable or disable the cache
CacheTimespan
represents the time span that we will cache the output.
In the next step, we will create a class named WebApiOutputCacheAttribute.cs that defines action Filter
to cache responses.
Add the following code snippet in WebApiOutputCacheAttribute
class:
public class WebApiOutputCacheAttribute : ActionFilterAttribute
{
private int _timespan;
private bool _cacheEnabled = false;
private readonly bool _dependsOnIdentity;
private static readonly ObjectCache WebApiCache = MemoryCache.Default;
private readonly bool _invalidateCache;
public WebApiOutputCacheAttribute()
: this(true)
{
}
public WebApiOutputCacheAttribute(bool dependsOnIdentity)
: this(dependsOnIdentity, false)
{
}
public WebApiOutputCacheAttribute(bool dependsOnIdentity, bool invalidateCache)
{
_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 (WebApiCache.Contains(_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 (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)
{
}
}
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;
}
}
Usage
public class UserDashboardController : ApiController
{
private DBEntities db = new DBEntities();
[WebApiOutputCacheAttribute(true)]
public dynamic Get(long id)
{
return db.Users;
}
}
The post Output Cache Action Filter Attribute in ASP.NET Web API appeared first on Venkat Baggu Blog.