user1751825
user1751825

Reputation: 4309

MVC 5: PartialViewResult action cache never changes with VaryByParam:="*"

I'm having issues with OutputCache for a partial view action. My index action controller is defined like so...

<OutputCache(Duration:=3600, VaryByParam:="*")>      
<Route("")>
<HttpGet>
Public Function Index(value As MySearchFilter) As ActionResult
    ViewData("Title") = "Search Jobs"
    Return View("Index", value)
End Function

and I have a PartialViewResult action defined like so...

<OutputCache(Duration:=3600, VaryByParam:="*")>
<Route("search")>
<HttpGet>
Public Function Search(value As MySearchFilter) As PartialViewResult
    Return PartialView("_List", Search(value))
End Function

In my Index view (vbhtml), I call the partial action like so...

@Html.Action("Search")

This works fine without caching. I can see that the "Search" action is getting the correct filter object passed to it etc.

The issue I'm having is that with caching enabled, VaryByParam:="*" seems to be ignored. The result never changes, even when the querystring params change. When I debug, I can see that the action is only called the first time, and never after that.

The main "Index" action works correctly, and any change to the parameters correctly caches different content.

I know I could just use caching on the index action, and turn it off for the "Search" action, but I have a number of other partial views, and I'd like to be able to control the caching independently for each.

Note: I'm not trying to customise the cache by RouteData.Values, I'm trying to customise it by Querystring parameters, which is supposed to be exactly what VaryByParam does. In the debugger I can see that the Request.QueryString is available to controller action. I'm completely stumped, I can't understand why it's not working.

Upvotes: 1

Views: 291

Answers (1)

user1751825
user1751825

Reputation: 4309

I found the solution partly from Partial Page Caching and VaryByParam in ASP.NET MVC 3

Apparently for child controller actions, it doesn't use the URL, or form parameters, but rather the controller method parameters. To determine if they've changed, it calls .ToString() on each parameter. For simple types, this is fine, but for a complex object, you must override .ToString(), otherwise it's never going to change. It'll just return the name of the class.

Just in case it's useful. This is my ToString method, which is defined in a base class which all my view models inherit...

Public Overrides Function ToString() As String
    Return JsonConvert.SerializeObject(Me)
End Function

This seems to be a fairly neat/reliable way to ensure that any change to any property correctly changes the cache.

Upvotes: 0

Related Questions