Search code examples
c#asp.net-mvcoutputcache

ChildActionOnly output cache not disabled


I have the following Action in a controller marked with [ChildActionOnly]:

[OutputCache(Duration = 3600)]
public PartialViewResult SideNavigation()
{
    SideNavigationModel model = _sideNavigationFactory.GetSideNavigation();

    if (model != null)
    {
        return PartialView(model);
    }

    return default(PartialViewResult);
}

Which works fine when I call it with:

@Html.Action("SideNavigation", "Template") 

In my main template. However I have noticed that when I update the cshtml file of the side navigation, it does not update on the webpage even though my output caching is disabled in the web.config:

<outputCache enableOutputCache="false">

If I change the main template this is on, that will update but the navigation part of the template won't. Is this expected behaviour? If so is there a way to output cache it only when output caching is enabled?


Solution

  • Thanks to a mixture of the this answer and the answer provided by Laurent, I have come up with the following solution using a custom attribute:

    public class ChildActionOutputCacheAttribute : OutputCacheAttribute
    {
        private const string _cachingSection = "system.web/caching/";
        private const string _outputCacheSection = "outputCache";
        private const string _profileSection = "outputCacheSettings";
        private bool _profileEnabled;
    
        public ChildActionOutputCacheAttribute(string cacheProfile)
        {
            // get output cache section of web config
            OutputCacheSection settings = (OutputCacheSection)WebConfigurationManager.GetSection($"{_cachingSection}{_outputCacheSection}");
    
            // check section exists and caching is enabled
            if (settings != null && settings.EnableOutputCache)
            {
                // if caching enabled, get profile
                OutputCacheSettingsSection profileSettings = (OutputCacheSettingsSection)WebConfigurationManager.GetSection($"{_cachingSection}{_profileSection}");
                OutputCacheProfile profile = profileSettings.OutputCacheProfiles[cacheProfile];
    
                if (profile != null && profile.Enabled)
                {
                    // if profile exits set profile params
                    Duration = profile.Duration;
                    VaryByParam = profile.VaryByParam;
                    VaryByCustom = profile.VaryByCustom;
    
                    _profileEnabled = true;           // set profile enable to true as output cache is turned on and there is a profile
                }
            }
        }
    
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (_profileEnabled)
            {
                // only run this if caching has been set and is enabled
                base.OnActionExecuting(filterContext);
            }
        }
    }
    

    This can then been added to the child action controller using the following:

    [ChildActionOutputCache(CacheProfile.Long)]
    

    If you have the following sections in your web.config:

    <system.web>
      <caching>
        <outputCache enableOutputCache="false"></outputCache>
        <outputCacheSettings>
          <outputCacheProfiles>
            <add name="Long" duration="86400" varyByParam="*" varyByHeader="none" location="Server" />
          </outputCacheProfiles>
        </outputCacheSettings>
      </caching>
    </system.web>