We have a Web API 2 application that is using Strathweb.CacheOutput.WebApi2 for caching.
Short question: Is there a way to detect in Application_LogRequest (or anywhere, really) whether a request was served by cache?
Long question: Lately, we've been looking at performance and seeing which API calls we can improve. I pulled a list from our logs (which includes duration) to see what the worst offenders are. By worst offenders, I mean the longest average durations and/or the most number of calls.
But the numbers are misleading because the cached requests are included in the stats. Cached requests are usually served in half a second or less, so they pull average durations down. Also, if a particular call is being made, say 1000 times a minute, but 999 of those are cached, I don't really care.
So I'd like to add a flag in my log that indicates whether the request was served by the cache, so I can exclude those. All our logging is done in the Application_LogRequest event. But even if I can detect it somewhere else, I can store a value in HttpContext.Current.Items
that I can retrieve later.
Strathweb CacheOutputAttribute
does not add some reliable information in http responses or elsewhere for allowing to know whether the response was served from cache or not.
You may derive from it for doing that, then replace all your usage of CacheOutputAttribute
by your own.
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class YourCustomizedCacheOutputAttribute : CacheOutputAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
base.OnActionExecuting(actionContext);
// If response is set, it has been retrieved from cache.
actionContext.Request.Properties["yourCacheHitKey"] =
actionContext.Response != null;
}
}
Of course, use something else than HttpRequestMessage.Properties
if where you log you do not have access to it.
You may by example add some custom header in response, if leaking that out to browsers is not an issue for you:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class YourCustomizedCacheOutputAttribute : CacheOutputAttribute
{
// "X-" prefix is deprecated, but the rational behind this is about wannabe
// standard header. I do not intend this one to become standard for anything.
private const string _cacheHeader = "X-Cache";
protected override void ApplyCacheHeaders(HttpResponseMessage response,
CacheTime cacheTime)
{
base.ApplyCacheHeaders(response, cacheTime);
if (response.Headers.Contains(_cacheHeader))
return;
// At this point, we do not know. miss by default.
response.Headers.Add(_cacheHeader, "miss");
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
base.OnActionExecuting(actionContext);
if (actionContext.Response == null)
return;
// Response has been retrieved from cache.
// Headers.Remove does not fail if not already there.
response.Headers.Remove(_cacheHeader);
actionContext.Response.Headers.Add(_cacheHeader, "hit");
}
}