Come impostare il download del nome del file nell'API Web ASP.NET


140

Nella mia classe ApiController, ho il seguente metodo per scaricare un file creato dal server.

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

Tutto funziona perfettamente, tranne che il nome del file di download predefinito è il suo ID, quindi l'utente potrebbe dover digitare il proprio nome di file al momento del salvataggio come finestra di dialogo ogni volta. C'è un modo per impostare un nome file predefinito nel codice sopra?


1
puoi condividere il codice che hai usato per chiamare questo metodo?
Yasser Shaikh,

@Yasser - questo è un metodo del controller API Web - probabilmente viene chiamato tramite richieste HTTP che arrivano in IIS e le analizzano e trovano route e API Web che chiamano il metodo (e, naturalmente, vengono anche chiamate dai test).
Dave Rael,

cosa sta succedendo all'interno di GetMyForm ()? Conversione dei file in flusso di byte?
MSIslam,

@MSIslam Sort of. La funzione ottiene informazioni dal modulo dell'utente e crea un file prima di convertirlo nel flusso risultante.
Tae-Sung Shin,

Risposte:


289

È necessario impostare l' Content-Dispositionintestazione su HttpResponseMessage:

HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(result);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileName = "foo.txt"
};

21
Per chiunque sia curioso del tipo di disposizione "allegato", l'elenco completo dei tipi di disposizione è disponibile su iana.org/assignments/cont-disp/cont-disp.xhtml
sfuqua

1
Hai un'altra risposta al download di un file qui. Importa se usi System.Net.Mime.ContentDispositiono ContentDispositionHeaderValue? Uno è più attuale e più preferito dell'altro?
Luminoso

@Luminosa una risposta è per ActionResult, una perHttpResponseMessage
Weston,

@weston la tua risposta non risponde alla mia domanda.
Luminoso

4
@Luminoso "Importa" e "È uno più attuale e più preferito dell'altro?" No e no. Uno è per MVC ActionResulte uno per WebApi HttpResponseMessage.
Weston,

27

MODIFICA: Come menzionato in un commento, la mia risposta non tiene conto dei personaggi che devono essere salvati come a ;. Dovresti usare la risposta accettata da Darin se il tuo nome file potrebbe contenere un punto e virgola.

Aggiungi un Response.AddHeader per impostare il nome del file

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

Cambia FILE_NAME con il nome del file.


2
Ciò si è rivelato utile per me nel risolvere un problema simile alla domanda che si pone. Nel mio caso, ho anche trovato utile cambiare "allegato" in "inline" in modo che IE8 mi darebbe la possibilità di aprire sempre il tipo di file in questione.
Scott,

2
Non copre la fuga. Cosa succede se il nome del file include uno ;o qualcos'altro con un significato speciale?
Sam,

Sam, Al momento in cui ho scritto questa risposta 3 anni fa, non mi ero reso conto che la mia risposta fosse necessaria per gestire la fuga. Grazie per avermelo fatto notare, ho apportato una modifica alla mia risposta spiegando che la mia risposta non tiene conto della fuga. Ma mantenere la mia risposta uguale poiché sembrava aver aiutato le persone.
KingPancake,

8

Se vuoi assicurarti che il nome del file sia codificato correttamente ma eviti anche WebApi HttpResponseMessage puoi usare quanto segue:

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

È possibile utilizzare ContentDisposition o ContentDispositionHeaderValue. Chiamare ToString su un'istanza di uno dei due farà la codifica dei nomi dei file per te.


6

Penso che questo potrebbe esserti utile.

Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName)

4
Non copre la fuga. Cosa succede se il nome del file include uno ;o qualcos'altro con un significato speciale?
Sam,

3

È necessario aggiungere l'intestazione content-disposition alla risposta:

 response.StatusCode = HttpStatusCode.OK;
 response.Content = new StreamContent(result);
 response.AppendHeader("content-disposition", "attachment; filename=" + fileName);
 return response;

3
Non copre la fuga. Cosa succede se il nome del file include uno ;o qualcos'altro con un significato speciale?
Sam,

3

Se stai usando ASP.NET Core MVC, le risposte sopra sono sempre così leggermente modificate ...

Nel mio metodo di azione (che restituisce async Task<JsonResult>) aggiungo la riga (ovunque prima dell'istruzione return):

Response.Headers.Add("Content-Disposition", $"attachment; filename={myFileName}");

Non copre la fuga. Che cosa succede se il nome del file include a; o qualcos'altro con un significato speciale?
KoalaBear il

2

Questo dovrebbe fare:

Response.AddHeader("Content-Disposition", "attachment;filename="+ YourFilename)

2
Non copre la fuga. Cosa succede se il nome del file include uno ;o qualcos'altro con un significato speciale?
Sam,

0

Nota: l'ultima riga è obbligatoria.

Se non specifichiamo Access-Control-Expose-Headers , non otterremo Nome file nell'interfaccia utente.

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

0

Considerando le risposte precedenti, è necessario stare attenti ai personaggi globalizzati.

Supponiamo che il nome del file sia: " Esdrújula prenda ñame - güena.jpg "

Raw risultato per il download: "Esdrújula prenda à ± ame - güena.jpg" [Brutto]

Risultato del codice HTML da scaricare: "Esdr & _250; jula prenda & _241; ame - g & _252; ena.jpg" [Ugly]

UrlEncode risultato da scaricare: " Esdrújula + prenda + ñame + - + güena.jpg " [OK]

Quindi, è quasi sempre necessario utilizzare UrlEncode sul nome del file . Inoltre, se si imposta l'intestazione disposizione-contenuto come stringa diretta, è necessario assicurarsi di racchiudere le virgolette per evitare problemi di compatibilità del browser.

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

o con aiuti di classe:

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

System.Net.Mime. La classe ContentDisposition si occupa delle virgolette.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.