วิธีตั้งค่าการดาวน์โหลดชื่อไฟล์ใน ASP.NET Web API


140

ในคลาส ApiController ของฉันฉันมีวิธีการดังต่อไปนี้เพื่อดาวน์โหลดไฟล์ที่สร้างโดยเซิร์ฟเวอร์

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

ทุกอย่างทำงานได้อย่างสมบูรณ์แบบยกเว้นชื่อไฟล์เริ่มต้นที่ดาวน์โหลดเป็นรหัสของมันดังนั้นผู้ใช้อาจต้องพิมพ์ชื่อไฟล์ของตัวเองเมื่อทำการบันทึกในแต่ละครั้ง มีวิธีการตั้งชื่อไฟล์เริ่มต้นในรหัสด้านบนหรือไม่


1
คุณสามารถแบ่งปันรหัสที่คุณใช้เรียกวิธีการนี้ได้หรือไม่
Yasser Shaikh

@Yasser - นี่เป็นวิธีการควบคุมเว็บ API - มันอาจถูกเรียกผ่านคำขอ HTTP ที่เข้ามาใน IIS และแยกวิเคราะห์และค้นหาเส้นทางและเว็บ API เรียกวิธี (และแน่นอนมันถูกเรียกโดยการทดสอบ)
Dave Rael

เกิดอะไรขึ้นภายใน GetMyForm () กำลังแปลงไฟล์เป็นสตรีมของไบต์?
MSIslam

@MSIslam ประเภทของ ฟังก์ชันรับข้อมูลจากฟอร์มของผู้ใช้และสร้างไฟล์ก่อนที่จะแปลงเป็นผลลัพธ์
แทซองชิน

คำตอบ:


289

คุณต้องตั้งค่าContent-Dispositionส่วนหัวใน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
สำหรับทุกคนที่สงสัยเกี่ยวกับประเภทการจัดการ "สิ่งที่แนบมา" รายการประเภทการจัดการทั้งหมดอยู่ที่iana.org/assignments/cont-disp/cont-disp.xhtml iana.org
sfuqua

1
คุณมีคำตอบอื่นสำหรับการดาวน์โหลดไฟล์ที่นี่ ไม่ว่าคุณจะใช้System.Net.Mime.ContentDispositionหรือContentDispositionHeaderValueไม่? เป็นหนึ่งในปัจจุบันและเป็นที่ต้องการมากกว่าอีกหรือไม่
ส่องสว่าง

@Luminous คำตอบหนึ่งที่ActionResultหนึ่งสำหรับHttpResponseMessage
เวสตัน

@ เมื่อการตอบกลับของคุณไม่ตอบคำถามของฉัน
การส่องสว่าง

4
@ จำนวนมาก "มันมีความสำคัญ" และ "เป็นหนึ่งในปัจจุบันและเป็นที่ต้องการมากกว่าที่อื่น ๆ " ไม่และไม่ หนึ่งคือการ MVC ActionResults และหนึ่งสำหรับ WebAPI HttpResponseMessages
weston

27

แก้ไข: ;ตามที่ระบุไว้ในความคิดเห็นคำตอบของฉันไม่บัญชีสำหรับตัวละครที่จะต้องหนีออกมาเหมือน คุณควรใช้คำตอบที่ยอมรับได้ของดารินหากชื่อไฟล์ของคุณมีเซมิโคลอน

เพิ่ม Response.AddHeader เพื่อตั้งชื่อไฟล์

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

เพียงเปลี่ยน FILE_NAME เป็นชื่อไฟล์


2
สิ่งนี้พิสูจน์แล้วว่ามีประโยชน์สำหรับฉันในการแก้ปัญหาที่คล้ายกันกับผู้ถามคำถาม ในกรณีของฉันฉันยังพบว่ามีประโยชน์ในการเปลี่ยน "สิ่งที่แนบมา" เป็น "อินไลน์" ดังนั้น IE8 จะให้ตัวเลือกแก่ฉันในการเปิดประเภทไฟล์ที่เป็นปัญหาเสมอ
สกอตต์

2
ไม่ครอบคลุมถึงการหลบหนี ถ้าชื่อไฟล์มี;หรืออย่างอื่นที่มีความหมายพิเศษล่ะ?
Sam

