2010-07-08 5 views
51

Gibt es eine Möglichkeit, eine Datei mit ASP.NET MVC FileContentResult im Browser mit einem bestimmten Namen zu streamen?Stream-Datei mit ASP.NET MVC FileContentResult in einem Browser mit einem Namen?

Ich habe festgestellt, dass Sie entweder einen FileDialog (Öffnen/Speichern) haben oder Sie können die Datei in einem Browserfenster streamen, aber dann wird der ActionName verwendet, wenn Sie versuchen, die Datei zu speichern.

Ich habe folgendes Szenario:

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

Wenn ich diese, kann ich die Bytes streamen, sondern ein Öffnen/Speichern Dateidialog wird dem Benutzer gegeben. Ich möchte diese Datei tatsächlich in einem Browserfenster streamen.

Wenn ich nur die FilePathResult verwenden, zeigt es die Datei in einem Browser-Fenster, aber wenn ich dann auf „Speichern“ klicken, um die Datei in PDF zu speichern, es zeigt mir die Aktion Name als der Name der Datei.

Hat jemand begegnet?

Antwort

11

Dies könnte für wen sonst steht dieses Problem hilfreich sein. Ich habe endlich eine Lösung gefunden. Selbst wenn wir das Inline-Element für "Content-Disposition" verwenden und einen Dateinamen angeben, verwenden die Browser den Dateinamen nicht. Stattdessen versuchen Browser den Dateinamen basierend auf dem Pfad/der URL zu interpretieren.

Sie können auf dieser URL weiter lesen: Securly download file inside browser with correct filename

Dies gab mir eine Idee, ich habe gerade meine URL Route erstellt, der die URL umwandeln würde und es mit dem Namen der Datei anzeigen wollte ich die Datei geben, . So für z.B. Mein ursprünglicher Controller-Aufruf bestand lediglich darin, die Auftrags-ID des gedruckten Auftrags zu übergeben. Ich habe erwartet, dass der Dateiname das Format Order {0} .pdf hat, wobei {0} die Bestell-ID ist. Ähnlich für Zitate, ich wollte Zitat {0} .pdf.

In meiner Steuerung ging ich einfach weiter und fügte einen zusätzlichen Parameter hinzu, um den Dateinamen zu akzeptieren. Ich habe den Dateinamen als Parameter in der URL.Action-Methode übergeben.

Ich habe dann eine neue Route, die diese URL in das Format der Karte würde: Dieses ziemlich gelöst mein Problem http://localhost/ShoppingCart/PrintQuote/1054/Quote1054.pdf

 

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

. Hoffentlich hilft das jemandem!

Cheerz, Anup

+0

Ein Hack, aber ein sehr effektiver Hack! Vielen Dank! –

+0

Leider immer noch mit IE 11 benötigt. Nicht benötigt mit Chrome und Firefox. –

79
public ActionResult Index() 
{ 
    byte[] contents = FetchPdfBytes(); 
    return File(contents, "application/pdf", "test.pdf"); 
} 

und für die PDF-Datei im Browser öffnen müssen Sie die Content-Disposition Header setzen:

public ActionResult Index() 
{ 
    byte[] contents = FetchPdfBytes(); 
    Response.AddHeader("Content-Disposition", "inline; filename=test.pdf"); 
    return File(contents, "application/pdf"); 
} 
+0

Hallo Darin, Dies öffnet einen OPEN/SAVE-Dialog wie ich bereits erwähnt habe. Ich möchte das eine Datei im Browser öffnen. –

+1

@Anup, siehe mein Update. –

+0

Können wir einen generischen Wert anstelle von "application/pdf" haben? wie ich bin mir nicht sicher, der Typ der Datei. Es ist der Benutzer, der es an erster Stelle hochgeladen hat. – neebz

38

Eigentlich ist die absolut einfachste Weg, die folgende ...

byte[] content = your_byte[]; 

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

return result; 
+1

Nein! .. meine Antwort ist am einfachsten, http://Stackoverflow.com/a/29392930/193634 –

+2

Ich würde zustimmen, wenn die ursprüngliche Frage kein Byte-Array enthalten würde. – azarc3

0
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; 
    } 
} 
5

Vorherige Antworten sind richtig zu tun: das Hinzufügen der Zeile ...

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

... bewirkt, dass mehrere Content-Disposition-Header an den Browser gesendet werden.Dies geschieht b/c FileContentResult wendet intern den Header an, wenn Sie es mit einem Dateinamen angeben. Eine alternative und ziemlich einfache Lösung besteht darin, einfach eine Unterklasse von FileContentResult zu erstellen und deren ExecuteResult()-Methode zu überschreiben. Hier ist ein Beispiel, das eine Instanz der System.Net.Mime.ContentDisposition Klasse instanziiert (das gleiche Objekt in der internen FileContentResult Implementierung verwendet) und leitet es in die neue Klasse:

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

In Ihrem Controller oder in einer Basis Controller, können Sie schreiben ein einfacher Helfer wie so ein FileContentResultWithContentDisposition und dann rufen Sie es von Ihrer Aktionsmethode, instanziiert:

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

Jetzt wird die Datei mit dem Dateinamen an den Browser gesendet werden, die Sie und mit einem Content-Disposition-Header " Inline; Dateiname = [Dateiname] ".

Ich hoffe, dass hilft!

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

Das ist einfacher als das Verfahren, vorgeschlagen von @ azarc3 da man nicht einmal das Bytes lesen benötigen:

+0

Ich habe zuerst die 'ContentDisposition' -Helferklassen-Methode genommen, nur um zu realisieren, dass MVC sie auch intern benutzte, aber mit einigen Hacks, um den utf-8-Dateinamen korrekt zu behandeln. Die 'ContentDisposition'-Hilfsklasse tut es falsch, wenn sie utf-8-Werte kodieren muss. Weitere Informationen finden Sie unter [mein Kommentar hier] (/ questions/1012437/use-of-content-disposition-in-einem-http-response-header/22221217 # comment57484455_22221217). –

4

Der absolute einfachste Weg, eine Datei in dem Browser mit ASP.NET MVC diesem zu streamen .

Kredit geht an: http://prideparrot.com/blog/archive/2012/8/uploading_and_returning_files#how_to_return_a_file_as_response

** ** Bearbeiten

Offenbar meine 'Antwort' ist das gleiche wie die Frage des OP. Aber ich stehe nicht vor dem Problem, das er hat. Wahrscheinlich war dies ein Problem mit älteren Versionen von ASP.NET MVC?

+0

Sein Problem kann abstrahiert werden, MVC senden eine 'content-disposition'-Header mit' Anhang' Disposition bei der Angabe eines Dateinamens, wie man es als "Inline" senden? Testen Sie Ihre Lösungsantwortheader, normalerweise sehen Sie auch 'attachment'. –