2009-03-02 23 views
13

Como usted puede saber que tenemos un nuevo ActionResult llamada FileResult en la versión RC1 de ASP.NET MVC.304 de estado con FileResult en ASP.NET MVC RC1

Utilizando eso, sus métodos de acción pueden devolver la imagen al navegador de forma dinámica. Algo como esto:

public ActionResult DisplayPhoto(int id) 
{ 
    Photo photo = GetPhotoFromDatabase(id); 
    return File(photo.Content, photo.ContentType); 
} 

En el código HTML, podemos usar algo como esto:

<img src="http://mysite.com/controller/DisplayPhoto/657"> 

Dado que la imagen se devuelve de forma dinámica, necesitamos una manera de almacenar en caché la corriente vuelto de modo que don No es necesario volver a leer la imagen desde la base de datos. Creo que podemos hacerlo con algo como esto, no estoy seguro:

Response.StatusCode = 304; 

Esto indica al navegador que ya tiene la imagen en la memoria caché. Simplemente no sé qué devolver en mi método de acción después de configurar StatusCode en 304. ¿Debo devolver null o algo así?

Respuesta

8

No utilice 304 con FileResult. De the spec:

La respuesta 304 no debe contener un mensaje de cuerpo , y por lo tanto es siempre terminado por la primera línea vacía después de los campos de cabecera.

No está claro lo que intenta hacer a partir de su pregunta. El servidor no sabe qué tiene el navegador en su caché. El navegador decide eso. Si intenta decirle al navegador que no vuelva a buscar la imagen cuando sea necesario nuevamente si ya tiene una copia, configure la respuesta Cache-Control header.

Si necesita devolver 304, use EmptyResult en su lugar.

+0

En la primera solicitud, que establezca la propiedad ETag como esto: HttpContext.Current.Response.Cache.SetETag (someUniqueValue); En solicitudes posteriores, al leer ETag sé que la imagen está en el caché del navegador y, por lo tanto, tengo que devolver 304 – Meysam

+0

Usar EmptyResult, no FileResult al devolver 304. –

25

Este blog respondió la pregunta por mí; http://weblogs.asp.net/jeff/archive/2009/07/01/304-your-images-from-a-database.aspx

Básicamente, debe leer el encabezado de la solicitud, comparar las últimas fechas modificadas y devolver 304 si coinciden, de lo contrario devolver la imagen (con un estado de 200) y establecer los encabezados de la caché de forma adecuada.

Código fragmento del blog:

public ActionResult Image(int id) 
{ 
    var image = _imageRepository.Get(id); 
    if (image == null) 
     throw new HttpException(404, "Image not found"); 
    if (!String.IsNullOrEmpty(Request.Headers["If-Modified-Since"])) 
    { 
     CultureInfo provider = CultureInfo.InvariantCulture; 
     var lastMod = DateTime.ParseExact(Request.Headers["If-Modified-Since"], "r", provider).ToLocalTime(); 
     if (lastMod == image.TimeStamp.AddMilliseconds(-image.TimeStamp.Millisecond)) 
     { 
      Response.StatusCode = 304; 
      Response.StatusDescription = "Not Modified"; 
      return Content(String.Empty); 
     } 
    } 
    var stream = new MemoryStream(image.GetImage()); 
    Response.Cache.SetCacheability(HttpCacheability.Public); 
    Response.Cache.SetLastModified(image.TimeStamp); 
    return File(stream, image.MimeType); 
} 
+0

Impresionante, ¡esto es perfecto! Sin embargo, lo cambié para no hacer 'ToLocalTime()' porque ya guardo la fecha de caché en UTC. También 'devuelve un nuevo EmptyResult()'. Recuerde también hacer 'var adjustedTime = DateTime.SpecifyKind (image.TimeStamp, DateKind.Utc)' si almacena las fechas UTC según la publicación del blog citada. – kamranicus

+0

Me encanta, esto es realmente útil –

+0

cuando estoy usando así y si la imagen cambia, todavía toma de la memoria caché del navegador y no está golpeando el servidor para comprobar. Alguna idea sobre eso? Por favor –

0

En las versiones más recientes del MVC que sería mejor devolver un HttpStatusCodeResult. De esta forma, no es necesario que configure Response.StatusCode ni se meta con nada más.

public ActionResult DisplayPhoto(int id) 
{ 
    //Your code to check your cache and get the image goes here 
    //... 
    if (isChanged) 
    { 
     return File(photo.Content, photo.ContentType); 
    } 
    return new HttpStatusCodeResult(HttpStatusCode.NotModified); 
} 
Cuestiones relacionadas