asp.net-mvccachingoutputcachemvcsitemapprovidersecurity-trimming

MVCSiteMapProvider: Using security trimming with ouput cache returns empty sitemap


I am using the MvcSiteMapProvider Html Helper to create a navbar. The content of the navbar depends on the visitor rights therefore I am using security trimming to only display content which the person is authorized for. For performance improvement I am trying to cache this navbar.

The navbar is created in a partial view with the following content:

@Html.MvcSiteMap().Menu("MenuHelper", new { name = "MainMenu" })

Inside the layout file it is called by an action method which returns the partial view:

[System.Web.Mvc.OutputCache(Duration = 10, VaryByCustom = "User")]
[ChildActionOnly]
public ActionResult MainMenu()
{
    return PartialView("MainMenu");
}

The caching of works fine at the root page of the sitemap. However when the cache duration runs out and the action method is called from deeper levels, no sitemap is returned. When I disable security trimming or the output caching it works perfectly fine at all levels.

Is it possible that action method which returns the navbar, is called when the authorization data is unavailable and therefore returns a corrupt sitemap?


Solution

  • If you analyze the source for AuthorizeAttribute, you will note that it is not designed to work with child actions that are output cached (they go to some great lengths to ensure that child actions that are output cached will throw an exception).

    Of course, it also won't work right if you have a custom AuthorizeAttribute that overrides OnAuthorization that does not duplicate this important logic.

    However, there are a couple of things you can do to improve performance when using Security Trimming:

    1. Make sure that your injection constructors are simple, especially on your controllers. If you have heavy processing in your constructors, it can really slow things down (with or without MvcSiteMapProvider, but Security Trimming makes this much more apparent).
    2. If that doesn't improve things enough and you are not using a custom AuthorizeAttribute, you could use the roles attribute/property to duplicate your role logic into the SiteMap and remove the AuthorizeAttributeAclModule from your configuration (external DI only).

    See this discussion for more details.