Ви не можете безпосередньо повернути файл для завантаження через виклик AJAX, тому альтернативний підхід полягає у використанні виклику AJAX для розміщення відповідних даних на вашому сервері. Потім ви можете використовувати серверний код для створення файлу Excel (я б рекомендував використовувати EPPlus або NPOI для цього, хоча це звучить так, ніби у вас ця частина працює).
ОНОВИТИ вересень 2016 р
Моїй оригінальній відповіді (нижче) було понад 3 роки, тому я думав, що оновлюся, оскільки більше не створюю файли на сервері під час завантаження файлів через AJAX, однак я залишив оригінальну відповідь, оскільки вона може бути корисною, як і раніше, залежно від ваші конкретні вимоги.
Поширеним сценарієм у моїх програмах MVC є звітування через веб-сторінку, яка має деякі налаштовані користувачем параметри звітів (діапазони дат, фільтри тощо). Коли користувач вказав параметри, вони публікують їх на сервері, генерується звіт (скажімо, наприклад, файл Excel як вихідний файл), а потім я зберігаю отриманий файл як байтовий масив у TempData
сегменті з унікальним посиланням. Це посилання передається як результат Json на мою функцію AJAX, яка згодом переспрямовує на окрему дію контролера для вилучення даних TempData
та завантаження до браузера кінцевих користувачів.
Щоб надати цю детальнішу інформацію, припускаючи, що у вас є MVC View, який має форму, прив’язану до класу Model, давайте зателефонуємо Model ReportVM
.
По-перше, для отримання опублікованої моделі потрібна дія контролера, прикладом може бути:
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" }
};
}
Виклик 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{
// Problem - Log the error, generate a blank file,
// redirect to another controller action - whatever fits with your application
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);
}