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/My开发者_如何转开发App/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);
}
}
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
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);
}
精彩评论