Может ли контроллер ASP.NET MVC вернуть изображение?

Мы разрабатываем PythonAnywhere , чтобы заполнить именно эту нишу. Мы настроили его сначала на работу с iPad. Но похоже, что Nexus 7 достаточно популярен сейчас, что может потребоваться достаточно многого для Android.

436
задан Peter Mortensen 19 June 2015 в 18:38
поделиться

11 ответов

Используйте метод File базовых контроллеров.

public ActionResult Image(string id)
{
    var dir = Server.MapPath("/Images");
    var path = Path.Combine(dir, id + ".jpg"); //validate the path for security or use other means to generate the path.
    return base.File(path, "image/jpeg");
}

В качестве примечания, это кажется довольно эффективным. Я провел тест, в котором запросил изображение через контроллер ( http: // localhost / MyController / Image / MyImage ) и через прямой URL-адрес ( http: // localhost / Images / MyImage. jpg ) и получили следующие результаты:

  • MVC: 7,6 миллисекунды на фотографию
  • Прямая: 6,7 миллисекунд на фотографию

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

525
ответ дан 22 November 2019 в 23:09
поделиться

Вы могли использовать HttpContext. Ответ и непосредственно пишет содержание в него (WriteFile () мог бы работать на Вас), и затем возвратите ContentResult из своего действия вместо ActionResult.

Правовая оговорка: Я не попробовал это, это основано на рассмотрении доступных API.:-)

1
ответ дан Franci Penov 19 June 2015 в 18:38
поделиться

Взгляд на ContentResult. Это возвращает строку, но может использоваться для создания собственного подобного BinaryResult класса.

3
ответ дан leppie 19 June 2015 в 18:38
поделиться

Я вижу две опции:

1) Реализация Ваш собственный IViewEngine и набор свойство ViewEngine Контроллера Вы используете для своего ImageViewEngine в Вашем желаемом методе "изображения".

2) Использование представление:-). Просто измените тип контента и т.д.

1
ответ дан Matt Mitchell 19 June 2015 в 18:38
поделиться

Можно записать непосредственно в ответ, но тогда это не является тестируемым. Это предпочтено для возврата ActionResult, который задержал выполнение. Вот мой resusable StreamResult:

public class StreamResult : ViewResult
{
    public Stream Stream { get; set; }
    public string ContentType { get; set; }
    public string ETag { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.ContentType = ContentType;
        if (ETag != null) context.HttpContext.Response.AddHeader("ETag", ETag);
        const int size = 4096;
        byte[] bytes = new byte[size];
        int numBytes;
        while ((numBytes = Stream.Read(bytes, 0, size)) > 0)
            context.HttpContext.Response.OutputStream.Write(bytes, 0, numBytes);
    }
}
9
ответ дан JarrettV 19 June 2015 в 18:38
поделиться

ОБНОВЛЕНИЕ: существуют более оптимальные варианты, чем мой исходный ответ. Это работает за пределами MVC вполне хорошо, но лучше придерживаться встроенных методов возврата содержимого изображения. См. проголосовавшие ответы.

Вы, конечно, можете. Испытайте эти шаги:

  1. Загрузка изображение от диска в к массиву байтов
  2. кэширует изображение в случае, Вы ожидаете больше запросов на изображение и не хотите дисковый ввод-вывод (мой образец не кэширует его ниже)
  3. Изменение тип пантомимы через Ответ. Ответ ContentType
  4. . BinaryWrite массив байтов изображения

Вот является некоторым примером кода:

string pathToFile = @"C:\Documents and Settings\some_path.jpg";
byte[] imageData = File.ReadAllBytes(pathToFile);
Response.ContentType = "image/jpg";
Response.BinaryWrite(imageData);

Hope, которая помогает!

5
ответ дан Ian Suttle 19 June 2015 в 18:38
поделиться
  • 1
    @samseabom, если Вы хотите свой код, готовый к производству, можно всегда нанимать Eric... – albertedevigo 12 September 2012 в 15:09

Я также встретился с подобным требованием,

Так в моем случае, я выполняю запрос к Контроллеру с путем к папке изображения, который в ответ передает объект ImageResult обратно.

После фрагмента кода иллюстрируют работу:

