ASP.NET MVC: Problem with OutputCache
Asked Answered
E

3

16

for my current project it's necessary to generate dynamic CSS...

So, i have a partial view which serves as a CSS deliverer... The controller code looks like this:

    [OutputCache(CacheProfile = "DetailsCSS")]
    public ActionResult DetailsCSS(string version, string id)
    {
        // Do something with the version and id here.... bla bla
        Response.ContentType = "text/css";
        return PartialView("_css");
    }

The output cache profile looks like:

<add name="DetailsCSS" duration="360" varyByParam="*" location="Server" varyByContentEncoding="none" varyByHeader="none" />

The problem is: When i use the OutputCache line ([OutputCache(CacheProfile = "DetailsCSS")]), the response is of content type "text/html", instead of "text/css"... when i remove it, it works as expected...

So, for me it seems that the OutputCache doesn't save my "ContentType" setting here... is there any way around this?

Thanks

Enrol answered 18/11, 2009 at 11:16 Comment(0)
M
20

You could overwrite the ContentType with your own ActionFilter that executes after the cache has occurred.

public class CustomContentTypeAttribute : ActionFilterAttribute
{
    public string ContentType { get; set; }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        filterContext.HttpContext.Response.ContentType = ContentType;
    }
}

And then call that attribute after the OutputCache.

[CustomContentType(ContentType = "text/css", Order = 2)]
[OutputCache(CacheProfile = "DetailsCSS")]
public ActionResult DetailsCSS(string version, string id)
{
    // Do something with the version and id here.... bla bla
    return PartialView("_css");
}

Or (and I haven't tried this) but override the "OutputCacheAttribute" class with a CSS specific implementation. Something like this...

public class CSSOutputCache : OutputCacheAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        base.OnResultExecuting(filterContext);
        filterContext.HttpContext.Response.ContentType = "text/css";
    }
}

and this...

[CSSOutputCache(CacheProfile = "DetailsCSS")]
public ActionResult DetailsCSS(string version, string id)
{
    // Do something with the version and id here.... bla bla
    return PartialView("_css");
}
Medawar answered 18/11, 2009 at 20:28 Comment(1)
I would prefer the CSSOutputCacheAttribute version (note, your example is missing the Attribute at the end of the class name). I've tested it, it works, and it's nice to look at :).Prissy
A
12

This could be a bug in ASP.NET MVC. Internally they have a type called OutputCachedPage that derives from Page. When OnResultExecuting is called on OutputCacheAttribute they create an instance of this type and call ProcessRequest(HttpContext.Current), which eventually calls SetIntrinsics(HttpContext context, bool allowAsync) that sets the ContentType like this:

HttpCapabilitiesBase browser = this._request.Browser;
this._response.ContentType = browser.PreferredRenderingMime;

Here's a fix:

public sealed class CacheAttribute : OutputCacheAttribute {

   public override void OnResultExecuting(ResultExecutingContext filterContext) {

      string contentType = null;
      bool notChildAction = !filterContext.IsChildAction;

      if (notChildAction) 
         contentType = filterContext.HttpContext.Response.ContentType;

      base.OnResultExecuting(filterContext);

      if (notChildAction)
         filterContext.HttpContext.Response.ContentType = contentType;
   }
}
Antetype answered 18/11, 2009 at 19:7 Comment(1)
What is the significance of the filterContext.IsChildAction check?Sulfurous
E
-1

Try setting the VaryByContentEncoding as well as VaryByParam.

Eruct answered 18/11, 2009 at 12:49 Comment(1)
Oops. Yeah, that wouldn't work. ContentType != ContentEncoding!! Sorry, my bad.Eruct

© 2022 - 2024 — McMap. All rights reserved.