Mam problem z wysyłaniem plików przechowywanych w bazie danych z powrotem do użytkownika w ASP.NET MVC. To, czego chcę, to widok z listą dwóch linków, z których jeden służy do wyświetlania pliku i pozwala typowi mimetalnemu wysłanemu do przeglądarki określić, jak powinien być obsługiwany, a drugi do wymuszenia pobrania.
Jeśli zdecyduję się wyświetlić plik o nazwie, SomeRandomFile.bak
a przeglądarka nie ma powiązanego programu do otwierania plików tego typu, nie mam problemu z domyślnym zachowaniem pobierania. Jeśli jednak zdecyduję się wyświetlić plik o nazwie SomeRandomFile.pdf
lub SomeRandomFile.jpg
chcę go po prostu otworzyć. Ale chcę też zachować odsyłacz pobierania z boku, aby móc wymusić monit o pobranie niezależnie od typu pliku. Czy to ma sens?
Próbowałem FileStreamResult
i działa dla większości plików, jego konstruktor domyślnie nie akceptuje nazwy pliku, więc nieznanym plikom przypisuje się nazwę pliku na podstawie adresu URL (który nie zna rozszerzenia, które można podać na podstawie typu zawartości). Jeśli wymuszę nazwę pliku, określając go, tracę możliwość bezpośredniego otwarcia pliku przez przeglądarkę i pojawia się monit o pobranie. Czy ktoś jeszcze tego doświadczył?
To są przykłady tego, czego do tej pory próbowałem.
//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};
Jakieś sugestie?
AKTUALIZACJA:
To pytanie wydaje się uderzać w wielu ludzi, więc pomyślałem, że opublikuję aktualizację. Ostrzeżenie dotyczące zaakceptowanej odpowiedzi poniżej, które zostało dodane przez Oskara w odniesieniu do znaków międzynarodowych, jest całkowicie ważne i trafiłem go kilka razy z powodu korzystania z ContentDisposition
klasy. Od tego czasu zaktualizowałem moją implementację, aby to naprawić. Chociaż poniższy kod pochodzi z mojego ostatniego wcielenia tego problemu w aplikacji ASP.NET Core (Full Framework), powinien on również działać przy minimalnych zmianach w starszej aplikacji MVC, ponieważ używam tej System.Net.Http.Headers.ContentDispositionHeaderValue
klasy.
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
}