Bạn không thể trực tiếp trả lại tệp để tải xuống thông qua lệnh gọi AJAX, vì vậy, một phương pháp thay thế là sử dụng lệnh gọi AJAX để đăng dữ liệu liên quan lên máy chủ của bạn. Sau đó, bạn có thể sử dụng mã phía máy chủ để tạo Tệp Excel (Tôi khuyên bạn nên sử dụng EPPlus hoặc NPOI cho việc này mặc dù có vẻ như bạn có phần này đang hoạt động).
CẬP NHẬT Tháng 9 năm 2016
Câu trả lời ban đầu của tôi (bên dưới) đã được hơn 3 năm, vì vậy tôi nghĩ rằng tôi sẽ cập nhật vì tôi không còn tạo tệp trên máy chủ khi tải xuống tệp qua AJAX. Tuy nhiên, tôi đã để lại câu trả lời ban đầu vì nó có thể còn được sử dụng tùy thuộc vào yêu cầu cụ thể của bạn.
Một tình huống phổ biến trong các ứng dụng MVC của tôi là báo cáo qua một trang web có một số thông số báo cáo do người dùng định cấu hình (Phạm vi ngày, Bộ lọc, v.v.). Khi người dùng đã chỉ định các tham số mà họ đăng lên máy chủ, báo cáo sẽ được tạo (ví dụ: tệp Excel làm đầu ra) và sau đó tôi lưu trữ tệp kết quả dưới dạng mảng byte trong TempData
nhóm với một tham chiếu duy nhất. Tham chiếu này được chuyển trở lại dưới dạng Kết quả Json cho hàm AJAX của tôi, sau đó chuyển hướng đến hành động của bộ điều khiển riêng biệt để trích xuất dữ liệu từ đó TempData
và tải xuống trình duyệt của người dùng cuối.
Để cung cấp thêm chi tiết này, giả sử bạn có Chế độ xem MVC có biểu mẫu liên kết với một lớp Mô hình, hãy gọi Mô hình ReportVM
.
Đầu tiên, hành động của bộ điều khiển là bắt buộc để nhận được mô hình đã đăng, một ví dụ sẽ là:
public ActionResult PostReportPartial(ReportVM model){
// Validate the Model is correct and contains valid data
// Generate your report output based on the model parameters
// This can be an Excel, PDF, Word file - whatever you need.
// As an example lets assume we've generated an EPPlus ExcelPackage
ExcelPackage workbook = new ExcelPackage();
// Do something to populate your workbook
// Generate a new unique identifier against which the file can be stored
string handle = Guid.NewGuid().ToString();
using(MemoryStream memoryStream = new MemoryStream()){
workbook.SaveAs(memoryStream);
memoryStream.Position = 0;
TempData[handle] = memoryStream.ToArray();
}
// Note we are returning a filename as well as the handle
return new JsonResult() {
Data = new { FileGuid = handle, FileName = "TestReportOutput.xlsx" }
};
}
Lệnh gọi AJAX đăng biểu mẫu MVC của tôi lên bộ điều khiển ở trên và nhận được phản hồi giống như sau:
$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;
}
})
Hành động của trình điều khiển để xử lý việc tải xuống tệp:
[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{
// Problem - Log the error, generate a blank file,
// redirect to another controller action - whatever fits with your application
return new EmptyResult();
}
}
Một thay đổi khác có thể dễ dàng được thực hiện nếu được yêu cầu là chuyển Loại MIME của tệp làm tham số thứ ba để một hành động Bộ điều khiển có thể phân phát chính xác nhiều định dạng tệp đầu ra.
Điều này loại bỏ bất kỳ nhu cầu nào đối với bất kỳ tệp vật lý nào được tạo và lưu trữ trên máy chủ, do đó, không yêu cầu quy trình vệ sinh và một lần nữa, điều này là liền mạch với người dùng cuối.
Lưu ý, lợi thế của việc sử dụng TempData
chứ không phải Session
là một khi TempData
là đọc dữ liệu sẽ bị xóa vì vậy nó sẽ có hiệu quả hơn về mặt sử dụng bộ nhớ nếu bạn có một số lượng lớn các yêu cầu tập tin. Xem Thực hành tốt nhất về TempData .
Câu trả lời GỐC
Bạn không thể trực tiếp trả lại tệp để tải xuống thông qua lệnh gọi AJAX, vì vậy, một phương pháp thay thế là sử dụng lệnh gọi AJAX để đăng dữ liệu liên quan lên máy chủ của bạn. Sau đó, bạn có thể sử dụng mã phía máy chủ để tạo Tệp Excel (Tôi khuyên bạn nên sử dụng EPPlus hoặc NPOI cho việc này mặc dù có vẻ như bạn có phần này đang hoạt động).
Khi tệp đã được tạo trên máy chủ, hãy chuyển lại đường dẫn đến tệp (hoặc chỉ tên tệp) làm giá trị trả về cho lệnh gọi AJAX của bạn và sau đó đặt JavaScript window.location
thành URL này sẽ nhắc trình duyệt tải xuống tệp.
Từ góc độ người dùng cuối, hoạt động tải xuống tệp diễn ra liền mạch vì họ không bao giờ rời khỏi trang bắt nguồn yêu cầu.
Dưới đây là một ví dụ đơn giản theo mô hình của một lệnh gọi ajax để đạt được điều này:
$.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;
}
});
- tham số url là phương thức Bộ điều khiển / Hành động nơi mã của bạn sẽ tạo tệp Excel.
- tham số dữ liệu chứa dữ liệu json sẽ được trích xuất từ biểu mẫu.
- returnValue sẽ là tên tệp của tệp Excel mới được tạo của bạn.
- Lệnh window.location chuyển hướng đến phương thức Controller / Action thực sự trả về tệp của bạn để tải xuống.
Phương thức bộ điều khiển mẫu cho hành động Tải xuống sẽ là:
[HttpGet]
public virtual ActionResult Download(string file)
{
string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
return File(fullPath, "application/vnd.ms-excel", file);
}