2016-07-07 11 views
3

ersten Frage aus, so lassen Sie mich wissen, wenn ich es falsch mache ...C# mvc pdf-Download auf Android Chrom hier

Mein C# MVC5 App können Anwender PDF-Dateien herunterladen. Es funktioniert gut, außer auf meinem Android-Handy. Ich benutze Chrome und lasse das Betriebssystem mit dem PDF umgehen. Es sieht so aus, als würde der Google Drive-App-Build im PDF-Viewer verwendet.

Wenn ich einen direkten Link zu der Datei verwenden, funktioniert es gut, aber wenn ich es über eine Controller-Aktion herunterladen, scheitert es mit "Datei ist ungültiges Format". Ich habe es zu einem Testfall für diese Frage vereinfacht.

Also hier ist meine Aktionsmethode:

public ActionResult IndirectTestFile() 
{ 
string filename = "document.pdf"; 

var disposition = new System.Net.Mime.ContentDisposition("inline") { FileName = filename }; 
Response.AppendHeader("Content-Disposition", disposition.ToString()); 

string serverFilename = Server.MapPath("~/files/direct/" + filename); 
return File(serverFilename, "application/pdf"); 
} 

und mein HTML:

//This fails: 
<a href="/report/indirectTestFile">Indirect link to file</a> 

//This works: 
<a href="/Files/direct/Document.pdf">Direct link to file</a> 

Ich verwende Windows (Desktop) Chrome die Header für diese Anfrage zu bekommen.

Hier ist die Antwort-Header für den direkten Link:

HTTP/1.1 200 OK 
Content-Type: application/pdf 
Last-Modified: Thu, 07 Jul 2016 11:46:47 GMT 
Accept-Ranges: bytes 
ETag: "b8a3dd3d45d8d11:0" 
Server: Microsoft-IIS/10.0 
X-Powered-By: ASP.NET 
Date: Thu, 07 Jul 2016 12:33:05 GMT 
Content-Length: 51793 

Und die Antwort-Header für Link auf die Aktion MVC:

HTTP/1.1 200 OK 
Cache-Control: private, s-maxage=0 
Content-Type: application/pdf 
Server: Microsoft-IIS/10.0 
Content-Disposition: inline; filename=document.pdf 
X-AspNet-Version: 4.0.30319 
X-Powered-By: ASP.NET 
Date: Thu, 07 Jul 2016 12:34:09 GMT 
Content-Length: 51793 

Ich sehe es große Unterschiede nicht, aber man ist zuverlässig funktioniert, und der andere versagt zuverlässig.

ist es kein korrupter Download. Wenn ich das "schlechte" PDF auf Windows herunterlade und es auf das Android-Handy kopiere, ist der gleiche Betrachter froh, es zu zeigen!

Wer sieht das schon mal? Danke für jede Hilfe.

Antwort

1

Für zukünftige Forscher:

Ich habe dieses Problem nicht gelöst, aber ich habe genau herauszufinden, was die Ursache war. Wenn ich meine Logs anschaue, sieht es so aus, als ob die Google Drive/Docs-App den Download statt des Browsers handhabt. Die Anfrage kommt mit einem anderen User-Agent zum Browser.

Das bedeutet, dass es in einer anderen Sitzung passiert. Diese Sitzung ist nicht auf der Website angemeldet. Anstatt die PDF-Datei herunterzuladen, wird sie auf die Anmeldeseite umgeleitet, lädt sie herunter und beschwert sich, dass es sich nicht um eine gültige PDF-Datei handelt! Deshalb passiert es.

Ich getestet, dass durch Entfernen der Authentifizierung von der Steuerung, so wird die Anfrage nicht umgeleitet, und die PDF-Downloads und zeigt OK.

Ich kann nicht herausfinden, warum Chrome den direkten Download selbst handhabt, aber übergibt den Controller Link an die Google App. Ich habe meinen Server so geändert, dass beide Anfragen die gleichen Header zurückgeben, also bin ich mir nicht bewusst, wie Chrome den Unterschied zwischen den beiden erkennen und sie anders behandeln kann, aber das tut es.

Ich muss entweder herausfinden oder meine App neu organisieren, um dieses Problem zu umgehen, aber vielleicht ist das für eine andere Frage.

