Skip to content

Instantly share code, notes, and snippets.

@bradwilson
Created January 23, 2014 20:53
Show Gist options
  • Star 78 You must be signed in to star a gist
  • Fork 15 You must be signed in to fork a gist
  • Save bradwilson/8586562 to your computer and use it in GitHub Desktop.
Save bradwilson/8586562 to your computer and use it in GitHub Desktop.
Using chaining to create cached results in ASP.NET Web API v2
public enum Cacheability
{
NoCache,
Private,
Public,
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
public class CachedResult<T> : IHttpActionResult
where T : IHttpActionResult
{
public CachedResult(
T innerResult,
Cacheability cacheability,
string eTag,
DateTimeOffset? expires,
DateTimeOffset? lastModified,
TimeSpan? maxAge,
bool? noStore)
{
Cacheability = cacheability;
ETag = eTag;
Expires = expires;
InnerResult = innerResult;
LastModified = lastModified;
MaxAge = maxAge;
NoStore = noStore;
}
public Cacheability Cacheability { get; private set; }
public string ETag { get; private set; }
public DateTimeOffset? Expires { get; private set; }
public T InnerResult { get; private set; }
public DateTimeOffset? LastModified { get; private set; }
public TimeSpan? MaxAge { get; private set; }
public bool? NoStore { get; private set; }
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = await InnerResult.ExecuteAsync(cancellationToken);
if (!response.Headers.Date.HasValue)
response.Headers.Date = DateTimeOffset.UtcNow;
response.Headers.CacheControl = new CacheControlHeaderValue
{
NoCache = Cacheability == Cacheability.NoCache,
Private = Cacheability == Cacheability.Private,
Public = Cacheability == Cacheability.Public
};
if (response.Headers.CacheControl.NoCache)
{
response.Headers.Pragma.TryParseAdd("no-cache");
response.Content.Headers.Expires = response.Headers.Date;
return response; // None of the other headers are valid
}
response.Content.Headers.Expires = Expires;
response.Content.Headers.LastModified = LastModified;
response.Headers.CacheControl.MaxAge = MaxAge;
if (!String.IsNullOrWhiteSpace(ETag))
response.Headers.ETag = new EntityTagHeaderValue(String.Format("\"{0}\"", ETag));
if (NoStore.HasValue)
response.Headers.CacheControl.NoStore = NoStore.Value;
return response;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
public static class HttpActionResultExtensions
{
public static CachedResult<T> Cached<T>(
this T actionResult,
Cacheability cacheability = Cacheability.Private,
string eTag = null,
DateTimeOffset? expires = null,
DateTimeOffset? lastModified = null,
TimeSpan? maxAge = null,
bool? noStore = null) where T : IHttpActionResult
{
return new CachedResult<T>(actionResult, cacheability, eTag, expires, lastModified, maxAge, noStore);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
public SampleController : ApiController
{
public IHttpActionResult GetExample(string name)
{
return Ok("Hello, " + name).Cached(Cacheability.Public, maxAge: TimeSpan.FromMinutes(15));
}
}
@darrelmiller
Copy link

Thanks, that makes sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment