340 Stimmen

Rückgabe einer Datei zur Ansicht/Download in ASP.NET MVC

Ich stoße auf ein Problem, das Senden von Dateien in einer Datenbank gespeichert zurück an den Benutzer in ASP.NET MVC. Was ich will, ist eine Ansicht, die zwei Links auflistet, eine, um die Datei anzuzeigen und lassen Sie den Mimetyp an den Browser gesendet bestimmen, wie es behandelt werden soll, und die andere, um einen Download zu erzwingen.

Wenn ich eine Datei namens SomeRandomFile.bak und der Browser kein zugehöriges Programm zum Öffnen von Dateien dieses Typs hat, dann habe ich kein Problem damit, dass er standardmäßig das Download-Verhalten anwendet. Wenn ich jedoch eine Datei namens SomeRandomFile.pdf ou SomeRandomFile.jpg Ich möchte, dass die Datei einfach geöffnet wird. Aber ich möchte auch einen Download-Link auf der Seite, so dass ich eine Download-Aufforderung unabhängig vom Dateityp erzwingen kann. Ist dies sinnvoll?

Ich habe versucht FileStreamResult und es funktioniert für die meisten Dateien, sein Konstruktor akzeptiert standardmäßig keinen Dateinamen, so dass unbekannte Dateien einen Dateinamen auf der Grundlage der URL zugewiesen werden (die nicht weiß, welche Erweiterung auf der Grundlage des Inhaltstyps zu geben). Wenn ich den Dateinamen erzwinge, indem ich ihn angebe, kann der Browser die Datei nicht mehr direkt öffnen und ich erhalte eine Aufforderung zum Herunterladen. Hat jemand dieses Problem schon einmal gehabt?

Dies sind die Beispiele, die 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?


UPDATE: Diese Frage scheint viele Leute zu beschäftigen, also dachte ich, ich bringe sie mal auf den neuesten Stand. Die Warnung in der akzeptierten Antwort unten, die von Oskar in Bezug auf internationale Zeichen hinzugefügt wurde, ist absolut gültig, und ich habe sie ein paar Mal getroffen, weil ich die ContentDisposition Klasse. Ich habe seitdem meine Implementierung aktualisiert, um dies zu beheben. Während der Code unten von meiner neuesten Inkarnation dieses Problems in einer ASP.NET Core (Full Framework)-App ist, sollte es mit minimalen Änderungen in einer älteren MVC-Anwendung auch funktionieren, da ich die System.Net.Http.Headers.ContentDispositionHeaderValue Klasse.

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
}

464voto

Darin Dimitrov Punkte 990883
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 die internationalen Zeichen im Dateinamen nicht richtig. Siehe RFC6266 für die entsprechende Standardisierung. Ich glaube, dass neuere Versionen von ASP.Net MVC's File() Methode und die ContentDispositionHeaderValue Klasse trägt dem angemessen Rechnung. - Oskar 2016-02-25

147voto

ooXei1sh Punkte 3279

Ich hatte Probleme mit der akzeptierten Antwort, da die Variable "document" nicht mit einem Typ-Hinweis versehen war: var document = ... Deshalb poste ich hier, was bei mir als Alternative funktioniert hat, 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);
}

18voto

An siehe Datei (z. B. txt):

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

An herunterladen Datei (z. B. txt):

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

Hinweis: Um die Datei herunterzuladen, müssen wir fileDownloadName Argument

16voto

Leo Punkte 399

Die Antwort von Darin Dimitrov 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 "Content-Disposition"-Header enthält. In diesem Fall können Sie verwenden:

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

5voto

Serj Sagan Punkte 26507

Ich glaube, diese Antwort ist h )

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X