Reputation: 12854
I have a ViewPage that contains <% Html.RenderAction<MyController>(c => c.SidebarStats()); %>
. On the controller action for the action SidebarStats I have an OutputCache action filter to cache only that part of the page. However, the whole page is getting cached and not just that action.
I remember seeing somewhere that this might be a bug with ASP.NET MVC though I'm not sure. I'm currently using ASP.NET MVC RC1, IIS7, Windows Server 2008 and .NET 3.5 SP1.
Upvotes: 7
Views: 4429
Reputation: 14100
I'm now using what Steve Sanderson made in his blog and it's very nice:
public class ActionOutputCacheAttribute : ActionFilterAttribute
{
// This hack is optional; I'll explain it later in the blog post
private static readonly MethodInfo _switchWriterMethod = typeof (HttpResponse).GetMethod("SwitchWriter",
BindingFlags.Instance |
BindingFlags.NonPublic);
private readonly int _cacheDuration;
private string _cacheKey;
private TextWriter _originalWriter;
public ActionOutputCacheAttribute(int cacheDuration)
{
_cacheDuration = cacheDuration;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
_cacheKey = ComputeCacheKey(filterContext);
var cachedOutput = (string) filterContext.HttpContext.Cache[_cacheKey];
if (cachedOutput != null)
filterContext.Result = new ContentResult {Content = cachedOutput};
else
_originalWriter =
(TextWriter)
_switchWriterMethod.Invoke(HttpContext.Current.Response,
new object[] {new HtmlTextWriter(new StringWriter())});
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (_originalWriter != null) // Must complete the caching
{
var cacheWriter =
(HtmlTextWriter)
_switchWriterMethod.Invoke(HttpContext.Current.Response, new object[] {_originalWriter});
string textWritten = (cacheWriter.InnerWriter).ToString();
filterContext.HttpContext.Response.Write(textWritten);
filterContext.HttpContext.Cache.Add(_cacheKey, textWritten, null,
DateTime.Now.AddSeconds(_cacheDuration), Cache.NoSlidingExpiration,
CacheItemPriority.Normal, null);
}
}
private string ComputeCacheKey(ActionExecutingContext filterContext)
{
var keyBuilder = new StringBuilder();
foreach (var pair in filterContext.RouteData.Values)
keyBuilder.AppendFormat("rd{0}_{1}_", pair.Key.GetHashCode(), pair.Value.GetHashCode());
foreach (var pair in filterContext.ActionParameters)
keyBuilder.AppendFormat("ap{0}_{1}_", pair.Key.GetHashCode(), pair.Value.GetHashCode());
return keyBuilder.ToString();
}
}
Please visit Steve Sanderson blog's article for more information.
Upvotes: 0
Reputation: 59061
I blogged a solution to this problem here. It's simple, but it only works if you're using the WebFormViewEngine. We will look hard into figuring out what it will take to make this work for all view engines.
Upvotes: 10
Reputation: 12854
According to Microsoft this is a known bug with no known fix. Only workarounds suggested are to create your own OutputCache action filter.
Upvotes: 2