Как вернуть статус 304 с помощью FileResult в ASP.NET MVC RC1

Как вы знаете, у нас есть новый ActionResult, называемый FileResult в версии RC1 ASP.NET MVC.

Используя это, ваши методы действий могут динамически возвращать изображение в браузер. Что-то вроде этого:

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

В HTML-коде мы можем использовать что-то вроде этого:

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

Поскольку изображение возвращается динамически, нам нужен способ кэширования возвращенного потока, чтобы нам не нужно было снова считывать изображение из базы данных. Я думаю, мы можем сделать это с чем-то вроде этого, я не уверен:

Response.StatusCode = 304;

Это говорит браузеру, что у вас уже есть изображение в кеше. Я просто не знаю, что возвратить в моем методе действий после установки StatusCode на 304. Должен ли я вернуть нуль или что-то еще?

Ответы

Ответ 1

Этот блог ответил на вопрос для меня; http://weblogs.asp.net/jeff/archive/2009/07/01/304-your-images-from-a-database.aspx

В принципе, вам нужно прочитать заголовок запроса, сравнить последние измененные даты и вернуть 304, если они совпадают, в противном случае вернуть изображение (с статусом 200) и соответствующим образом установить заголовки кеша.

Фрагмент кода из блога:

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

Ответ 2

Не используйте 304 с FileResult. Из спецификация:

Ответ 304 НЕ ДОЛЖЕН содержать тело сообщения, и, следовательно, всегда заканчивается первой пустой строкой после полей заголовка.

Непонятно, что вы пытаетесь сделать из своего вопроса. Сервер не знает, что браузер имеет в кеше. Браузер решает это. Если вы пытаетесь сообщить браузеру не повторно извлекать изображение при необходимости, если оно уже есть, установите ответ заголовок Cache-Control.

Если вам нужно вернуть 304, вместо этого используйте EmptyResult.

Ответ 3

В более новых версиях MVC вам будет лучше возвращать HttpStatusCodeResult. Таким образом вам не нужно устанавливать Response.StatusCode или беспорядок с чем-либо еще.

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