harishr
harishr

Reputation: 18065

custom caching policy not applied for api response in web-api-2/owin

I am just starting with web-api 2 and stumbled upon : how to set caching settings. I have custom caching-message-handler like below (simplified for SO post)

public class CachingMessageHandler : DelegatingHandler
{
    private void SetCachingPolicy(HttpResponseMessage response)
    {
        response.Headers.CacheControl = new CacheControlHeaderValue
        {
            MaxAge = TimeSpan.FromSeconds(100),
        };
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        return base
            .SendAsync(request, cancellationToken)
            .ContinueWith(task =>
            {
                var response = task.Result;
                if (request.Method == HttpMethod.Get) SetCachingPolicy(response);
                return response;
            }, cancellationToken);
    }
}

and I have various hello-world HttpGet api's

    [HttpGet]
    public HttpResponseMessage Get1()
    {
        HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "value");
        response.Content = new StringContent("Hello World 1", Encoding.Unicode);
        return response;
    }

    [HttpGet]
    public HttpResponseMessage Get2()
    {
        return Request.CreateResponse(HttpStatusCode.OK, "Hello World 2");
    }

    [HttpGet]
    public HttpResponseMessage Get2_1()
    {
        var response = Request.CreateResponse(HttpStatusCode.OK, "Hello World 2");
        response.Headers.CacheControl = null;
        return response;
    }

    [HttpGet]
    public OkNegotiatedContentResult<string> Get3()
    {
        return Ok("Hello World 3");
    }

    [HttpGet]
    public string Get4()
    {
        return "Hello World 4";
    }

but the caching-message-handler is applied only for Get1 api, for all other Get2/3/4 api's, it seems some default caching setting is used. Below is the response in postman

enter image description here

Can someone please explain this behavior!!! why is caching only applied for Content-Type : text/plain and not for application/json

Upvotes: 2

Views: 1127

Answers (3)

zhimin
zhimin

Reputation: 3050

I use angular and WebAPI with owin to build app too, and I have a custom cache filter too, but I use System.Web.Http.Filters.ActionFilterAttribute instead of DelegatingHandler , and it works for all response types, here is my custom cache filter code:

public class NoCacheFilter : System.Web.Http.Filters.ActionFilterAttribute {

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) {
        if (actionExecutedContext.Request.Method == System.Net.Http.HttpMethod.Get && actionExecutedContext.Response != null) {
            actionExecutedContext.Response.Headers.CacheControl = new CacheControlHeaderValue {
                NoCache = true, NoStore = true, MustRevalidate = true,
                //MaxAge = TimeSpan.FromSeconds(100)
            };
            actionExecutedContext.Response.Headers.Pragma.Add(new NameValueHeaderValue("no-cache"));
            if (actionExecutedContext.Response.Content != null) {
                actionExecutedContext.Response.Content.Headers.Expires = DateTimeOffset.UtcNow;
            }
        }
        base.OnActionExecuted(actionExecutedContext);
    }
}

I register the filter in the Configure method like this:

var config = new HttpConfiguration();
config.Filters.Add(new NoCacheFilter());
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);
app.UseWebApi(config);

I think maybe you should try to use ActionFilterAttribute.

Upvotes: 2

Muhammad Reda
Muhammad Reda

Reputation: 27043

You need to add Access-Control-Expose-Headers header at the backend. CORS returns certain response headers, so you need to tell it to return any other custom headers.

Access-Control-Expose-Headers: your-custom-cache-header-1, your-custom-cache-header-2, any-other-headers

Update

Since postman returns the same results, so it is not angular-related issue. It all resides on the server logic. Try to debug the lifecycle of text/plain and application/json requests. That might give you an idea why certain headers are not being set for application/json requests.

Upvotes: 1

algos
algos

Reputation: 238

Ideally you should disable caching from server side. But since you tagged angularjs & you want to disable caching globally - you can do it like below

app.config(['$httpProvider', function($httpProvider) {
    if (!$httpProvider.defaults.headers.get)  $httpProvider.defaults.headers.get = {};    

    $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache';
    $httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
}]);

Upvotes: 0

Related Questions