Danke an Fran für die Ideen.

Update: Ich erinnere mich nicht die genaue Lösung dieses Problems (so traurig, es war nur ein paar Wochen ...), aber ich glaube, es war, weil ich zum meinem Controller-Aktion umgeleitet wurde. z.B. Ich würde eine Aktion wie diese (vereinfacht) haben

public ActionResult MakePDF(string id) 
    { 
     // code to create the file removed for clarity. 
     return RedirectToAction("IndirectTestFile"); 
    } 

dies würde die PDF-Datei machen und auf eine Aktion umleiten, die es dem Benutzer zurückgibt.

public ActionResult MakePDF(string id) 
    { 
     // code to create the file removed for clarity. 
     return IndirectTestFile(); 
    } 

So schneiden Ich mag dieses die Umleitung und das scheint die Lösung zu sein - ich diese Methode trotzdem bin mit und es ist für mich zu arbeiten.

+0

Ich habe das gleiche genaue Problem. Werden Sie ein Update veröffentlichen, wenn Sie etwas finden? Ich werde weiter forschen. – Danation

+0

Es sieht also so aus, als ob dies vom Content-Disposition-Header verursacht wird. Ich habe verschiedene Dinge ausprobiert, um es zum Laufen zu bringen, aber ich hatte nicht viel Glück. Wenn Sie nicht versuchen, es inline zu erstellen, wird es von Chrome heruntergeladen. – Danation

+0

Der einzige Unterschied, den ich mit Content-Disposition gesehen habe, war, dass Sie Chrom als Download angeben, um es herunterzuladen, damit es heruntergeladen wird. – EamonnM

0

Wenn ich eine pdf schreiben, verwende ich eine benutzerdefinierte PdfResult

public class PdfResult : FileResult 
{ 
    private const String DefaultFileName = "file.pdf"; 
    private readonly Byte[] _byteArray; 

    public PdfResult(Byte[] byteArray, String fileName = DefaultFileName) 
     : base(MediaTypeNames.Application.Pdf) 
    { 
     _byteArray = byteArray; 
     FileDownloadName = fileName; 
    } 

    protected override void WriteFile(HttpResponseBase response) { response.BinaryWrite(_byteArray); } 
} 

Ich würde Sie Controller-Aktion ändern, um die PdfResult zu verwenden, in der Bytes der Datei übergeben. Sie können die Bytes mithilfe von File.ReadAllBytes abrufen.

public ActionResult IndirectTestFile() 
{ 
string filename = "document.pdf"; 

var fileBytes = File.ReadAllBytes(Server.MapPath("~/files/direct/" + filename)); 
return new PdfResult(fileBytes, filename); 
} 

Sie zweiter Link

<a href="/Files/direct/Document.pdf">Direct link to file</a> 

funktioniert, weil der Browser direkt beim Lesen der Datei, um die Arbeit zu tun.

+0

Hallo Fran, ich habe Ihren Code versucht, kann aber nicht sagen, ob es funktioniert, wie es Content-Disposition verwendet: Anhang, um einen Download zu erzwingen. Der Download funktioniert einwandfrei und kann angezeigt werden, aber er kann nicht inline angezeigt werden. Kann dies angepasst werden, um inline statt als Anhang zu sein? Ich bin mir nicht sicher, ob es hier viel Unterschied gibt, außer es ist eine andere Möglichkeit, die Datei in den Stream zu laden? – EamonnM

+0

Sie sagen, der Browser lädt den 2. Link direkt - wie ich es verstehe, lädt der Browser beide Links auf genau die gleiche Weise. Entweder lädt der Browser sie beide oder der PDF-Viewer ist. Es macht keinen Sinn, dass der Browser einen herunterladen würde, aber der PDF-Viewer würde den anderen herunterladen. Vielleicht bin ich falsch? – EamonnM

+0

was ich meinte war, dass Ihre erste Verbindung asp.net mvc in der Mitte setzt. Ein Anker-Tag mit einem href zu der exakten Datei wird nicht durch eine Controller-Aktion gehen. also wird ein a-tag interpretiert, aber der browser interpretiert ein a-tag. – Fran