คุณไม่สามารถส่งคืนไฟล์สำหรับดาวน์โหลดโดยตรงผ่านการโทร AJAX ได้อีกวิธีหนึ่งคือการใช้การโทร AJAX เพื่อโพสต์ข้อมูลที่เกี่ยวข้องไปยังเซิร์ฟเวอร์ของคุณ จากนั้นคุณสามารถใช้รหัสฝั่งเซิร์ฟเวอร์เพื่อสร้างไฟล์ Excel (ฉันขอแนะนำให้ใช้ EPPlus หรือ NPOI สำหรับสิ่งนี้แม้ว่าจะฟังดูเหมือนว่าคุณมีส่วนนี้ทำงานอยู่ก็ตาม)
อัพเดทกันยายน 2559
คำตอบเดิมของฉัน (ด้านล่าง) มีอายุมากกว่า 3 ปีฉันจึงคิดว่าฉันจะอัปเดตเนื่องจากฉันไม่ได้สร้างไฟล์บนเซิร์ฟเวอร์อีกต่อไปเมื่อดาวน์โหลดไฟล์ผ่าน AJAX อย่างไรก็ตามฉันได้ทิ้งคำตอบเดิมไว้เนื่องจากอาจยังใช้งานได้อยู่บ้างขึ้นอยู่กับ ความต้องการเฉพาะของคุณ
สถานการณ์ทั่วไปในแอปพลิเคชัน MVC ของฉันคือการรายงานผ่านหน้าเว็บที่มีผู้ใช้กำหนดค่าพารามิเตอร์รายงาน (ช่วงวันที่ตัวกรอง ฯลฯ ) เมื่อผู้ใช้ระบุพารามิเตอร์ที่พวกเขาโพสต์ไปยังเซิร์ฟเวอร์รายงานจะถูกสร้างขึ้น (เช่นไฟล์ Excel เป็นเอาต์พุต) จากนั้นฉันจะจัดเก็บไฟล์ผลลัพธ์เป็นอาร์เรย์ไบต์ในที่TempData
เก็บข้อมูลโดยมีการอ้างอิงเฉพาะ การอ้างอิงนี้ถูกส่งกลับเป็น Json Result ไปยังฟังก์ชัน AJAX ของฉันซึ่งต่อมาจะเปลี่ยนเส้นทางไปยังแอ็คชันคอนโทรลเลอร์แยกต่างหากเพื่อดึงข้อมูลจากTempData
และดาวน์โหลดไปยังเบราว์เซอร์ของผู้ใช้ปลายทาง
หากต้องการให้รายละเอียดเพิ่มเติมสมมติว่าคุณมีมุมมอง MVC ที่มีรูปแบบที่เชื่อมโยงกับคลาส Model ให้เรียก Model ReportVM
ดูที่มีรูปแบบที่ถูกผูกไว้กับชั้นรุ่นช่วยให้เรียกรุ่น
ขั้นแรกต้องมีการดำเนินการของคอนโทรลเลอร์เพื่อรับโมเดลที่โพสต์ตัวอย่างจะเป็น:
public ActionResult PostReportPartial(ReportVM model){
ExcelPackage workbook = new ExcelPackage();
string handle = Guid.NewGuid().ToString();
using(MemoryStream memoryStream = new MemoryStream()){
workbook.SaveAs(memoryStream);
memoryStream.Position = 0;
TempData[handle] = memoryStream.ToArray();
}
return new JsonResult() {
Data = new { FileGuid = handle, FileName = "TestReportOutput.xlsx" }
};
}
การเรียก AJAX ที่โพสต์แบบฟอร์ม MVC ของฉันไปยังคอนโทรลเลอร์ด้านบนและได้รับการตอบกลับมีลักษณะดังนี้
$ajax({
cache: false,
url: '/Report/PostReportPartial',
data: _form.serialize(),
success: function (data){
var response = JSON.parse(data);
window.location = '/Report/Download?fileGuid=' + response.FileGuid
+ '&filename=' + response.FileName;
}
})
การดำเนินการของคอนโทรลเลอร์เพื่อจัดการการดาวน์โหลดไฟล์:
[HttpGet]
public virtual ActionResult Download(string fileGuid, string fileName)
{
if(TempData[fileGuid] != null){
byte[] data = TempData[fileGuid] as byte[];
return File(data, "application/vnd.ms-excel", fileName);
}
else{
return new EmptyResult();
}
}
การเปลี่ยนแปลงอื่น ๆ อีกอย่างหนึ่งที่สามารถรองรับได้อย่างง่ายดายหากจำเป็นคือการส่งผ่านประเภท MIME ของไฟล์เป็นพารามิเตอร์ที่สามเพื่อให้แอ็คชันคอนโทรลเลอร์หนึ่งตัวสามารถรองรับรูปแบบไฟล์เอาต์พุตที่หลากหลายได้อย่างถูกต้อง
ซึ่งจะขจัดความจำเป็นในการสร้างและจัดเก็บไฟล์ฟิสิคัลใด ๆ บนเซิร์ฟเวอร์ดังนั้นจึงไม่จำเป็นต้องมีขั้นตอนการดูแลทำความสะอาดอีกต่อไปสิ่งนี้จะราบรื่นสำหรับผู้ใช้ปลายทาง
หมายเหตุข้อดีของการใช้TempData
มากกว่าSession
คือเมื่อTempData
อ่านข้อมูลจะถูกล้างดังนั้นจะมีประสิทธิภาพมากขึ้นในแง่ของการใช้หน่วยความจำหากคุณมีคำขอไฟล์จำนวนมาก ดูTempData ปฏิบัติที่ดีที่สุด
คำตอบเดิม
คุณไม่สามารถส่งคืนไฟล์สำหรับดาวน์โหลดโดยตรงผ่านการโทร AJAX ได้อีกวิธีหนึ่งคือการใช้การโทร AJAX เพื่อโพสต์ข้อมูลที่เกี่ยวข้องไปยังเซิร์ฟเวอร์ของคุณ จากนั้นคุณสามารถใช้รหัสฝั่งเซิร์ฟเวอร์เพื่อสร้างไฟล์ Excel (ฉันขอแนะนำให้ใช้ EPPlus หรือ NPOI สำหรับสิ่งนี้แม้ว่าจะฟังดูเหมือนว่าคุณมีส่วนนี้ทำงานอยู่ก็ตาม)
เมื่อไฟล์ถูกสร้างขึ้นบนเซิร์ฟเวอร์แล้วให้ส่งกลับเส้นทางไปยังไฟล์ (หรือเพียงแค่ชื่อไฟล์) เป็นค่าส่งคืนไปยังการเรียก AJAX ของคุณจากนั้นตั้งค่า JavaScript window.location
เป็น URL นี้ซึ่งจะแจ้งให้เบราว์เซอร์ดาวน์โหลดไฟล์
จากมุมมองของผู้ใช้ปลายทางการดำเนินการดาวน์โหลดไฟล์จะราบรื่นเนื่องจากพวกเขาไม่เคยออกจากหน้าที่มีการร้องขอ
ด้านล่างนี้เป็นตัวอย่างง่ายๆของการเรียก ajax เพื่อให้บรรลุสิ่งนี้:
$.ajax({
type: 'POST',
url: '/Reports/ExportMyData',
data: '{ "dataprop1": "test", "dataprop2" : "test2" }',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (returnValue) {
window.location = '/Reports/Download?file=' + returnValue;
}
});
- urlพารามิเตอร์คือวิธีการควบคุม / การดำเนินการที่โค้ดของคุณจะสร้างไฟล์ Excel
- พารามิเตอร์dataมีข้อมูล json ที่จะดึงออกมาจากฟอร์ม
- returnValueจะเป็นชื่อไฟล์ของไฟล์ Excel ที่คุณสร้างขึ้นใหม่
- window.locationคำสั่งเปลี่ยนเส้นทางไปที่วิธีการควบคุม / การกระทำที่จริงส่งไฟล์ของคุณสำหรับการดาวน์โหลด
วิธีการควบคุมตัวอย่างสำหรับการดำเนินการดาวน์โหลดคือ:
[HttpGet]
public virtual ActionResult Download(string file)
{
string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
return File(fullPath, "application/vnd.ms-excel", file);
}