Nie możesz bezpośrednio zwrócić pliku do pobrania za pośrednictwem wywołania AJAX, więc alternatywnym podejściem jest użycie wywołania AJAX do opublikowania powiązanych danych na serwerze. Następnie możesz użyć kodu po stronie serwera, aby utworzyć plik Excel (zalecałbym do tego użycie EPPlus lub NPOI, chociaż brzmi to tak, jakbyś miał tę część działającą).
UPDATE wrzesień 2016
Moja pierwotna odpowiedź (poniżej) miała ponad 3 lata, więc pomyślałem, że zaktualizuję, ponieważ nie tworzę już plików na serwerze podczas pobierania plików przez AJAX, jednak zostawiłem oryginalną odpowiedź, ponieważ może to być nadal przydatne w zależności od Twoje specyficzne wymagania.
Typowym scenariuszem w moich aplikacjach MVC jest raportowanie za pośrednictwem strony internetowej, która ma skonfigurowane przez użytkownika parametry raportu (zakresy dat, filtry itp.). Gdy użytkownik określi parametry, które wysyła na serwer, generowany jest raport (np. Plik Excela jako dane wyjściowe), a następnie przechowuję wynikowy plik jako tablicę bajtów w TempData
zasobniku z unikalnym odniesieniem. To odwołanie jest przekazywane z powrotem jako wynik Json do mojej funkcji AJAX, która następnie przekierowuje do oddzielnej akcji kontrolera w celu wyodrębnienia danych z TempData
przeglądarki użytkowników końcowych i pobrania ich do przeglądarki.
Aby podać więcej szczegółów, zakładając, że masz widok MVC, który ma formularz powiązany z klasą Model, wywołajmy Model ReportVM
.
Po pierwsze, aby otrzymać przesłany model, wymagana jest akcja kontrolera, przykładem może być:
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" }
};
}
Wywołanie AJAX, które wysyła mój formularz MVC do powyższego kontrolera i odbiera odpowiedź, wygląda następująco:
$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;
}
})
Akcja kontrolera obsługująca pobieranie pliku:
[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();
}
}
Inną zmianą, którą można łatwo wprowadzić w razie potrzeby, jest przekazanie typu MIME pliku jako trzeciego parametru, aby jedna akcja kontrolera mogła poprawnie obsługiwać różne formaty plików wyjściowych.
Eliminuje to potrzebę tworzenia i przechowywania jakichkolwiek plików fizycznych na serwerze, więc nie są wymagane żadne procedury porządkowe i po raz kolejny jest to bezproblemowe dla użytkownika końcowego.
Zwróć uwagę, że zaletą używania TempData
zamiast Session
jest to, że po TempData
odczytaniu dane są usuwane, więc będzie bardziej wydajne pod względem wykorzystania pamięci, jeśli masz dużą liczbę żądań plików. Zobacz najlepsze praktyki TempData .
ORYGINALNA odpowiedź
Nie możesz bezpośrednio zwrócić pliku do pobrania za pośrednictwem wywołania AJAX, więc alternatywnym podejściem jest użycie wywołania AJAX w celu opublikowania powiązanych danych na serwerze. Następnie możesz użyć kodu po stronie serwera, aby utworzyć plik Excel (zalecałbym użycie do tego EPPlus lub NPOI, chociaż brzmi to tak, jakbyś miał tę część działającą).
Gdy plik zostanie utworzony na serwerze, przekaż ścieżkę do pliku (lub tylko nazwę pliku) jako wartość zwracaną do wywołania AJAX, a następnie ustaw JavaScript window.location
na ten adres URL, co spowoduje, że przeglądarka pobierze plik.
Z punktu widzenia użytkowników końcowych operacja pobierania plików przebiega bezproblemowo, ponieważ nigdy nie opuszczają oni strony, z której pochodzi żądanie.
Poniżej znajduje się prosty wymyślony przykład wywołania AJAX, aby to osiągnąć:
$.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 to metoda kontrolera / akcji, w której kod utworzy plik Excel.
- parametr data zawiera dane json, które zostaną wyodrębnione z formularza.
- returnValue będzie nazwą pliku nowo utworzonego pliku Excel.
- Polecenie window.location przekierowuje do metody kontrolera / akcji, która w rzeczywistości zwraca plik do pobrania.
Przykładowa metoda kontrolera dla akcji Download to:
[HttpGet]
public virtual ActionResult Download(string file)
{
string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
return File(fullPath, "application/vnd.ms-excel", file);
}