Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Output Caching using BOTH varybyparam and varybycustom

I'm trying to do something which should be very simple...I have a site with a dropdown from which the user selects a group. Thereafter, the user navigates through the site using querystring arguments from menus. So I want the caching to be dependent on the querystring - this seems to work. I also want the cache to be dependent on the group that they selected.

But when the querystring is empty, neither cache element seems to work - the page is just whatever the version was for the last selected group. My cache directive looks like this:

<%@ OutputCache Duration="300" VaryByCustom="currentAtomId" VaryByParam="documentId;folderId;sectionId;renderMode;typeId" %>

My varyByCustom code looks like this:

public override string GetVaryByCustomString(HttpContext context, string custom)
{
    switch (custom)
    {
        case "currentAtomId":
            var currentAtomId = SecurityManifold.Create().CurrentAtomId;

            var returnString = currentAtomId == null ? Guid.NewGuid().ToString() : currentAtomId.ToString();

            return returnString;

        default:
            throw new ArgumentException(string.Format("Argument '{0}' is not a valid cache argument.", custom));
    }
}

The call to CurrentAtomId boils down to this:

public static int? GetCurrentAtomIdFromContext(HttpContext context)
{
    int entityId;

    if (context.Session == null)
    {
        throw new InvalidOperationException("Session is null");
    }

    var sessionEntityId = context.Session["CurrentEntityId"];

    if (sessionEntityId == null || string.IsNullOrEmpty(sessionEntityId.ToString()))
    {
        return null;
    }

    if (!int.TryParse(sessionEntityId.ToString(), out entityId))
    {
        return null;
    }

    return entityId;
}

Finally, the code which specifies the CurrentEntityId is this:

    var selectedEntityId = this.lstSecurityEntities.SelectedValue;

    if (string.IsNullOrEmpty(selectedEntityId))
    {
        return;
    }

    Session["CurrentEntityId"] = selectedEntityId;

    var possibleQueryString = Request.QueryString.ToString();

    if (!string.IsNullOrEmpty(possibleQueryString))
    {
        possibleQueryString = "?" + possibleQueryString;
    }

    Response.Redirect("default.aspx" + possibleQueryString);

I'm baffled. Any thoughts would be appreciated.

like image 901
Chris B. Behrens Avatar asked Jul 21 '11 18:07

Chris B. Behrens


People also ask

What is output caching?

Output caching stores the generated output of pages, controls, and HTTP responses in memory. Output caching enables you to cache different versions of content depending on the query string and on form-post parameters to a page, on browser type, or on the language of the user.

What is the difference between page output caching and application data caching?

Output Caching : Output cache stores a copy of the finally rendered HTML pages or part of pages sent to the client. When the next client requests for this page, instead of regenerating the page, a cached copy of the page is sent, thus saving time. Data Caching : Data caching means caching data from a data source.

What is the difference between output cache and ASP.NET data cache?

ASP.NET supports caching of data as well web pages. Applications Data caching enables caching of data whereas Page Output Caching enables Web pages.

How does output cache work?

The output cache enables you to cache the content returned by a controller action. That way, the same content does not need to be generated each and every time the same controller action is invoked. Imagine, for example, that your ASP.NET MVC application displays a list of database records in a view named Index.


1 Answers

I eventually determined the problem - when output caching is placed at a PAGE level (as opposed to a control level), the session is not available, and throws an exception. Because this exception is occurring in Global ABOVE the global error handler, it fails silently. I eventually figured this out by wrapping a try-catch block around the cache key generation code in VaryByCustomString and Response.Write-ing it out.

What a beatdown...at any rate, the solution is to implement caching at the control level, which unfortunately is a lot more work because the pieces of the page work together...but it's better than no caching. I hope this helps save somebody else some time.

Bottom Line: for varyByCustomString in global.asax - SESSION IS NOT AVAILABLE WHEN CACHING AT THE PAGE LEVEL.

like image 113
Chris B. Behrens Avatar answered Nov 15 '22 03:11

Chris B. Behrens