58

What's the best way to set cache control headers for public caching servers in WebAPI?

I'm not interested in OutputCache control on my server, I'm looking to control caching at the CDN side and beyond (I have individual API calls where the response can be indefinitely cached for the given URL) but everything I've read thus far either references pre-release versions of WebAPI (and thus references things that seem to no longer exist, like System.Web.HttpContext.Current.Reponse.Headers.CacheControl) or seems massively complicated for just setting a couple of http headers.

Is there a simple way to do this?

4 Answers 4

104

As suggested in the comments, you can create an ActionFilterAttribute. Here's a simple one that only handles the MaxAge property:

public class CacheControlAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
    public int MaxAge { get; set; }

    public CacheControlAttribute()
    {
        MaxAge = 3600;
    }

    public override void OnActionExecuted(HttpActionExecutedContext context)
    {
        if (context.Response != null)
            context.Response.Headers.CacheControl = new CacheControlHeaderValue()
            {
                Public = true,
                MaxAge = TimeSpan.FromSeconds(MaxAge)
            };

        base.OnActionExecuted(context);
    }
}

Then you can apply it to your methods:

 [CacheControl(MaxAge = 60)]
 public string GetFoo(int id)
 {
    // ...
 }
Sign up to request clarification or add additional context in comments.

1 Comment

This chace is only for the client side ? For server cache I should Strathweb.CacheOutput.WebApi2 setting the attribute to any , rigth ?
81

The cache control header can be set like this.

public HttpResponseMessage GetFoo(int id)
{
    var foo = _FooRepository.GetFoo(id);
    var response = Request.CreateResponse(HttpStatusCode.OK, foo);
    response.Headers.CacheControl = new CacheControlHeaderValue()
        {
            Public = true,
            MaxAge = new TimeSpan(1, 0, 0, 0)
        };
    return response;
}

9 Comments

Thats one of the approaches I know about, but I was hoping for something that was less invasive and specifically something that did not require you to remove useful information from the method declaration (going from a specific return type to a very generic one is not a good change imho). Thanks anyhow.
@Moo you could easily create an ActionFilterAttribute that does these few lines. Personally, I only use HttpResponseMessage as my return type, so the above style doesn't both me. HTTP is a generic interface, so reflecting that in my API layer makes sense to me.
@Moo And if you could tell what went over the wire from looking at the signature I might agree. However, you have no idea what is going over the wire. It could be JSON, it could be a XMLSerializer serialization of the object, it could be DataContractSerialization of the object. You have no idea, unless you know all of the installed formatters, what order they were setup, what the accept header looks like, what the limits of the formatters are, etc, etc.
What goes out over the wire is only half the party tho, I have to write and maintain this stuff, and hand it over to other developers. Hiding what actually is returned in the method block rather than in the declaration means the docs have to be 100% spot on all the time, and we know how well that goes don't we...
@VishnooRath It works the same whether you use attribute routing or regular routing
|
10

In case anyone lands here looking for an answer specifically to ASP.NET Core, you can now do what @Jacob suggested without writing your own filter. Core already includes this:

[ResponseCache(VaryByHeader = "User-Agent", Duration = 1800)]
public async Task<JsonResult> GetData()
{
}

https://learn.microsoft.com/en-us/aspnet/core/performance/caching/response

1 Comment

You are missing a closing bracket ) after duration :)
3

Like this answer suggesting filters, consider the "extended" version -- http://www.strathweb.com/2012/05/output-caching-in-asp-net-web-api/

It used to be available as a NuGet package Strathweb.CacheOutput.WebApi2, but doesn't seem to be hosted anymore, and is instead on GitHub -- https://github.com/filipw/AspNetWebApi-OutputCache

1 Comment

I just found it in NuGet but I guess that might be a VS version thing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.