Zwracanie pliku do obejrzenia/pobrania w ASP.NET MVC

Napotykam problem z wysłaniem plików przechowywanych w bazie danych z powrotem do użytkownika w ASP.NET MVC. Chcę mieć widok z listą dwóch linków, jeden do przeglądania pliku i pozwalający typ MIME wysłany do przeglądarki określić, jak powinien być obsługiwany, a drugi do wymuszenia pobierania.

Jeśli zdecyduję się wyświetlić plik o nazwie SomeRandomFile.bak i przeglądarka nie ma powiązanego programu do otwierania plików tego typu, to nie mam problemu z domyślnym zachowaniem pobierania. Jeśli jednak zdecyduję aby wyświetlić plik o nazwie SomeRandomFile.pdf lub SomeRandomFile.jpg chcę, aby plik po prostu się otworzył. Ale chcę również zachować link do pobierania z boku, aby móc wymusić monit o pobieranie niezależnie od typu pliku. Czy to ma sens?

Próbowałem FileStreamResult i działa dla większości plików, jego konstruktor domyślnie nie akceptuje nazwy pliku, więc nieznanym plikom przypisuje się nazwę pliku na podstawie adresu url(który nie zna rozszerzenia, które należy podać na podstawie typu zawartości). Jeśli wymuszę nazwę pliku podając tracę możliwość bezpośredniego otwarcia pliku przez przeglądarkę i otrzymuję monit o pobranie. Czy ktoś jeszcze się z tym zetknął?

To są przykłady tego, czego próbowałem do tej pory.
//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};
Jakieś sugestie?
Author: Nick Albrecht, 2011-04-29

8 answers

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

Uwaga: powyższy przykładowy kod nie uwzględnia znaków międzynarodowych w nazwie pliku. Patrz RFC6266 dla odpowiedniej standaryzacji. Wierzę, że najnowsze wersje ASP.Net metoda MVC File() i klasa ContentDispositionHeaderValue poprawnie to ujmują. - Oskar 2016-02-25

 377
Author: Darin Dimitrov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-26 00:00:19

Miałem problem z zaakceptowaną odpowiedzią ze względu na brak hintingu typu na zmiennej "document": var document = ... więc zamieszczam to, co działało dla mnie jako alternatywa na wypadek, gdyby ktoś inny miał problemy.

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);
}
 103
Author: ooXei1sh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-23 01:18:21

To Zobacz Plik (na przykład txt):

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

Do pobierz plik (na przykład txt):

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

Uwaga: Aby pobrać plik powinniśmy przekazać filedownname argument

 8
Author: Ashot Muradian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-04 16:10:14

Odpowiedź Darina Dimitrowa jest prawidłowa. Tylko dodatek:

Response.AppendHeader("Content-Disposition", cd.ToString()); może to spowodować, że przeglądarka nie wyświetli pliku, jeśli odpowiedź zawiera już nagłówek "Content-Disposition". W takim przypadku możesz użyć:

Response.Headers.Add("Content-Disposition", cd.ToString());
 8
Author: Leo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:50

FileVirtualPath -- > Research\Global Office Review.pdf

public virtual ActionResult GetFile()
{
    return File(FileVirtualPath, "application/force-download", Path.GetFileName(FileVirtualPath));
}
 1
Author: Bishoy Hanna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-24 00:43:49

Uważam, że ta odpowiedź jest czystsza, (na podstawie 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
Author: Serj Sagan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:00

Poniższy kod zadziałał u mnie za pobranie pliku pdf z usługi API i wysłanie go do przeglądarki-mam nadzieję, że pomoże;

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);
    }
 0
Author: Jonny Boy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-10 12:38:33

Innym łatwym sposobem jest

public ActionResult GetLoadingLogo()
{
  if (1 == 1)
  {
    return new FilePathResult(Server.MapPath("~/Content/Images/ajaxLoader_dhanlaxmi.gif"), "image/gif");
  }
  else
  {
    return new FilePathResult(Server.MapPath("~/Content/Images/add-icon.png"), "image/png");
  }
}
 -1
Author: Bimal Das,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-19 05:29:31