Skip to content

Instantly share code, notes, and snippets.

@bradwilson
Created January 23, 2014 20:53

Revisions

  1. bradwilson created this gist Jan 23, 2014.
    6 changes: 6 additions & 0 deletions Cacheability.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,6 @@
    public enum Cacheability
    {
    NoCache,
    Private,
    Public,
    }
    71 changes: 71 additions & 0 deletions CachedResult.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,71 @@
    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;
    }
    }
    19 changes: 19 additions & 0 deletions HttpActionResultExtensions.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    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);
    }
    }
    12 changes: 12 additions & 0 deletions SampleController.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    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));
    }
    }