So legen Sie den Namen der Download-Datei in der ASP.NET-Web-API fest

140

In meiner ApiController-Klasse habe ich folgende Methode, um eine vom Server erstellte Datei herunterzuladen.

public HttpResponseMessage Get(int id)
{
    try
    {
        string dir = HttpContext.Current.Server.MapPath("~"); //location of the template file
        Stream file = new MemoryStream();
        Stream result = _service.GetMyForm(id, dir, file);
        if (result == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        result.Position = 0;
        HttpResponseMessage response = new HttpResponseMessage();
        response.StatusCode = HttpStatusCode.OK;
        response.Content = new StreamContent(result);
        return response;
    }
    catch (IOException)
    {
        return Request.CreateResponse(HttpStatusCode.InternalServerError);
    }
}

Alles funktioniert einwandfrei, außer dass der Standardname für das Herunterladen der Datei die ID ist, sodass der Benutzer möglicherweise jedes Mal beim Speichern als Dialog seinen eigenen Dateinamen eingeben muss. Gibt es eine Möglichkeit, einen Standarddateinamen im obigen Code festzulegen?

Tae-Sung Shin
quelle
1
Können Sie den Code freigeben, mit dem Sie diese Methode aufgerufen haben?
Yasser Shaikh
@Yasser - dies ist eine Web-API-Controller-Methode - sie wird wahrscheinlich über HTTP-Anforderungen aufgerufen, die in IIS eingehen und diese analysieren und Routen und Web-APIs finden, die die Methode aufrufen (und natürlich auch durch Tests aufgerufen werden).
Dave Rael
Was passiert in GetMyForm ()? Die Dateien in einen Bytestrom konvertieren?
MSIslam
@MSIslam Art von. Die Funktion ruft Informationen aus dem Benutzerformular ab und erstellt eine Datei, bevor sie in den resultierenden Stream konvertiert.
Tae-Sung Shin

Antworten:

288

Sie müssen den Content-DispositionHeader auf Folgendes setzen HttpResponseMessage:

HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(result);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileName = "foo.txt"
};
Darin Dimitrov
quelle
21
Für alle, die neugierig auf den Dispositionstyp "Anhang" sind, finden Sie die vollständige Liste der Dispositionstypen unter iana.org/assignments/cont-disp/cont-disp.xhtml
sfuqua
1
Sie haben hier eine andere Antwort auf das Herunterladen einer Datei. Ist es wichtig, ob Sie System.Net.Mime.ContentDispositionoder verwenden ContentDispositionHeaderValue? Ist einer aktueller und bevorzugter als der andere?
Leuchtend
@ Leuchtend ist eine Antwort für ActionResult, eine fürHttpResponseMessage
Weston
@weston Ihre Antwort beantwortet nicht meine Frage.
Leuchtend
4
@Luminous "Ist das wichtig" und "Ist einer aktueller und bevorzugter als der andere?" Nein und nein. Eine ist ActionResultfür MVCs und eine für WebApis HttpResponseMessage.
Weston
27

BEARBEITEN: Wie in einem Kommentar erwähnt, berücksichtigt meine Antwort keine Zeichen, die wie a maskiert werden müssen ;. Sie sollten die akzeptierte Antwort von Darin verwenden, wenn Ihr Dateiname ein Semikolon enthalten könnte.

Fügen Sie einen Response.AddHeader hinzu, um den Dateinamen festzulegen

Response.AddHeader("Content-Disposition", "attachment; filename=*FILE_NAME*");

Ändern Sie einfach FILE_NAME in den Namen der Datei.

KingPancake
quelle
2
Dies erwies sich für mich als hilfreich bei der Lösung eines ähnlichen Problems wie der Fragesteller. In meinem Fall fand ich es auch nützlich, "Anhang" in "Inline" zu ändern, damit IE8 mir die Möglichkeit gibt, den betreffenden Dateityp immer zu öffnen.
Scott
2
Deckt nicht die Flucht ab. Was ist, wenn der Dateiname ein ;oder etwas anderes mit einer besonderen Bedeutung enthält?
Sam
Sam, Als ich diese Antwort vor 3 Jahren schrieb, wusste ich nicht, dass meine Antwort für die Flucht benötigt wurde. Vielen Dank, dass Sie mich darauf hingewiesen haben. Ich habe meine Antwort bearbeitet und erklärt, dass meine Antwort nicht für das Entkommen verantwortlich ist. Aber meine Antwort gleich zu halten, da sie den Menschen geholfen zu haben schien.
KingPancake
8