var src = string.Format("/GenericGrid.mvc/DocumentPreviewImageLink?fullpath={0}&routingId={1}&siteCode={2}", fullFilePath, metaInfo.RoutingId, da.SiteCode);

                if (enlarged)
                    result = "<a class='thumbnail' href='#thumb'>" +
                        "<img src='" + src + "' height='66px' border='0' />" +
                        "<span><img src='" + src + "' /></span>" +
                        "</a>";
                else
                    result = "<span><img src='" + src + "' height='150px' border='0' /></span>";

И в Контроллере от канал передачи изображения я произвожу изображение и возвращаю его назад вызывающей стороне

try
{
  var file = new FileInfo(fullpath);
  if (!file.Exists)
     return string.Empty;


  var image = new WebImage(fullpath);
  return new ImageResult(new MemoryStream(image.GetBytes()), "image/jpg");


}
catch(Exception ex)
{
  return "File Error : "+ex.ToString();
}
0
ответ дан 22 November 2019 в 23:09
поделиться

Используя релизную версию MVC, вот что я делаю:

[AcceptVerbs(HttpVerbs.Get)]
[OutputCache(CacheProfile = "CustomerImages")]
public FileResult Show(int customerId, string imageName)
{
    var path = string.Concat(ConfigData.ImagesDirectory, customerId, "\\", imageName);
    return new FileStreamResult(new FileStream(path, FileMode.Open), "image/jpeg");
}

У меня, очевидно, есть кое-какие специфичные для приложения вещи в здесь относительно построения пути, но возвращение FileStreamResult приятно и просто.

Я провел некоторое тестирование производительности в отношении этого действия в отношении вашего ежедневного обращения к изображению (в обход контроллера), и разница между средними составляла только около 3 миллисекунд (среднее значение для контроллера составляло 68 мс, для неконтроллера было 65 мс).

Я попробовал некоторые из других методов, упомянутых в ответах здесь, и снижение производительности было гораздо более драматичным ... некоторые из ответов решения были в 6 раз неконтроллерными (другие контроллеры в среднем 340 мс, неконтроллерные 65 мс ).

125
ответ дан 22 November 2019 в 23:09
поделиться

Ниже кода использует System.Drawing.Bitmap для загрузки изображения.

using System.Drawing;
using System.Drawing.Imaging;

public IActionResult Get()
{
    string filename = "Image/test.jpg";
    var bitmap = new Bitmap(filename);

    var ms = new System.IO.MemoryStream();
    result.Save(ms, ImageFormat.Jpeg);
    ms.Position = 0;
    return new FileStreamResult(ms, "image/jpeg");
}
0
ответ дан 22 November 2019 в 23:09
поделиться

Чтобы немного пояснить ответ Диланда:

Три класса реализуют класс FileResult :

System.Web.Mvc.FileResult
      System.Web.Mvc.FileContentResult
      System.Web.Mvc.FilePathResult
      System.Web.Mvc.FileStreamResult

Все они достаточно понятны:

  • Для загрузки пути к файлу, где файл существует на диске, используйте FilePathResult - это самый простой способ, позволяющий избежать использования потоков.
  • Для массивов byte [] (похожих на Response.BinaryWrite) используйте FileContentResult .
  • Для массивов byte [], в которых требуется файл для загрузки (content-disposition: attachment), используйте FileStreamResult аналогично описанному ниже, но с MemoryStream и с помощью GetBuffer () .
  • ] Для потоков используйте FileStreamResult . Он называется FileStreamResult, но для него требуется Stream , поэтому я предполагаю , что он работает с MemoryStream .

Ниже приведен пример использования метода размещения контента (не тестировался):

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult GetFile()
    {
        // No need to dispose the stream, MVC does it for you
        string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data", "myimage.png");
        FileStream stream = new FileStream(path, FileMode.Open);
        FileStreamResult result = new FileStreamResult(stream, "image/png");
        result.FileDownloadName = "image.png";
        return result;
    }
100
ответ дан 22 November 2019 в 23:09
поделиться
if (!System.IO.File.Exists(filePath))
    return SomeHelper.EmptyImageResult(); // preventing JSON GET/POST exception
else
    return new FilePathResult(filePath, contentType);

SomeHelper.EmptyImageResult () должен вернуть FileResult с существующим изображением (например, прозрачным 1x1).

Это самый простой способ, если у вас есть файлы, хранящиеся на локальном диске. Если файлы представляют собой байт [] или поток , тогда используйте FileContentResult ] или FileStreamResult , как предложил Дилан.

1
ответ дан 22 November 2019 в 23:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: