2009-03-02 5 views
13

Jak wiadomo mamy nową ActionResult nazwie FileResult w wersji RC1 ASP.NET MVC.Jak powrócić ze stanu 304 FileResult w ASP.NET MVC RC1

Dzięki tym metodom działania mogą dynamicznie zwracać obraz do przeglądarki. Coś takiego:

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

W kodzie HTML, możemy użyć czegoś takiego:

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

Ponieważ obraz jest zwracany dynamicznie, musimy znaleźć sposób buforowania zwrócony strumień tak, że don Trzeba ponownie odczytać obraz z bazy danych. Myślę, że możemy to zrobić z czymś takim, nie jestem pewien:

Response.StatusCode = 304; 

ta informuje przeglądarkę, że masz już obraz w swojej pamięci podręcznej. Po prostu nie wiem, co zwrócić w mojej metody działania po ustawieniu StatusCode na 304. Czy powinienem zwrócić wartość null lub coś podobnego?

Odpowiedz

8

Nie używaj 304 z FileResult. Od the spec:

Odpowiedź 304 NIE MUSI zawierać wiadomość-ciało, a więc jest zawsze rozwiązana przez pierwszą pustą linią po polach nagłówka.

Nie jest jasne, co próbujesz zrobić ze swojego pytania. Serwer nie wie, co przeglądarka ma w pamięci podręcznej. Przeglądarka decyduje o tym. Jeśli próbujesz poinformować przeglądarkę, aby ponownie nie pobierze obrazu, gdy będzie to potrzebne, jeśli ma już kopię, ustaw odpowiedź Cache-Control header.

Jeśli potrzebujesz zwrócić 304, użyj EmptyResult zamiast tego.

+0

W pierwszym wniosku, ustawić właściwość ETag takiego: HttpContext.Current.Response.Cache.SetETag (someUniqueValue); W kolejnych żądaniach, czytając ETag wiem, że obraz jest w pamięci podręcznej przeglądarki i dlatego muszę zwrócić 304 – Meysam

+0

Użyj EmptyResult, a nie FileResult po powrocie 304. –

25

Ten blog odpowiedział mi na to pytanie; http://weblogs.asp.net/jeff/archive/2009/07/01/304-your-images-from-a-database.aspx

Zasadniczo należy przeczytać nagłówek żądania, porównać daty ostatniej modyfikacji i zwrócić 304, jeśli pasują, w przeciwnym razie zwrócić obraz (ze statusem 200) i odpowiednio ustawić nagłówki pamięci podręcznej.

Fragment kodu z bloga:

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

Awesome, to jest idealne! Zmieniłem go jednak, aby nie wykonywał 'ToLocalTime()', ponieważ już przechowuję datę pamięci podręcznej w UTC. Zwracam również 'empty new EmptyResult()'. Pamiętaj też o tym, że 'var adjustTime = DateTime.SpecifyKind (image.TimeStamp, DateKind.Utc)' jeśli przechowujesz daty UTC zgodnie z cytowanym postem na blogu. – kamranicus

+0

Uwielbiam to, to jest naprawdę pomocne –

+0

, kiedy używam w ten sposób i jeśli obraz zmienia się nadal trwa od pamięci podręcznej przeglądarki i jej nie trafienia serwera do sprawdzenia. Masz jakiś pomysł? Proszę –

0

W nowszych wersjach MVC byłbyś lepiej zwrócenie HttpStatusCodeResult. W ten sposób nie trzeba ustawiać Response.StatusCode lub bałagan z czymkolwiek innym.

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); 
}