Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OutputCache with VaryByCustom not working

I'm trying to implement caching in ASP.NET MVC 4 using the OutputCache attribute.

Here is my controller action:

[HttpGet]
[OutputCache(Duration = CACHE_DURATION, VaryByCustom = "$LanguageCode;myParam", Location = OutputCacheLocation.Server)]
public JsonResult MyAction(string myParam)
{
    // this is called also if should be cached!
}

And here is the GetVaryByCustomString in the Global.asax:

public override string GetVaryByCustomString(HttpContext context, string arg)
{
    var pars = arg.Split(';');
    if (pars.Length == 0) return string.Empty;

    var res = new System.Text.StringBuilder();
    foreach (var s in pars)
    {
        switch (s)
        {
            case "$LanguageCode":
                var culture = CultureManager.GetCurrentCulture();
                res.Append(culture.Name);
                break;
            default:
                var par = context.Request[s];
                if (par != null)
                    res.AppendFormat(par);
                break;
        }
    }
    return base.GetVaryByCustomString(context, res.ToString());
}

This method is always called and returns the right value (e.g. "it123").

If I call the action with the only myParam parameter, the cache works correctly.

http://localhost:1592/MyController/MyAction?myParam=123 // called multiple times always read from cache

The problem is that when I call the action with another parameter, not included in the VaryByCustom string, the controller action is called anyway, also if is should be cached and the GetVaryByCustomString returns the same result.

http://localhost:1592/MyController/MyAction?myParam=123&dummy=asdf // called multiple times with different 'dummy' values always calls the action

Any idea?

like image 830
Flea777 Avatar asked Apr 10 '14 15:04

Flea777


1 Answers

First you have to change your [OutputCache] to include VaryByParam="":

[OutputCache(Duration = CACHE_DURATION, VaryByCustom = "$LanguageCode;myParam", VaryByParam = "", Location = OutputCacheLocation.Server)]

Becuase by default its value is "*" (All).

Then in your GetVaryByCustomString() method, try to return your generated string instead of calling the base method:

return res.ToString();

Here's the source code of the base.GetVaryByCustomString() method:

public virtual string GetVaryByCustomString(HttpContext context, string custom) {

        if (StringUtil.EqualsIgnoreCase(custom, "browser")) {
            return context.Request.Browser.Type;
        }

        return null;
    }

As you can see, it doesn't do what you think it does, it only compares the Browser type with the string you provided and if there's no match it returns null, not the string you provided.

(I suspect the [OutputCache] change alone will suffice, but try changing the method as well)

like image 86
haim770 Avatar answered Oct 08 '22 22:10

haim770