22

In ASP.NET Core application I have a action method that returns some data. I wanted to cache this data on client side. So based on the documentation here i can use ResponseCache attribute on the action method. This attribute adds Cache-Control header in response

Response caching refers to specifying cache-related headers on HTTP responses made by ASP.NET Core MVC actions. These headers specify how you want client and intermediate (proxy) machines to cache responses to certain requests (if at all). This can reduce the number of requests a client or proxy makes to the web server, since future requests for the same action may be served from the client or proxy’s cache.

also

Response caching does not cache responses on the web server. It differs from output caching, which would cache responses in memory on the server in earlier versions of ASP.NET and ASP.NET MVC.

So this is how my action method looks

public class LookupController : Controller
{
    [HttpGet]
    [ResponseCache(Duration = 120)]
    public IEnumerable<StateProvinceLookupModel> GetStateProvinces()
    {
        return _domain.GetStateProvinces();
    }
}

Then i call the method using browser as http://localhost:40004/lookup/getstateprovinces Here is the request and response headers

enter image description here

Notice that Response Headers has Cache-Control: public,max-age-120 as expected. However if refresh the page using F5 (before 120 seconds), the debugger breakpoint inside GetStateProvince action method alway hits. That means its not cahing the data on client side.

Is there anything else i need to do to enable client side caching?

Update I have tried using IE, Chrome and also POSTMAN with no luck. Everytime i type the url in address bar or hit refresh the client ( that is browser or postman) makes a call to action method.

LP13
  • 20,711
  • 38
  • 136
  • 286
  • @dotnetstep is right, also f5(refresh page) is already a cache broker on client side as I know. just enter the address in the address bar and enter. that the way I check cache – ergen Nov 02 '16 at 13:40
  • 1
    @ergen i have also tried with POSTMAN with no luck – LP13 Nov 02 '16 at 14:39
  • I do not know who post man is. let s clarify: try simply going to url on your browser instead of refresh. refresh is broker, secondly file type is important for client caching. for example, you don't except your 1000 mb video to be cached. you cache just a .json, so it does not matter. then, I am sure that you cache will work when you use an url like licalhost/lookup/getstateprovinces.json. focus on extension and cachable files in the client side. even if you add header to your response,browser may not know your file as a static file due to extension – ergen Nov 02 '16 at 15:05
  • 1
    why would i use filetype? Its an action method. You never call action method as `http://localhost/lookup/getstateprovinces.json`. btw on side note here is postman https://www.getpostman.com/ – LP13 Nov 02 '16 at 15:12
  • I did not say you should use filetype. I said that you would see your cache would work when you gave an extension. I advise you to make sure your _domain.GetStateProvinces(); method returns an valid json with a .json extension. it s just a result,not even a file without an extension. think that you serve an .aspx page and command the browser to cache all files with .aspx extension. summary:try add something like extension or mimetype(that depends on what and how your_domain.GetStateProvinces(); method return) and see if it works – ergen Nov 02 '16 at 15:23

3 Answers3

19

Actually ResponseCache attribute works as intended.
The difference is that the response is cached if you navigate through your website pages (case 1), or use back and forward buttons (not when refreshing the page).

As an example of case 1, I have the following:

As you will see in the article Response Caching in ASP.Net Core 1.1, the following is stated:

During a browser session, browsing multiple pages within the website or using back and forward button to visit the pages, content will be served from the local browser cache (if not expired).
But when page is refreshed via F5, the request will be go to the server and page content will get refreshed. You can verify it via refreshing contact page using F5.
So when you hit F5, response caching expiration value has no role to play to serve the content. You should see 200 response for contact request.

References:
[1]. ASP.NET Core Response Caching Sample
[2]. ResponseCache attribute sample
[3]: How to control web page caching, across all browsers?

Michael
  • 609
  • 5
  • 9
  • The Index action method returns View so what you say is might be true( i haven't tried yet). However my question was related to action method that returns data in JSON format. Like the one i posted in the question. – LP13 Jan 23 '17 at 18:34
  • The Content-Type doesn't matter if you're using the browser and you're in those specified situations when you get the cached response. Regarding Postman, if you installed it as a standalone app (downloading it from their website), you won't have the cache ability for your requests. But if you install it as an app into Google Chrome, you'll manage to get cached responses. I'll add the necessary info into the answer. – Michael Jan 25 '17 at 17:21
5

Long story short, using the ResponseCache attribute like the following is sufficient to get expiration-based client-side caching to work in a brand new, default dotnet core project (including async methods):

[HttpGet]
[ResponseCache(Duration = 120)]
public IEnumerable<StateProvinceLookupModel> GetStateProvinces()
{
    return _domain.GetStateProvinces();
}

This is working correctly in the screenshot above, as the Cache-Control: public,max-age=120 is visible there. In most cases, browsers won't send subsequent requests before the expiration (i.e. for the next 120 seconds or 2 minutes), but this is a decision of the browser (or other client).

If the request is sent regardless, you either have some middleware or server configuration overwriting your response headers, or your client ignores the caching directive. In the screenshot above, the client ignores caching, because the cache control header is there.

Common cases where the client cache is ignored and the request is sent:

  • Chrome prevents any kind of caching when using HTTPS without a certificate (or an invalid certificate, this is often common for local development, so make sure to use HTTP when testing your cache, or trust a self-signed cert)
  • Most browser dev tools disable caching by default when open, this can be disabled
    • Browsers usually send additional headers, Chrome sends Cache-Control: no-cache
  • Refreshing directly (i.e. Ctrl+F5) will instruct most browsers to not use a cache and make the request regardless of age
    • Browsers usually send additional headers, Chrome sends Cache-Control: max-age=0 (this is visible in your screenshot)
  • Postman sends the Cache-Control: no-cache header which makes it bypass the local cache, resulting in requests to be sent; you can disable it from the settings dialog, in which case requests will no longer be sent with the above client cache configuration

At this point we are beyond expiration-based client caching, and the server will receive the request in one way or another, and another layer of caching occurs: you may make the server respond with a 304 Not Modified code (which is then again up to the client to interpret in whatever way it wants) or use a server-side cache and respond with the full content. Or you may not use any subsequent caching and just perform the entire request processing again on the server.


Note: the ResponseCache attribute is not to be confused with services.AddResponseCaching() & app.UseResponseCaching() middleware in startup configuration, because that is for server-side caching (which by default uses an in-memory cache, when using the middleware). The middleware is not required for client-caching to work, the attribute by itself is enough.

John Weisz
  • 23,615
  • 9
  • 74
  • 118
-1

First of all I want to clarify few thing and I am sure that you already knew it.

  1. ResponseCache is not equal to OutputCache any way.

  2. ResponseCache is as per my thinking set header but it does not cache anything on server side.

Now If you want to Cache same as OutputCache then you might have to use preview release 1.1 that just release.

ASP.net core 1.1 preview release

https://blogs.msdn.microsoft.com/webdev/2016/10/25/announcing-asp-net-core-1-1-preview-1/

They introduce new Response Caching Middleware. Response Caching Middleware

Demo of it available here . https://github.com/aspnet/ResponseCaching/blob/dev/samples/ResponseCachingSample/Startup.cs

dotnetstep
  • 14,826
  • 4
  • 49
  • 61
  • i never said that i want to cache on server side like outputcache, In-fact i do not want to cache on server side, i want to cache data on client side. and thats what `ResponseCache` attribute supposed to do – LP13 Nov 02 '16 at 14:41