Non è possibile restituire direttamente un file per il download tramite una chiamata AJAX, quindi un approccio alternativo consiste nell'utilizzare una chiamata AJAX per inviare i dati correlati al server. È quindi possibile utilizzare il codice lato server per creare il file Excel (consiglierei di utilizzare EPPlus o NPOI anche se suona come se questa parte funzioni).
AGGIORNAMENTO Settembre 2016
La mia risposta originale (sotto) aveva più di 3 anni, quindi ho pensato di aggiornare poiché non creo più file sul server durante il download di file tramite AJAX, tuttavia, ho lasciato la risposta originale in quanto potrebbe essere di qualche utilità ancora a seconda le vostre esigenze specifiche.
Uno scenario comune nelle mie applicazioni MVC è la creazione di report tramite una pagina Web che ha alcuni parametri di report configurati dall'utente (intervalli di date, filtri, ecc.). Quando l'utente ha specificato i parametri, li inserisce nel server, viene generato il report (ad esempio un file Excel come output) e quindi memorizzo il file risultante come matrice di byte nel TempData
bucket con un riferimento univoco. Questo riferimento viene restituito come risultato Json alla mia funzione AJAX che successivamente reindirizza all'azione separata del controller per estrarre i dati TempData
e scaricarli nel browser degli utenti finali.
Per fornire maggiori dettagli, supponendo che tu abbia una vista MVC che ha un form associato a una classe Model, chiamiamo Model ReportVM
.
Innanzitutto, è necessaria un'azione del controller per ricevere il modello pubblicato, un esempio potrebbe essere:
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" }
};
}
La chiamata AJAX che invia il mio modulo MVC al controller sopra e riceve la risposta ha questo aspetto:
$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;
}
})
L'azione del controller per gestire il download del file:
[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();
}
}
Un altro cambiamento che potrebbe essere facilmente adattato se necessario è passare il tipo MIME del file come terzo parametro in modo che l'azione del controller possa servire correttamente una varietà di formati di file di output.
Ciò elimina la necessità di creare e archiviare file fisici sul server, quindi non sono necessarie routine di pulizia e, ancora una volta, questo è senza soluzione di continuità per l'utente finale.
Nota, il vantaggio di utilizzare TempData
piuttosto che Session
è che una volta TempData
letti i dati vengono cancellati, quindi sarà più efficiente in termini di utilizzo della memoria se si dispone di un volume elevato di richieste di file. Vedere TempData Best Practice .
Risposta ORIGINALE
Non è possibile restituire direttamente un file per il download tramite una chiamata AJAX, quindi un approccio alternativo consiste nell'utilizzare una chiamata AJAX per inviare i dati correlati al server. È quindi possibile utilizzare il codice lato server per creare il file Excel (consiglierei di utilizzare EPPlus o NPOI per questo, anche se sembra che questa parte funzioni).
Una volta che il file è stato creato sul server, restituire il percorso del file (o solo il nome del file) come valore di ritorno alla chiamata AJAX e quindi impostare JavaScript window.location
su questo URL che richiederà al browser di scaricare il file.
Dal punto di vista degli utenti finali, l'operazione di download dei file è semplice poiché non abbandonano mai la pagina in cui ha origine la richiesta.
Di seguito è riportato un semplice esempio artificioso di una chiamata ajax per ottenere ciò:
$.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;
}
});
- Il parametro url è il metodo Controller / Azione in cui il codice creerà il file Excel.
- Il parametro data contiene i dati JSON che verrebbero estratti dal modulo.
- returnValue sarebbe il nome file del file Excel appena creato.
- Il comando window.location reindirizza al metodo Controller / Action che restituisce effettivamente il file per il download.
Un metodo controller di esempio per l'azione Download potrebbe essere:
[HttpGet]
public virtual ActionResult Download(string file)
{
string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
return File(fullPath, "application/vnd.ms-excel", file);
}