it-swarm.com.de

Zurückgeben einer Datei an View / Download in ASP.NET MVC

Beim Senden von in einer Datenbank gespeicherten Dateien an den Benutzer in ASP.NET MVC ist ein Problem aufgetreten. Was ich möchte, ist eine Ansicht, die zwei Links auflistet, von denen einer die Datei anzeigt und der Mimetyp, der an den Browser gesendet wird, bestimmt, wie er behandelt werden soll, und der andere einen Download erzwingt.

Wenn ich eine Datei mit dem Namen SomeRandomFile.bak anzeigen möchte und der Browser kein Programm zum Öffnen von Dateien dieses Typs hat, kann ich problemlos das Standarddownload-Verhalten verwenden. Wenn ich jedoch eine Datei mit dem Namen SomeRandomFile.pdf oder SomeRandomFile.jpg anzeigen möchte, soll die Datei einfach geöffnet werden. Ich möchte aber auch einen Download-Link auf der Seite lassen, damit ich unabhängig vom Dateityp eine Download-Eingabeaufforderung erzwingen kann. Macht das Sinn?

Ich habe FileStreamResult ausprobiert und es funktioniert für die meisten Dateien. Der Konstruktor akzeptiert standardmäßig keinen Dateinamen. Unbekannten Dateien wird daher ein Dateiname zugewiesen, der auf der URL basiert (die die zu vergebende Erweiterung nicht kennt) Inhaltstyp). Wenn ich den Dateinamen durch Angabe erzwinge, kann der Browser die Datei nicht mehr direkt öffnen, und ich erhalte eine Aufforderung zum Herunterladen. Hat das noch jemand erlebt?.

Dies sind die Beispiele für das, was ich bisher ausprobiert habe.

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

Irgendwelche Vorschläge?


PDATE: Diese Frage scheint eine Menge Leute anzusprechen, also dachte ich, ich würde ein Update posten. Die Warnung auf der unten angegebenen akzeptierten Antwort, die Oskar in Bezug auf internationale Zeichen hinzugefügt hat, ist vollständig gültig, und ich habe sie einige Male getroffen, weil ich die Klasse ContentDisposition verwendet habe. Ich habe seitdem meine Implementierung aktualisiert, um dies zu beheben. Der folgende Code stammt aus meiner letzten Inkarnation dieses Problems in einer ASP.NET Core (Full Framework) -Anwendung, sollte jedoch auch in einer älteren MVC-Anwendung mit minimalen Änderungen funktionieren, da ich die Klasse System.Net.Http.Headers.ContentDispositionHeaderValue verwende .

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
}
277
Nick Albrecht
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);
}

HINWEIS: Der obige Beispielcode berücksichtigt internationale Zeichen im Dateinamen nicht richtig. Siehe RFC6266 für die relevante Standardisierung. Ich glaube, die neuesten Versionen der ASP.Net MVC-Methode File() und der Klasse ContentDispositionHeaderValue berücksichtigen dies ordnungsgemäß. - Oskar, 25. Februar 2016

409
Darin Dimitrov

Ich hatte Probleme mit der akzeptierten Antwort, da die Variable "document" keinen Tipp enthält: var document = ... Ich poste also, was für mich als Alternative funktioniert, falls jemand anderes Probleme hat.

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

Darin Dimitrovs Antwort ist richtig. Nur eine Ergänzung:

Response.AppendHeader("Content-Disposition", cd.ToString()); kann dazu führen, dass der Browser die Datei nicht wiedergibt, wenn Ihre Antwort bereits einen Header "Content-Disposition" enthält. In diesem Fall möchten Sie möglicherweise Folgendes verwenden:

Response.Headers.Add("Content-Disposition", cd.ToString());
13
Leo

To view file (zum Beispiel txt):

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

To download file (zum Beispiel txt):

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

hinweis: Um die Datei herunterzuladen, müssen wir das Argument fileDownloadName übergeben

9
Ashot Muradian

Ich halte diese Antwort für sauberer (basierend auf 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));
    }
3
Serj Sagan

FileVirtualPath -> Research\Global Office Review.pdf

public virtual ActionResult GetFile()
{
    return File(FileVirtualPath, "application/force-download", Path.GetFileName(FileVirtualPath));
}
1
Bishoy Hanna

Der folgende Code hat für mich funktioniert, um eine PDF-Datei von einem API-Dienst abzurufen und an den Browser zu senden - ich hoffe, er hilft.

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
Jonny Boy