Riscontro un problema con l'invio di file archiviati in un database all'utente in ASP.NET MVC. Quello che voglio è una vista che elenca due collegamenti, uno per visualizzare il file e lasciare che il mimetype inviato al browser determini come deve essere gestito e l'altro per forzare un download.
Se scelgo di visualizzare un file chiamato SomeRandomFile.bak
e il browser non ha un programma associato per aprire file di questo tipo, allora non ho problemi con l'impostazione predefinita del comportamento di download. Tuttavia, se scelgo di visualizzare un file chiamato SomeRandomFile.pdf
o SomeRandomFile.jpg
voglio che il file si apra semplicemente. Ma voglio anche mantenere un collegamento di download sul lato in modo da poter forzare un prompt di download indipendentemente dal tipo di file. Questo ha senso?
Ho provato FileStreamResult
e funziona per la maggior parte dei file, il suo costruttore non accetta un nome file per impostazione predefinita, quindi ai file sconosciuti viene assegnato un nome file basato sull'URL (che non conosce l'estensione da fornire in base al tipo di contenuto). Se forzo il nome del file specificandolo, perdo la capacità del browser di aprire direttamente il file e ricevo un prompt per il download. Qualcun altro ha riscontrato questo?
Questi sono gli esempi di ciò che ho provato finora.
//Gives me a download prompt.
return File(document.Data, document.ContentType, document.Name);
//Opens if it is a known extension type, downloads otherwise (download has bogus name and missing extension)
return new FileStreamResult(new MemoryStream(document.Data), document.ContentType);
//Gives me a download prompt (lose the ability to open by default if known type)
return new FileStreamResult(new MemoryStream(document.Data), document.ContentType) {FileDownloadName = document.Name};
Eventuali suggerimenti?
AGGIORNAMENTO:
Questa domanda sembra colpire un accordo con molte persone, quindi ho pensato di pubblicare un aggiornamento. L'avvertimento sulla risposta accettata di seguito che è stato aggiunto da Oskar riguardo ai personaggi internazionali è completamente valido, e l'ho colpito un paio di volte a causa dell'uso della ContentDisposition
classe. Da allora ho aggiornato la mia implementazione per risolvere questo problema. Mentre il codice riportato di seguito proviene dalla mia incarnazione più recente di questo problema in un'app ASP.NET Core (Full Framework), dovrebbe funzionare con modifiche minime in un'applicazione MVC precedente e poiché sto usando la System.Net.Http.Headers.ContentDispositionHeaderValue
classe.
using System.Net.Http.Headers;
public IActionResult Download()
{
Document document = ... //Obtain document from database context
//"attachment" means always prompt the user to download
//"inline" means let the browser try and handle it
var cd = new ContentDispositionHeaderValue("attachment")
{
FileNameStar = document.FileName
};
Response.Headers.Add(HeaderNames.ContentDisposition, cd.ToString());
return File(document.Data, document.ContentType);
}
// an entity class for the document in my database
public class Document
{
public string FileName { get; set; }
public string ContentType { get; set; }
public byte[] Data { get; set; }
//Other properties left out for brevity
}