Question

MVC 3 RTM. I have an action that returns a file (image/jpeg). I am trying to set the ETag for a file with no success (the etag doesn't come through on header). I have tried both Response.Cache.SetETag and Response.AppenderHeader. If I add my own custom header tag, it works as expected, it just seems to be ETag that I can't set.

Here is the source.

        [HttpGet, OutputCache(Location= OutputCacheLocation.Client, VaryByParam="userId", Duration=3600, NoStore=true)]
        public ActionResult GetImage(string userId)
        {
            byte[] result;

            using (var client = new WebClient())
            {
                client.Credentials = CredentialCache.DefaultCredentials; 
                result = client.DownloadData(string.Format(IntranetUrl, userId));
            }

            Response.Cache.SetETag("00amyWGct0y_ze4lIsj2Mw");
            //or Response.AppendHeader("ETag", "00amyWGct0y_ze4lIsj2Mw");
            Response.AppendHeader("MyHeader", "HelloWorld");

            return File(result, "image/jpeg");
        }

And here is the resource request/response:

> Request
> URL:http://localhost/MyApp/Employee.mvc/GetImage?userId=myUserId
> Request Method:GET Status Code:200 OK
> Request Headers Accept:*/*
> Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
> Accept-Encoding:gzip,deflate,sdch
> Accept-Language:en-US,en;q=0.8
> Cache-Control:max-age=0
> Connection:keep-alive
> Cookie:ASP.NET_SessionId=mySessionId
> Host:localhost
> Referer:http://localhost/MyApp/Employee/Review/24/Index
> User-Agent:Mozilla/5.0 (Windows; U;
> Windows NT 5.1; en-US)
> AppleWebKit/534.13 (KHTML, like Gecko)
> Chrome/9.0.597.98 Safari/534.13 Query
> String Parameters userId:myUserId
> Response Headers
> Cache-Control:private, no-store,
> max-age=3600 Content-Length:1428
> Content-Type:image/jpeg Date:Thu, 17
> Feb 2011 15:45:30 GMT Expires:Thu, 17
> Feb 2011 16:45:29 GMT
> Last-Modified:Thu, 17 Feb 2011
> 15:45:29 GMT MyHeader:HelloWorld
> Server:Microsoft-IIS/5.1
> X-AspNet-Version:4.0.30319
> X-AspNetMvc-Version:3.0
> X-Powered-By:ASP.NET

Update

I've stripped all the code down to this and still no go...

Action:

public FileETagActionResult GetImage()
{
    return new FileETagActionResult();
}

ActionResult:

    public class FileETagActionResult : ActionResult
    {

        public override void ExecuteResult(ControllerContext context)
        {

            byte[] result;

            using (var client = new WebClient())
            {
                result = client.DownloadData("http://myintranet/images/logo.png");
            }

            var hash = MD5.Create().ComputeHash(result);
            string etag = String.Format("\"{0}\"", Convert.ToBase64String(hash));

            TimeSpan expireTs = TimeSpan.FromDays(5);

            context.HttpContext.Response.Cache.SetCacheability(HttpCacheability.Private);
            context.HttpContext.Response.Cache.SetETag(etag);
            context.HttpContext.Response.Cache.SetExpires(DateTime.Now.AddDays(5));
            context.HttpContext.Response.Cache.SetMaxAge(expireTs);

            context.HttpContext.Response.ContentType = "image/png";
            context.HttpContext.Response.BinaryWrite(result);


        }
    }
Was it helpful?

Solution

The ETag will be suppressed if you use HttpCacheability.Private.

You can find more information on this question

If you change it to HttpCacheability.ServerAndPrivate it should work

OTHER TIPS

BZ,

try doing this stuff in the ExcecuteResult override as it's too late by the time the ActionResult is being thrown back (an example from a project that i quickly opened, edit to suit):

public override void ExecuteResult(ControllerContext context)
{
    var textWriter = new StringWriter();
    var viewResult = GetViewResult(textWriter);
    viewResult.ExecuteResult(context);

    var result = textWriter.ToString()
        .RegexReplace("<script.*?>", string.Empty)
        .Replace("</script>", string.Empty);

    //#if RELEASE
    //context.HttpContext.Response.CacheControl = "Public";
    //context.HttpContext.Response.Expires = CacheDuration;
    string version = "1.0"; //your dynamic version number
    HttpCachePolicyBase cache = context.HttpContext.Response.Cache;
    TimeSpan expireTs = TimeSpan.FromDays(CacheDuration);
    cache.SetCacheability(HttpCacheability.Private);
    cache.SetETag(version);
    cache.SetExpires(DateTime.Now.Add(expireTs));
    cache.SetMaxAge(expireTs);
   //#endif

    context.HttpContext.Response.ContentType = "text/javascript";
    context.HttpContext.Response.Write(result);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top