Search code examples
c#asp.net-web-apiasp.net-corecache-control

Best practice of Cache-Control for Bad Request (400)


Currently I have the following action which will tell the client to cache the response for 1200 seconds:

[ResponseCache(Location = ResponseCacheLocation.Client, Duration = 1200)]
[HttpGet("universities")]
public IActionResult GetAllUniversities(string location)
{
    if (/*location not found*/)
      return BadRequest();

    ...
    return Ok(universities);
}

In the response header, when it returns Ok (200), I received the following value:

Cache-Control: private, max-age=1200

Which is perfect as expected.

When I passed the wrong location to the API and the API returns BadRequest (400), it also returns the same Cache-Control value as above.

My question is, is this the best practice? Or should it return no-cache, no-store instead for 400? If it should, how do I return private, max-age=1200 when it's 200 and return no-cache, no-store in .NET Core for this particular action only?


Solution

  • Because I need to satisfy the following conditions:

    1. Do not return response cache header value if the response code is not 200.
    2. Returns private, max-age=1200 if the response code is 200.
    3. The solution should be applied to certain controller action only.

    So I decided to create an attribute class that implements IResultFilter instead.

    public sealed class PrivateCacheControlResultFilterAttribute : Attribute, IResultFilter
    {
        public void OnResultExecuted(ResultExecutedContext context)
        {
        }
    
        public void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.OnStarting(state =>
            {
                var httpContext = ((ResultExecutingContext)state).HttpContext;
    
                if (httpContext.Response.StatusCode == 200)
                    httpContext.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue
                    {
                        Private = true,
                        MaxAge = TimeSpan.FromSeconds(1200)
                    };
                return Task.CompletedTask;
            }, context);
        }
    }
    

    Then use this new attribute on the GetAllUniversities action.

    [PrivateCacheControlResultFilter]
    [HttpGet("universities")]
    public IActionResult GetAllUniversities(string location)
    {
        if (/*location not found*/)
          return BadRequest();
    
        ...
        return Ok(universities);
    }