Возврат файла для просмотра / загрузки в ASP.NET MVC - PullRequest
274 голосов
/ 29 апреля 2011

Я столкнулся с проблемой отправки файлов, хранящихся в базе данных, обратно пользователю в ASP.NET MVC.То, что мне нужно, - это просмотр списка двух ссылок: одна для просмотра файла и позволить mimetype, отправляемому в браузер, определить способ его обработки, а другая - для принудительной загрузки.

Если я выбрал просмотрфайл с именем SomeRandomFile.bak и браузер не имеет связанной программы для открытия файлов этого типа, тогда у меня нет проблем с его настройками по умолчанию при загрузке.Однако, если я решу просмотреть файл с именем SomeRandomFile.pdf или SomeRandomFile.jpg, я хочу, чтобы файл просто открылся.Но я также хочу оставить ссылку для скачивания в стороне, чтобы можно было принудительно вызвать приглашение к загрузке независимо от типа файла.Имеет ли это смысл?

Я пробовал FileStreamResult, и он работает для большинства файлов, его конструктор не принимает имя файла по умолчанию, поэтому неизвестным файлам присваивается имя файла на основе URL (которыйне знает расширение для предоставления на основе типа контента).Если я задаю имя файла, указав его, я теряю возможность браузера открывать файл напрямую и получаю приглашение на загрузку.Кто-нибудь еще сталкивался с этим.

Это примеры того, что я до сих пор пробовал.

//Gives me a download prompt.
return File(document.Data, document.ContentType, document.Name);

//Opens if it is a known extension type, downloads otherwise (download has bogus name and missing extension)
return new FileStreamResult(new MemoryStream(document.Data), document.ContentType);

//Gives me a download prompt (lose the ability to open by default if known type)
return new FileStreamResult(new MemoryStream(document.Data), document.ContentType) {FileDownloadName = document.Name};

Есть какие-либо предложения?


ОБНОВЛЕНИЕ: Этот вопрос, кажется, вызывает отклик у многих людей, поэтому я решил опубликовать обновление.Предупреждение о принятом ответе ниже, которое было добавлено Оскаром в отношении международных символов, является полностью действительным, и я ударил его несколько раз из-за использования класса ContentDisposition.С тех пор я обновил свою реализацию, чтобы исправить это.Хотя приведенный ниже код взят из моего последнего воплощения этой проблемы в приложении ASP.NET Core (Full Framework), он должен работать с минимальными изменениями и в более старом приложении MVC, поскольку я использую класс System.Net.Http.Headers.ContentDispositionHeaderValue.

using System.Net.Http.Headers;

public IActionResult Download()
{
    Document document = ... //Obtain document from database context

    //"attachment" means always prompt the user to download
    //"inline" means let the browser try and handle it
    var cd = new ContentDispositionHeaderValue("attachment")
    {
        FileNameStar = document.FileName
    };
    Response.Headers.Add(HeaderNames.ContentDisposition, cd.ToString());

    return File(document.Data, document.ContentType);
}

// an entity class for the document in my database 
public class Document
{
    public string FileName { get; set; }
    public string ContentType { get; set; }
    public byte[] Data { get; set; }
    //Other properties left out for brevity
}

Ответы [ 7 ]

405 голосов
/ 29 апреля 2011
public ActionResult Download()
{
    var document = ...
    var cd = new System.Net.Mime.ContentDisposition
    {
        // for example foo.bak
        FileName = document.FileName, 

        // always prompt the user for downloading, set to true if you want 
        // the browser to try to show the file inline
        Inline = false, 
    };
    Response.AppendHeader("Content-Disposition", cd.ToString());
    return File(document.Data, document.ContentType);
}

ПРИМЕЧАНИЕ: Приведенный выше пример кода не может правильно учитывать международные символы в имени файла.См. RFC6266 для соответствующей стандартизации.Я считаю, что последние версии ASP.Net MVC File() метода и класса ContentDispositionHeaderValue правильно объясняют это.- Оскар 2016-02-25

113 голосов
/ 17 июня 2015

У меня были проблемы с принятым ответом из-за отсутствия намеков на тип переменной "document": var document = ... Поэтому я публикую то, что сработало для меня в качестве альтернативы, на случай, если у кого-то еще возникнут проблемы.

public ActionResult DownloadFile()
{
    string filename = "File.pdf";
    string filepath = AppDomain.CurrentDomain.BaseDirectory + "/Path/To/File/" + filename;
    byte[] filedata = System.IO.File.ReadAllBytes(filepath);
    string contentType = MimeMapping.GetMimeMapping(filepath);

    var cd = new System.Net.Mime.ContentDisposition
    {
        FileName = filename,
        Inline = true,
    };

    Response.AppendHeader("Content-Disposition", cd.ToString());

    return File(filedata, contentType);
}
13 голосов
/ 21 апреля 2016

Ответ Дарина Димитрова правильный. Просто дополнение:

Response.AppendHeader("Content-Disposition", cd.ToString()); может привести к тому, что браузер не сможет отобразить файл, если ваш ответ уже содержит заголовок «Content-Disposition». В этом случае вы можете использовать:

Response.Headers.Add("Content-Disposition", cd.ToString());
9 голосов
/ 04 мая 2016

К просмотр файла (например, txt):

return File("~/TextFileInRootDir.txt", MediaTypeNames.Text.Plain);

К загрузить файл (например, txt):

return File("~/TextFileInRootDir.txt", MediaTypeNames.Text.Plain, "TextFile.txt");

примечание: для загрузки файла мы должны передать fileDownloadName аргумент

3 голосов
/ 07 ноября 2013

Я считаю, что этот ответ чище, (на основе https://stackoverflow.com/a/3007668/550975)

    public ActionResult GetAttachment(long id)
    {
        FileAttachment attachment;
        using (var db = new TheContext())
        {
            attachment = db.FileAttachments.FirstOrDefault(x => x.Id == id);
        }

        return File(attachment.FileData, "application/force-download", Path.GetFileName(attachment.FileName));
    }
1 голос
/ 24 января 2014

FileVirtualPath -> Исследования \ Global Office Review.pdf

public virtual ActionResult GetFile()
{
    return File(FileVirtualPath, "application/force-download", Path.GetFileName(FileVirtualPath));
}
0 голосов
/ 10 мая 2018

Приведенный ниже код помог мне получить pdf-файл из службы API и отправить его в браузер - надеюсь, это поможет;

public async Task<FileResult> PrintPdfStatements(string fileName)
    {
         var fileContent = await GetFileStreamAsync(fileName);
         var fileContentBytes = ((MemoryStream)fileContent).ToArray();
         return File(fileContentBytes, System.Net.Mime.MediaTypeNames.Application.Pdf);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...