Background
When i enhance the dotnetage runtime preformance with OutputCache i have found the OutputCacheAttribute seems to be not work for FileResult. At last i had to use “Last-Modified” and “ETag” http header to implatment the file cache feature for MVC.
Base concepts
What is Last-Modified
When a visitor browses your website, his/her browser caches your images, html, style sheet and other files locally for better performance. If you have the so-called "Last-Modified" header set in your pages, next time when the same visitor loads your website, the server will check whether there is a change in the files since the last time they have been accessed.
If there is no change, the server will send a "304 Not Modified" reply to the browser and the information will be loaded from the local cache. If you do not update your website very often, using "Last-modified" headers can significantly increase its loading speed.
If your website is using plain HTML files, the "Last-Modified" is just the time stamp of the HTML file. If you have, however, dynamic pages that fetch data from a database for example, things are a bit more complex. The server does not know how you are generating your data or how the data can be changed from the last time it was loaded.
What is ETag
Entity tags (ETags) are a mechanism that web servers and browsers use to determine whether the component in the browser's cache matches the one on the origin server. (An "entity" is another word a "component": images, scripts, stylesheets, etc.) ETags were added to provide a mechanism for validating entities that is more flexible than the last-modified date. An ETag is a string that uniquely identifies a specific version of a component. The only format constraints are that the string be quoted. The origin server specifies the component's ETag using the ETag
response header.
HTTP/1.1 200 OK Last-Modified:Tue, 29 Mar 2011 16:08:30 GMT ETag: "s3BsVvsMdH/IZg8XrO5NchhW2qhc2ROQMQ7a1rg990c=" Content-Length: 12195
Later, if the browser has to validate a component, it uses the If-None-Match
header to pass the ETag back to the origin server. If the ETags match, a 304 status code is returned reducing the response by 12195 bytes for this example.
GET /webshared/home/images/img_websitespark_banner.jpg HTTP/1.1 Host: dotnetage.com If-Modified-Since: Tue, 29 Mar 2011 16:08:30 GMT If-None-Match: "s3BsVvsMdH/IZg8XrO5NchhW2qhc2ROQMQ7a1rg990c=" HTTP/1.1 304 Not Modified
How to use Last-Modified and ETag to enhance file preforment
best way to extend the file cache in Mvc maybe use ActionFilter, so i create a FileCacheAttribute inhert from ActionFilter to add the “Last-Modified” and “ETag” header to http response.
1:// Copyright (c) 2011 Ray Liang (https://dotnetage.com)
2:// Dual licensed under the MIT and GPL licenses:
3:/span>// http://www.opensource.org/licenses/mit-license.php
4:// http://www.gnu.org/licenses/gpl.html
5:using System;
6:using System.Collections.Generic;
7:using System.Linq;
8:using System.Web;
9:using System.Web.Mvc;
10:
11:namespace DNA.Mvc
12:{
13: [AttributeUsage(AttributeTargets.Class |
14: AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
15: public class FileCacheAttribute : ActionFilterAttribute
16: {
17: private int duration = 300;
18:
19: public int Duration
20: {
21: get { return duration; }
22: set { duration = value; }
23: }
24:
25: public override void OnActionExecuting(ActionExecutingContext filterContext)
26: {
27: var request = filterContext.RequestContext.HttpContext.Request;
28: var response = filterContext.RequestContext.HttpContext.Response;
29: if (request.Headers["If-Modified-Since"] != null &&
30:TimeSpan.FromTicks(DateTime.Now.Ticks - DateTime.Parse(request.Headers["If-Modified-Since"]).Ticks).Seconds < Duration)
31: {
32: response.Write(DateTime.Now);
33: response.StatusCode = 304;
34: response.Headers.Add("Content-Encoding", "gzip");
35: response.StatusDescription = "Not Modified";
36: }
37: else
38: {
39: base.OnActionExecuting(filterContext);
40: }
41: }
42:
43: private void SetFileCaching(HttpResponseBase response, string fileName)
44: {
45: response.AddFileDependency(fileName);
46: response.Cache.SetETagFromFileDependencies();
47: response.Cache.SetLastModifiedFromFileDependencies();
48: response.Cache.SetCacheability(HttpCacheability.Public);
49: response.Cache.SetMaxAge(new TimeSpan(7, 0, 0, 0));
50: response.Cache.SetSlidingExpiration(true);
51: }
52:
53: public override void OnActionExecuted(ActionExecutedContext filterContext)
54: {
55: var result = filterContext.Result as FilePathResult;
56: if (result != null)
57: {
58: if (!string.IsNullOrEmpty(result.FileName) && (System.IO.File.Exists(result.FileName)))
59: SetFileCaching(filterContext.HttpContext.Response, result.FileName);
60: }
61: base.OnActionExecuted(filterContext);
62: }
63: }
64:}
use the filecacheattribute in action:
1:[HttpGet,FileCache(duration=3600)]
2: public FileResult Getfile()
3:{
4: return File(Server.MapPath("text.jpg"));
5:}
now the fileresult can be support the cache feature.
-
-
Letture(3558)
-
Permalink