In this blog, we will discuss
about Web API caching and memory caching and how it improve the overall
performance of Web API. Cached data save database call or external call to
process the future request.
Web API doesn’t support the
output caching and we have to store the data in local memory or in database.
ASP.NET Web API Caching |
Here is code sample to implement
memory caching in web api.
Microsoft provides the System.Runtime.Caching library for
memory caching.
Add a reference above lib and
here is a Helper Class to store data or get data from cached memory
using System;
using System.Runtime.Caching;
public static class MemoryCacher
{
public static object GetValue(string key)
{
MemoryCache memoryCache = MemoryCache.Default;
return memoryCache.Get(key);
}
public static bool Add(string key, object value,
DateTimeOffset absExpiration)
{
MemoryCache memoryCache = MemoryCache.Default;
return memoryCache.Add(key, value,
absExpiration);
}
public static void Delete(string key)
{
MemoryCache memoryCache = MemoryCache.Default;
if (memoryCache.Contains(key))
{
memoryCache.Remove(key);
}
}
}
Add data in cache memory:
MemoryCacher.Add(“Key”,Object, DateTimeOffset.UtcNow.AddYears(1))
Get data from cache memory:
MemoryCacher.Get(“Key”)
ASP.NET Web API provides the
filters, that you can use to add extra logic before or after action executes, so
above caching data logic you can use inside filter to cache web api response.
Here is an example how to create
action filter that cache web api response.
public class WebAPICacheAttribute : ActionFilterAttribute
{
public int Duration { get; set; }
private bool CacheEnabled = false;
public WebAPICacheAttribute(int _duration, bool _cacheEnabled)
{
Duration = _duration;
CacheEnabled = _cacheEnabled;
}
public override void OnActionExecuting(HttpActionContext context)
{
if (CacheEnabled)
{
if (context != null)
{
//generate cache key
from HTTP request URI and Header
string _cachekey = string.Join(":", new string[]
{
context.Request.RequestUri.OriginalString,
context.Request.Headers.Accept.FirstOrDefault().ToString(),
});
// Check Key exists
if (MemoryCacher.Contains(_cachekey))
{
var val = (string)MemoryCacher.GetValue(_cachekey);
if (val != null)
{
context.Response = context.Request.CreateResponse();
context.Response.Content = new StringContent(val);
var contenttype = (MediaTypeHeaderValue)MemoryCacher.GetValue(_cachekey +
":response-ct");
if (contenttype == null)
contenttype = new MediaTypeHeaderValue(_cachekey.Split(':')[1]);
context.Response.Content.Headers.ContentType = contenttype;
return;
}
}
}
}
}
public override void OnActionExecuted(HttpActionExecutedContext context)
{
if (CacheEnabled)
{
if (WebApiCache != null)
{
string _cachekey = string.Join(":", new string[]
{
context.Request.RequestUri.OriginalString,
context.Request.Headers.Accept.FirstOrDefault().ToString(),
});
if (context.Response
!= null &&
context.Response.Content != null)
{
string body =
context.Response.Content.ReadAsStringAsync().Result;
if (MemoryCacher.Contains(_cachekey))
{
MemoryCacher.Add(_cachekey, body, DateTime.Now.AddSeconds(Duration));
MemoryCacher.Add(_cachekey + ":response-ct",
context.Response.Content.Headers.ContentType,
DateTime.Now.AddSeconds(_timespan));
}
else
{
MemoryCacher.Add(_cachekey, body, DateTime.Now.AddSeconds(Duration));
MemoryCacher.Add(_cachekey + ":response-ct",
context.Response.Content.Headers.ContentType,
DateTime.Now.AddSeconds(Duration));
}
}
}
}
}
}
Now you can use WebAPICache
action filter on GetProject Action to cache Project data and if the client will
send the same request, the Web API will not call to data repository layer
to get project records, it will get from cache
Web API Controller:
public class ProjectApiController : ApiController
{
[HttpGet]
[Route("api/Project/{projectId:int}")]
[WebAPICache(_duration:3600,_cacheEnabled: true)]
public Project GetProject(int projectId)
{
return Repository.GetProperty(projectId);
}
}
Thanks for visiting!!
5 comments:
G8 article. Got below errors when I use above code,
1. if (MemoryCacher.Contains(_cachekey))
No method named "Contains"
2. DateTime.Now.AddSeconds(_timespan));
No property named "_timespan"
3. if (WebApiCache != null)
No property/object named WebApiCache
I got the same issues what Ravi said.Can you help us to resolve those issues?
I have same issues.....
Good article Rajiv! Thanks for sharing it in easy word.
Post a Comment