Wenn Sie sicherstellen möchten, dass der Dateiname ordnungsgemäß codiert ist, aber auch die WebApi HttpResponseMessage vermeiden möchten, können Sie Folgendes verwenden:

Response.AddHeader("Content-Disposition", new System.Net.Mime.ContentDisposition("attachment") { FileName = "foo.txt" }.ToString());

Sie können entweder ContentDisposition oder ContentDispositionHeaderValue verwenden. Wenn Sie ToString für eine der beiden Instanzen aufrufen, werden die Dateinamen für Sie codiert.

sorenhk
quelle
6

Ich denke, dass dies für Sie hilfreich sein könnte.

Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName)
Jarek
quelle
4
Deckt nicht die Flucht ab. Was ist, wenn der Dateiname ein ;oder etwas anderes mit einer besonderen Bedeutung enthält?
Sam
3

Sie müssen der Antwort den Header für die Inhaltsdisposition hinzufügen:

 response.StatusCode = HttpStatusCode.OK;
 response.Content = new StreamContent(result);
 response.AppendHeader("content-disposition", "attachment; filename=" + fileName);
 return response;
Carl Raymond
quelle
3
Deckt nicht die Flucht ab. Was ist, wenn der Dateiname ein ;oder etwas anderes mit einer besonderen Bedeutung enthält?
Sam
3

Wenn Sie ASP.NET Core MVC verwenden, werden die obigen Antworten geringfügig geändert ...

In meiner Aktionsmethode (die zurückgibt async Task<JsonResult>) füge ich die Zeile hinzu (irgendwo vor der return-Anweisung):

Response.Headers.Add("Content-Disposition", $"attachment; filename={myFileName}");
Peter
quelle
Deckt nicht die Flucht ab. Was ist, wenn der Dateiname a enthält? oder etwas anderes mit einer besonderen Bedeutung?
KoalaBear
2

Dies sollte tun:

Response.AddHeader("Content-Disposition", "attachment;filename="+ YourFilename)
Tucaz
quelle
2
Deckt nicht die Flucht ab. Was ist, wenn der Dateiname ein ;oder etwas anderes mit einer besonderen Bedeutung enthält?
Sam
0

Hinweis: Die letzte Zeile ist obligatorisch.

Wenn wir keine Access-Control-Expose-Header angegeben haben , erhalten wir keinen Dateinamen in der Benutzeroberfläche.

FileInfo file = new FileInfo(FILEPATH);

HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileName = file.Name
};
response.Content.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
Chandan YS
quelle
0

In Anbetracht der vorherigen Antworten ist es notwendig, mit globalisierten Zeichen vorsichtig zu sein.

Angenommen, der Name der Datei lautet: " Esdrújula prenda ñame - güena.jpg "

Rohes Ergebnis zum Download: "Esdrújula prenda à ± ame - güena.jpg" [Hässlich]

HtmlEncode-Ergebnis zum Herunterladen: "Esdr & _250; jula prenda & _241; ame - g & _252; ena.jpg" [Ugly]

UrlEncode-Ergebnis zum Herunterladen: " Esdrújula + prenda + ñame + - + güena.jpg " [OK]

Dann müssen Sie fast immer den UrlEncode über dem Dateinamen verwenden . Wenn Sie den Header für die Inhaltsdisposition als direkte Zeichenfolge festlegen, müssen Sie außerdem Surround mit Anführungszeichen sicherstellen , um Probleme mit der Browserkompatibilität zu vermeiden.

Response.AddHeader("Content-Disposition", $"attachment; filename=\"{HttpUtility.UrlEncode(YourFilename)}\"");

oder mit Klassenhilfe:

var cd = new ContentDisposition("attachment") { FileName = HttpUtility.UrlEncode(resultFileName) };
Response.AddHeader("Content-Disposition", cd.ToString());

Die System.Net.Mime. Die ContentDisposition- Klasse kümmert sich um Anführungszeichen.

Asereware
quelle