When we use the [OutputCache] attribute, content could be cached in three locations:
- Web server, any
- Proxy servers, and
- Web browser.
We can control exactly where content is cached by modifying the Location property of the [OutputCache] attribute. The Location property can be set to any one of the following values,
- Any
- Client
- Downstream
- Server
- None
- ServerAndClient
By default, the Location property has the value
Any. However, there are situations in which one might want to cache only on the browser or only on the server. For example, if you are caching information that is personalized for each user then you should not cache the information on the server. If you are displaying different information to different users then you should cache the information only on the client.
Add code below into the OutputCacheController,
- [OutputCache(Duration = 3600, VaryByParam = "none")]
- public string GetName()
- {
- return "Hi " + User.Identity.Name();
- }
-
- [OutputCache(Duration = 3600, VaryByParam = "none", Location = OutputCacheLocation.Client, NoStore = true)]
- public string GetName1()
- {
- return "Hi " + User.Identity.Name();
- }
The output of the GetName() action is cached with no locaiton (location by default: Any), while GetName1() action is cached with location at Client. Notice that the [OutputCache] attribute in GetName1() action also includes a NoStore property. The NoStore property is used to inform proxy servers and browser that they should not store a permanent copy of the cached content.
Update the code in Views/home/index.chtml:
- @{
- ViewBag.Title = "Home Page";
- }
-
-
- <div class="row">
- <div class="col-md-4">
- <h2>Time Cached</h2>
- <li>@Html.ActionLink("No Cache", "NoCache", "OutputCache")</li>
- <li>@Html.ActionLink("Outpu Cache: duration = 10 senc", "Index", "OutputCache")</li>
- </div>
- <div class="col-md-4">
- <h2>Client Side Cache</h2>
- <li>@Html.ActionLink("Get Name | Server Cache", "GetName", "OutputCache")</li>
- <li>@Html.ActionLink("Get Name | Client (Browser)Cache", "GetName1", "OutputCache")</li>
- </div>
-
- </div>
Register at least one user such as:
If we logout, click these two links again, then we will see, the one, that the content is cached on the client browser and not on the server, will get the correct name, i.e.
While another one, that the content by default is cached on the server, will get the same name for both login or log out situations as "Hi,
[email protected]", which is the result of the first request, but not correct for the second request, the log out situation.
Varying the Output Cache: VaryByParam
In some situations, one might want different cached versions of the very same content. Imagine, for example, that you are creating a master/detail page. The master page displays a list of movie titles. When you click a title, you get details for the selected movie.
If you cache the details page, then the details for the same movie will be displayed no matter which movie you click. The first movie selected by the first user will be displayed to all future users.
You can fix this problem by taking advantage of the VaryByParam property of the [OutputCache] attribute. This property enables you to create different cached versions of the very same content when a form parameter or query string parameter varies.
Examine our MoviesController created from the PreSetup app, the action named Index() is the Master and the action Details(int? id) is the Detail. The Master action returns a list of movie titles and the Details(int? id) action returns the details for the selected movie.
We add a VaryByParam property with the value "none" to both Master action, Index(), and Details action, Details(int? id).
- // GET: Movies
- [OutputCache(Duration = int.MaxValue, VaryByParam = "none")]
- public ActionResult Index()
- {
- return View(db.Movies.ToList());
- }
-
- // GET: Movies/Details/5
- [OutputCache(Duration = int.MaxValue, VaryByParam = "none")]
- public ActionResult Details(int? id)
- {
- if (id == null)
- {
- return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
- }
- Movie movie = db.Movies.Find(id);
- if (movie == null)
- {
- return HttpNotFound();
- }
- return View(movie);
- }
When the Master action is invoked, the same cached version of the Master view is returned. Any form parameters or query string parameters are ignored. If you refresh the browser, it will not make a request from the server to execute the code to get a new version of data, instead to use the server chached version. If you add a debug point in the code, you will see exactly what the process is doing.
The Details() action also includes a VaryByParam property with the value "none" in our code now. We expected that the behavior is the same as the Master action that the same cached version of the detailed view is returned for any different parameters. However, it is not, for exampe, when id = 1 and id = 2, you got two different versions:
Exame the link, we found out that those are two different addresses, one is
- https://localhost:44374/Movies/Details/1, another is
- https://localhost:44374/Movies/Details/2,
instead of one address with two different parameters. Therefore, they must have an independent version cached by themselves.
Now, if we change the address like this
- https://localhost:44374/Movies/Details?id=1, and
- https://localhost:44374/Movies/Details?id=2,
then we will get the same cached version: the one that the first time be requested.
For example, we choose the parameter id = 3 the first time; if we change the id, and refresh the browser, we will get exactly the same version as the case: id = 3.
Now, we modify the VaryByParam property with the value "Id" for the detias action. When different values of the Id parameter are passed to the controller action, different cached versions of the Details view are generated.
- // GET: Movies
- [OutputCache(Duration = int.MaxValue, VaryByParam = "none")]
- public ActionResult Index()
- {
- return View(db.Movies.ToList());
- }
-
- // GET: Movies/Details/5
- [OutputCache(Duration = int.MaxValue, VaryByParam = "id")]
- public ActionResult Details(int? id)
- {
- if (id == null)
- {
- return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
- }
- Movie movie = db.Movies.Find(id);
- if (movie == null)
- {
- return HttpNotFound();
- }
- return View(movie);
- }
It is important to understand that using the VaryByParam property results in more caching and not less for one specific caching (with one address). A different cached version of the Details view is created for each different version of the Id parameter.
Finally, one can set the VaryByParam property to the following values,
* = Create a different cached version whenever a form or query string parameter varies.
none = Never create different cached versions
Semicolon list of parameters = Create different cached versions whenever any of the form or query string parameters in the list varies