Потоковый файл с использованием ASP.NET MVC FileContentResult в браузере с именем? - PullRequest
57 голосов
/ 08 июля 2010

Есть ли способ для потоковой передачи файла с помощью ASP.NET MVC FileContentResult в браузере с определенным именем?

Я заметил, что вы можете иметь FileDialog (Open / Save) или вы можете выполнять потоковую передачуфайл в окне браузера, но затем он будет использовать ActionName при попытке сохранить файл.

У меня есть следующий сценарий:

byte[] contents = DocumentServiceInstance.CreateDocument(orderId, EPrintTypes.Quote);
result = File(contents, "application/pdf", String.Format("Quote{0}.pdf", orderId));

Когда я использую это, я могупоток байтов, но диалоговое окно файла OPEN / SAVE предоставляется пользователю.Я хотел бы на самом деле поток этого файла в окне браузера.

Если я просто использую FilePathResult, он показывает файл в окне браузера, но затем, когда я нажимаю кнопку «Сохранить», чтобы сохранить файл вPDF, он показывает имя действия в качестве имени файла.

Кто-нибудь сталкивался с этим?

Ответы [ 6 ]

86 голосов
/ 08 июля 2010
public ActionResult Index()
{
    byte[] contents = FetchPdfBytes();
    return File(contents, "application/pdf", "test.pdf");
}

и для открытия PDF в браузере вам нужно установить заголовок Content-Disposition:

public ActionResult Index()
{
    byte[] contents = FetchPdfBytes();
    Response.AddHeader("Content-Disposition", "inline; filename=test.pdf");
    return File(contents, "application/pdf");
}
44 голосов
/ 15 апреля 2013

На самом деле, самый простой способ - сделать следующее ...

byte[] content = your_byte[];

FileContentResult result = new FileContentResult(content, "application/octet-stream") 
                 {
                     FileDownloadName = "your_file_name"
                 };

return result;
12 голосов
/ 15 июля 2010

Это может быть полезно для тех, кто сталкивается с этой проблемой.Я наконец-то нашел решение.Оказывается, даже если мы используем inline для «content-disposition» и указываем имя файла, браузеры по-прежнему не используют имя файла.Вместо этого браузеры пытаются интерпретировать имя файла на основе пути / URL.

Вы можете прочитать далее по этому URL: Безопасная загрузка файла в браузере с правильным именем файла

Этодал мне идею, я просто создал свой маршрут URL, который будет преобразовывать URL и заканчивать его именем файла, который я хотел дать файлу.Так, например, мой первоначальный вызов контроллера просто состоял из передачи идентификатора заказа из распечатанного заказа.Я ожидал, что имя файла будет иметь формат Order {0} .pdf, где {0} - это Order Id.Точно так же для кавычек я хотел Quote {0} .pdf.

. В моем контроллере я просто добавил и добавил дополнительный параметр, чтобы принять имя файла.Я передал имя файла в качестве параметра в методе URL.Action.

Затем я создал новый маршрут, который отобразит этот URL в формате: http://localhost/ShoppingCart/PrintQuote/1054/Quote1054.pdf


routes.MapRoute("", "{controller}/{action}/{orderId}/{fileName}",
                new { controller = "ShoppingCart", action = "PrintQuote" }
                , new string[] { "x.x.x.Controllers" }
            );

Это в значительной степенирешил мою проблему.Надеюсь, это кому-нибудь поможет!

Cheerz, Anup

7 голосов
/ 27 июля 2013

Предыдущие ответы верны: добавление строки ...

Response.AddHeader("Content-Disposition", "inline; filename=[filename]");

... приведет к отправке нескольких заголовков Content-Disposition в браузер. Это происходит, поскольку b / c FileContentResult внутренне применяет заголовок, если вы предоставляете ему имя файла. Альтернативное и довольно простое решение - просто создать подкласс FileContentResult и переопределить его ExecuteResult() метод. Вот пример, который создает экземпляр класса System.Net.Mime.ContentDisposition (тот же объект, который используется во внутренней реализации FileContentResult) и передает его в новый класс:

public class FileContentResultWithContentDisposition : FileContentResult
{
    private const string ContentDispositionHeaderName = "Content-Disposition";

    public FileContentResultWithContentDisposition(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
        : base(fileContents, contentType)
    {
        // check for null or invalid ctor arguments
        ContentDisposition = contentDisposition;
    }

    public ContentDisposition ContentDisposition { get; private set; }

    public override void ExecuteResult(ControllerContext context)
    {
        // check for null or invalid method argument
        ContentDisposition.FileName = ContentDisposition.FileName ?? FileDownloadName;
        var response = context.HttpContext.Response;
        response.ContentType = ContentType;
        response.AddHeader(ContentDispositionHeaderName, ContentDisposition.ToString());
        WriteFile(response);
    }
}

В вашем Controller или в базе Controller вы можете написать простого помощника для создания экземпляра FileContentResultWithContentDisposition и затем вызвать его из вашего метода действия, например:

protected virtual FileContentResult File(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
{
    var result = new FileContentResultWithContentDisposition(fileContents, contentType, contentDisposition);
    return result;
}

public ActionResult Report()
{
    // get a reference to your document or file
    // in this example the report exposes properties for
    // the byte[] data and content-type of the document
    var report = ...
    return File(report.Data, report.ContentType, new ContentDisposition {
        Inline = true,
        FileName = report.FileName
    });
}

Теперь файл будет отправлен в браузер с выбранным вами именем файла и заголовком расположения содержимого «inline; filename = [имя файла]».

Надеюсь, это поможет!

4 голосов
/ 01 апреля 2015

Абсолютно самый простой способ для потоковой передачи файла в браузер с использованием ASP.NET MVC заключается в следующем:

public ActionResult DownloadFile() {
    return File(@"c:\path\to\somefile.pdf", "application/pdf", "Your Filename.pdf");
}

Это проще, чем метод, предложенный @ azarc3, ​​поскольку вам даже не нужно читать байты.

Кредит идет на: http://prideparrot.com/blog/archive/2012/8/uploading_and_returning_files#how_to_return_a_file_as_response

** Редактировать **

Очевидно, мой «ответ» такой же, как вопрос ОП. Но я не сталкиваюсь с проблемой, с которой он сталкивается. Возможно, это была проблема со старой версией ASP.NET MVC?

0 голосов
/ 26 июля 2013
public FileContentResult GetImage(int productId) { 
     Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productId); 
     if (prod != null) { 
         return File(prod.ImageData, prod.ImageMimeType); 
      } else { 
         return null; 
     } 
}
...