Cara mengatur pengunduhan nama file di ASP.NET Web API

140

Di kelas ApiController saya, saya memiliki metode berikut untuk mengunduh file yang dibuat oleh 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);
    }
}

Semuanya berfungsi dengan baik kecuali bahwa nama file unduhan default adalah id sehingga pengguna mungkin harus mengetikkan nama file sendiri di save as dialog setiap kali. Apakah ada cara untuk menetapkan nama file default dalam kode di atas?

Tae-Sung Shin
sumber
1
dapatkah Anda membagikan kode yang Anda gunakan untuk memanggil metode ini?
Yasser Shaikh
@ Yasser - ini adalah metode pengontrol API web - mungkin dipanggil melalui permintaan HTTP yang masuk ke IIS dan menguraikannya dan menemukan rute dan API web yang memanggil metode (dan, tentu saja, itu juga dipanggil dengan tes).
Dave Rael
apa yang terjadi di dalam GetMyForm ()? Mengubah file menjadi aliran byte?
MSIslam
@MSIslam Sortir dari. Fungsi mendapatkan informasi dari formulir pengguna dan membuat file sebelum mengkonversi ke aliran yang dihasilkan.
Tae-Sung Shin

Jawaban:

289

Anda perlu mengatur Content-Dispositiontajuk pada 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
sumber
21
Bagi siapa pun yang penasaran dengan tipe disposisi "lampiran", daftar lengkap tipe disposisi ada di iana.org/assignments/cont-disp/cont-disp.xhtml
sfuqua
1
Anda punya jawaban lain untuk mengunduh file di sini. Apakah penting apakah Anda menggunakan System.Net.Mime.ContentDispositionatau ContentDispositionHeaderValue? Apakah yang satu lebih terkini dan lebih disukai daripada yang lain?
Luminous
@Luminous satu jawaban adalah untuk ActionResult, satu untukHttpResponseMessage
barat
@ Barat pada respons Anda tidak menjawab pertanyaan saya.
Luminous
4
@ Luminous "Apakah itu penting" dan "Apakah yang satu lebih terkini dan lebih disukai daripada yang lain?" Tidak, dan tidak. Satu untuk MVC ActionResult, dan satu untuk WebApi HttpResponseMessage.
barat
27

EDIT: Seperti yang disebutkan dalam komentar, Jawaban saya tidak memperhitungkan karakter yang perlu melarikan diri seperti a ; . Anda harus menggunakan jawaban yang diterima yang dibuat oleh Darin jika nama file Anda dapat berisi tanda titik dua.

Tambahkan Response.AddHeader untuk mengatur nama file

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

Ubah saja FILE_NAME ke nama file.

KingPancake
sumber
2
Ini terbukti membantu saya dalam menyelesaikan masalah yang serupa dengan penanya pertanyaan. Dalam kasus saya, saya juga merasa berguna untuk mengubah "lampiran" menjadi "inline" sehingga IE8 akan memberi saya opsi untuk selalu membuka jenis file yang dimaksud.
Scott
2
Tidak mencakup pelarian. Bagaimana jika nama file menyertakan ;atau sesuatu yang lain dengan makna khusus?
Sam
Sam, Pada saat saya menulis jawaban ini 3 tahun yang lalu saya tidak menyadari jawaban saya perlu menangani melarikan diri. Terima kasih telah menunjukkan ini kepada saya, saya mengedit jawaban saya menjelaskan jawaban saya tidak masuk akal untuk melarikan diri. Tetapi menjaga jawaban saya tetap sama karena tampaknya telah membantu orang.
KingPancake
8

Jika Anda ingin memastikan bahwa nama file dikodekan dengan benar tetapi juga menghindari WebApi HttpResponseMessage Anda dapat menggunakan yang berikut ini:

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

Anda dapat menggunakan ContentDisposition atau ContentDispositionHeaderValue. Memanggil ToString pada instance dari keduanya akan melakukan pengodean nama file untuk Anda.

Sorenhk
sumber
6

Saya pikir ini mungkin membantu Anda.

Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName)
Jarek
sumber
4
Tidak mencakup pelarian. Bagaimana jika nama file menyertakan ;atau sesuatu yang lain dengan makna khusus?
Sam
3

Anda perlu menambahkan header disposisi konten ke respons:

 response.StatusCode = HttpStatusCode.OK;
 response.Content = new StreamContent(result);
 response.AppendHeader("content-disposition", "attachment; filename=" + fileName);
 return response;
Carl Raymond
sumber
3
Tidak mencakup pelarian. Bagaimana jika nama file menyertakan ;atau sesuatu yang lain dengan makna khusus?
Sam
3

Jika Anda menggunakan ASP.NET Core MVC, jawaban di atas sedikit berubah ...

Dalam metode tindakan saya (yang mengembalikan async Task<JsonResult>) saya menambahkan baris (di mana saja sebelum pernyataan pengembalian):

Response.Headers.Add("Content-Disposition", $"attachment; filename={myFileName}");
Peter
sumber
Tidak mencakup pelarian. Bagaimana jika nama file termasuk; atau sesuatu yang lain dengan makna khusus?
KoalaBear
2

Ini harus dilakukan:

Response.AddHeader("Content-Disposition", "attachment;filename="+ YourFilename)
tucaz
sumber
2
Tidak mencakup pelarian. Bagaimana jika nama file menyertakan ;atau sesuatu yang lain dengan makna khusus?
Sam
0

Catatan: Baris terakhir adalah wajib.

Jika kami tidak menentukan Access-Control-Expose-Header , kami tidak akan mendapatkan Nama File di UI.

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
sumber
0

Mempertimbangkan jawaban sebelumnya, perlu berhati-hati dengan karakter yang terglobalisasi.

Misalkan nama file tersebut adalah: " Esdrújula prenda ñame - güena.jpg "

Hasil mentah untuk diunduh: "Esra jula prenda à ± ame - güena.jpg" [Jelek]

HtmlEncode hasil unduhan: "Esdr & _250; jula prenda & _241; ame - g & _252; ena.jpg" [Jelek]

Hasil urlEncode untuk diunduh: " Esdrújula + prenda + ñame + - + güena.jpg " [OK]

Kemudian, Anda hampir selalu perlu menggunakan UrlEncode di atas nama file . Selain itu, jika Anda mengatur header disposisi konten sebagai string langsung, maka Anda perlu memastikan surround dengan tanda kutip untuk menghindari masalah kompatibilitas browser.

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

atau dengan bantuan kelas:

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

System.Net.Mime. Kelas ContentDisposition menangani penawaran.

Asereware
sumber