W zwykłym kontrolerze MVC możemy wyprowadzić plik PDF z rozszerzeniem FileContentResult
.
public FileContentResult Test(TestViewModel vm)
{
var stream = new MemoryStream();
//... add content to the stream.
return File(stream.GetBuffer(), "application/pdf", "test.pdf");
}
Ale jak możemy to zmienić w ApiController
?
[HttpPost]
public IHttpActionResult Test(TestViewModel vm)
{
//...
return Ok(pdfOutput);
}
Oto, czego próbowałem, ale wydaje się, że nie działa.
[HttpGet]
public IHttpActionResult Test()
{
var stream = new MemoryStream();
//...
var content = new StreamContent(stream);
content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
content.Headers.ContentLength = stream.GetBuffer().Length;
return Ok(content);
}
Zwrócony wynik wyświetlany w przeglądarce to:
{"Headers":[{"Key":"Content-Type","Value":["application/pdf"]},{"Key":"Content-Length","Value":["152844"]}]}
I jest podobny post na SO: Returning binary file from controller in ASP.NET Web API . Mówi o wyprowadzaniu istniejącego pliku. Ale nie mogłem zmusić tego do pracy ze strumieniem.
Jakieś sugestie?
c#
asp.net
asp.net-mvc
asp.net-web-api
Blaise
źródło
źródło
Odpowiedzi:
Zamiast wracać
StreamContent
jakoContent
, mogę sprawić, że to zadziałaByteArrayContent
.źródło
MemoryStream.GetBuffer()
rzeczywistości zwraca bufor MemoryStream, który jest zwykle większy niż zawartość strumienia (aby wstawienia były wydajne).MemoryStream.ToArray()
zwraca bufor obcięty do rozmiaru zawartości.byte[]
zamiast tego wszystko nie jest ujawniane jako bufory? Użytkownicy mogą łatwo uruchomić aplikację z powodu braku pamięci.Jeśli chcesz wrócić
IHttpActionResult
, możesz to zrobić w ten sposób:źródło
To pytanie mi pomogło.
Więc spróbuj tego:
Kod kontrolera:
Wyświetl znaczniki HTML (ze zdarzeniem kliknięcia i prostym adresem URL):
źródło
FileStream
istniejącego pliku na serwerze. To trochę różni się odMemoryStream
. Ale dzięki za wkład.FileStream
ale nie zMemoryStream
. Zasadniczo ma to związek ze StreamemPosition
.Oto implementacja, która przesyła zawartość pliku na zewnątrz bez buforowania go (buforowanie w bajcie [] / MemoryStream itp. Może być problemem serwera, jeśli jest to duży plik).
Można go po prostu użyć w następujący sposób:
źródło
var fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);
zamiastFile.OpenRead(FilePath)
Nie jestem dokładnie pewien, którą część winić, ale oto dlaczego
MemoryStream
nie działa w Twoim przypadku:Kiedy piszesz do
MemoryStream
, zwiększa swojąPosition
własność. KonstruktorStreamContent
bierze pod uwagę prąd strumieniaPosition
. Więc jeśli napiszesz do strumienia, a następnie przekażesz go doStreamContent
, odpowiedź zacznie się od nicości na końcu strumienia.Istnieją dwa sposoby, aby to naprawić:
1) konstruować treść, pisać do strumienia
2) napisz do strumienia, zresetuj pozycję, skonstruuj zawartość
2) wygląda trochę lepiej, jeśli masz nowy strumień, 1) jest prostszy, jeśli strumień nie zaczyna się od 0
źródło
Dla mnie to była różnica między
i
Pierwsza zwróciła reprezentację StringContent w formacie JSON: {"Headers": [{"Key": "Content-Type", "Value": ["application / octet-stream; charset = utf-8"]}]}
Podczas gdy drugi zwracał właściwy plik.
Wygląda na to, że Request.CreateResponse ma przeciążenie, które pobiera ciąg jako drugi parametr i wydaje się, że to właśnie spowodowało, że sam obiekt StringContent był renderowany jako ciąg znaków, zamiast rzeczywistej zawartości.
źródło