แซมในขณะที่ฉันเขียนคำตอบนี้ 3 ปีที่ผ่านมาฉันไม่ได้ตระหนักถึงคำตอบของฉันที่จำเป็นในการจัดการหนี ขอบคุณสำหรับการชี้ให้ฉันเห็นฉันแก้ไขคำตอบของฉันเพื่ออธิบายคำตอบของฉันไม่ได้หมายความว่าจะหนีไปไหน แต่การรักษาคำตอบของฉันเหมือนกันเพราะดูเหมือนจะช่วยคน
KingPancake

8

หากคุณต้องการให้แน่ใจว่าชื่อไฟล์นั้นได้รับการเข้ารหัสอย่างถูกต้อง แต่ยังหลีกเลี่ยง WebApi HttpResponseMessage คุณสามารถใช้สิ่งต่อไปนี้:

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

คุณสามารถใช้ ContentDisposition หรือ ContentDispositionHeaderValue การเรียกใช้ ToString บนอินสแตนซ์ของทั้งสองอย่างจะทำการเข้ารหัสชื่อไฟล์ให้คุณ


6

ฉันคิดว่านี่อาจเป็นประโยชน์กับคุณ

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

4
ไม่ครอบคลุมถึงการหลบหนี ถ้าชื่อไฟล์มี;หรืออย่างอื่นที่มีความหมายพิเศษล่ะ?
Sam

3

คุณต้องเพิ่มหัวข้อการจัดการเนื้อหาลงในการตอบกลับ:

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

3
ไม่ครอบคลุมถึงการหลบหนี ถ้าชื่อไฟล์มี;หรืออย่างอื่นที่มีความหมายพิเศษล่ะ?
Sam

3

หากคุณใช้ ASP.NET Core MVC คำตอบข้างต้นจะเปลี่ยนไปเล็กน้อย ...

ในวิธีการกระทำของฉัน (ซึ่งคืนค่าasync Task<JsonResult>) ฉันเพิ่มบรรทัด (ที่ใดก็ได้ก่อนหน้าคำสั่ง return):

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

ไม่ครอบคลุมถึงการหลบหนี เกิดอะไรขึ้นถ้าชื่อไฟล์รวมถึง; หรืออย่างอื่นที่มีความหมายพิเศษ
KoalaBear

2

สิ่งนี้ควรทำ:

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

2
ไม่ครอบคลุมถึงการหลบหนี จะทำอย่างไรถ้าชื่อไฟล์มี;หรืออย่างอื่นที่มีความหมายพิเศษ
Sam

0

หมายเหตุ: บรรทัดสุดท้ายเป็นข้อบังคับ

หากเราไม่ได้ระบุAccess-Control-Expose-Headersเราจะไม่ได้รับชื่อไฟล์ใน 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");

0

เมื่อพิจารณาถึงคำตอบก่อนหน้านี้จำเป็นต้องระมัดระวังตัวละครที่เป็นสากล

สมมติว่าชื่อของไฟล์คือ: " Esdrújula prenda ñame - güena.jpg "

ผลการดาวน์โหลดดิบ : "Esdrújula prenda ñ ame - güena.jpg" [Ugly]

ผลลัพธ์ HtmlEncodeให้ดาวน์โหลด: "Esdr & _250; jula prenda & _241; ame - g & _252; ena.jpg" [Ugly]

UrlEncode ผลการดาวน์โหลด: " Esdrújula + prenda + ñame + - + güena.jpg " [OK]

จากนั้นคุณต้องใช้ UrlEncode เหนือชื่อไฟล์เกือบทุกครั้ง นอกจากนี้หากคุณตั้งค่าส่วนหัว content-disposition เป็นสตริงโดยตรงคุณต้องตรวจสอบให้แน่ใจว่ามีเครื่องหมายคำพูดล้อมรอบเพื่อหลีกเลี่ยงปัญหาความเข้ากันได้ของเบราว์เซอร์

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

หรือด้วยความช่วยเหลือในชั้นเรียน:

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

The System.Net.Mime คลาสContentDispositionดูแลราคา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.