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
}
źródło
Inline = true
upewnij się, że NIE użyjesz przeciążenia 3-param,File()
który przyjmuje nazwę pliku jako 3. parametr. To będzie pracować w IE, ale Chrome zgłosi duplikat nagłówek i odmawiają przedstawienia obrazu.Miałem problem z zaakceptowaną odpowiedzią z powodu braku podpowiedzi typu w zmiennej „document”:
var document = ...
Więc zamieszczam to, co działało dla mnie jako alternatywę na wypadek, gdyby ktokolwiek miał problemy.źródło
AppDomain.CurrentDomain.BaseDirectory
jest toSystem.Web.HttpContext.Current.Server.MapPath("~")
, że może działać lepiej na prawdziwym serwerze w porównaniu do komputera lokalnego.Odpowiedź Darina Dimitrowa jest poprawna. Tylko dodatek:
Response.AppendHeader("Content-Disposition", cd.ToString());
może spowodować, że przeglądarka nie wyświetli pliku, jeśli Twoja odpowiedź zawiera już nagłówek „Content-Disposition”. W takim przypadku możesz użyć:źródło
pdf
plik, jeśli ustawię typ zawartości jakoSystem.Net.Mime.MediaTypeNames.Application.Octet
, wymusi pobranie nawet wtedy, gdy ustawięInline = true
, ale jeśli ustawię jakoResponse.ContentType = MimeMapping.GetMimeMapping(filePath)
, to znaczyapplication/pdf
, że można go poprawnie otworzyć, a nie pobraćResponse.Headers.Add
wymagają zintegrowanego trybu potokowego IIS. Dodatkowo, nawet jeśli pula aplikacji jest ustawiona jako zintegrowana, wygeneruje wyjątek. Rozwiązanie. ZastosowanieResponse.AddHeader
. Zobacz temat SO: stackoverflow.com/questions/22313167/…Aby wyświetlić plik (na przykład txt):
Aby pobrać plik (na przykład txt):
Uwaga: aby pobrać plik, należy przekazać argument fileDownloadName
źródło
Inline
właściwości w Content-Disposition pozwala mi oddzielić możliwość ustawiania nazwy pliku od zachowania wymuszającego pobieranie lub nie.Uważam, że ta odpowiedź jest bardziej przejrzysta (na podstawie https://stackoverflow.com/a/3007668/550975 )
źródło
application/octet-stream
i to wciąż spowodowało, że plik został pobrany, a nie pokazany, i wydaje się być zgodny.FileVirtualPath -> Research \ Global Office Review.pdf
źródło
Poniższy kod działał dla mnie w celu pobrania pliku pdf z usługi API i wysłania go do przeglądarki - mam nadzieję, że to pomoże;
źródło
Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider
Metoda akcji musi zwrócić FileResult ze strumieniem, bajtem [] lub wirtualną ścieżką pliku. Będziesz także musiał znać typ zawartości pobieranego pliku. Oto przykładowa (szybka / brudna) metoda narzędzia. Przykładowy link wideo Jak pobierać pliki za pomocą asp.net core
źródło
Jeśli, podobnie jak ja, przyszedłeś do tego tematu za pomocą komponentów Razor, ucząc się Blazora, musisz pomyśleć nieco więcej, aby rozwiązać ten problem. To trochę pole minowe, jeśli (tak jak ja) Blazor jest twoim pierwszym wcieleniem do świata typu MVC, ponieważ dokumentacja nie jest tak pomocna dla takich „służebnych” zadań.
W chwili pisania tego tekstu nie można tego osiągnąć za pomocą wanilii Blazor / Razor bez osadzenia kontrolera MVC w celu obsługi części pobierania plików, której przykład jest następujący:
Następnie upewnij się, że uruchomienie aplikacji (Startup.cs) jest skonfigurowane do prawidłowego korzystania z MVC i ma następujący wiersz (dodaj go, jeśli nie):
.. a następnie w końcu zmodyfikuj komponent, aby połączyć się ze sterownikiem, na przykład (przykład oparty na iteracji z wykorzystaniem klasy niestandardowej):
Mam nadzieję, że pomoże to każdemu, kto miał problemy (jak ja!), Aby uzyskać odpowiednią odpowiedź na to z pozoru proste pytanie w dziedzinie Blazora…!
źródło