19

I'm attempting to use the new partial page caching available in ASP.NET MVC 3. In my view, I'm using:

<% Html.RenderAction("RenderContent", Model); %>

Which calls the controller method:

[Authorize]
[OutputCache(Duration = 6000, VaryByParam = "*", VaryByCustom = "browser")]
public ActionResult RenderContent(Content content)
{
   return PartialView(content);
}

Note that both the original view and the partial view are using the same view model.

The problem is that VaryByParam doesn't work - RenderContent() always returns the same cached HTML no matter what view model is passed to it. Is there something about VaryByParam that I don't understand?

James Sulak
  • 31,389
  • 11
  • 53
  • 57
  • How is the calling action method decorated, cache-wise? Also, VaryByParam has nothing to do with the Model passed to the action method - it has to do with the parameters (query string, form, etc) sent by the browser - *to the calling action method*, in this case. – bzlm Feb 28 '11 at 16:44
  • No caching is specified on the calling action method. – James Sulak Feb 28 '11 at 16:44
  • @bzlm, partial page caching *does* have to do with input parameters, and not with querystring/form fields. See http://weblogs.asp.net/scottgu/archive/2010/12/10/announcing-asp-net-mvc-3-release-candidate-2.aspx, section Output Caching Improvements. – Carvellis Feb 28 '11 at 16:50
  • @Jappie You're right. Good stuff! Technically though, "automatically varies the output cached entries when you have explicit parameters on your action method" is true even for ASP.NET MVC 1 for normal actions using GET. (Still have to `VaryByParam` there though.) – bzlm Feb 28 '11 at 22:21

1 Answers1

27

I think I figured it out. It looks like the issue is that VaryByParam, when the input parameter is an object, uses ToString() on that object to determine it's uniqueness. So this leaves two options:

  1. Overriding ToString() to provide a unique identifier.
  2. Passing a unique identifier as an additional parameter:

    <% Html.RenderAction("RenderContent", Model, Model.Id); %>
    
    [Authorize]
    [OutputCache(Duration = 6000, VaryByParam = "id", VaryByCustom = "browser")]
    public ActionResult RenderContent(Content content, string id)
    {
       return PartialView(content);
    }
    
James Sulak
  • 31,389
  • 11
  • 53
  • 57
  • 1
    Great answer, just what we needed. We used option 1. Using `return GetHashCode().ToString();` in the `public override string ToString()` to create a unique code for each object. This seem to work fine. – Tom Styles Sep 06 '11 at 13:00
  • Don't use ```GetHashCode().ToString()``` as a unique ID. Hash codes are _not_ designed to be unique, only unique-ish. – erikkallen Nov 28 '14 at 10:21