Как вернуть файл (FileContentResult) в ASP.NET WebAPI
в обычном контроллере MVC мы можем выводить pdf с помощью FileContentResult.
public FileContentResult Test(TestViewModel vm)
{
var stream = new MemoryStream();
//... add content to the stream.
return File(stream.GetBuffer(), "application/pdf", "test.pdf");
}
но как мы можем изменить его в ApiController?
[HttpPost]
public IHttpActionResult Test(TestViewModel vm)
{
//...
return Ok(pdfOutput);
}
вот что я пробовал, но это, кажется, не работает.
[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);
}
возвращенный результат отображается в браузере:
{"Headers":[{"Key":"Content-Type","Value":["application/pdf"]},{"Key":"Content-Length","Value":["152844"]}]}
и есть аналогичный пост на SO:возвращаясь двоичный файл из контроллера в Интернете ASP.NET API-интерфейс
. Он говорит о выводе существующего файла. но я не удалось заставить его работать с потоком.
какие предложения?
5 ответов:
вместо возврата
StreamContentкакContent, Я могу заставить его работать сByteArrayContent.[HttpGet] public HttpResponseMessage Generate() { var stream = new MemoryStream(); // processing the stream. var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(stream.ToArray()) }; result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = "CertificationCard.pdf" }; result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); return result; }
Если вы хотите вернуть
IHttpActionResultвы можете сделать это так:[HttpGet] public IHttpActionResult Test() { var stream = new MemoryStream(); var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(stream.GetBuffer()) }; result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = "test.pdf" }; result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); var response = ResponseMessage(result); return response; }
этой вопрос помог мне.
Итак, попробуйте это:
код контроллера:
[HttpGet] public HttpResponseMessage Test() { var path = System.Web.HttpContext.Current.Server.MapPath("~/Content/test.docx");; HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); var stream = new FileStream(path, FileMode.Open); result.Content = new StreamContent(stream); result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(path); result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); result.Content.Headers.ContentLength = stream.Length; return result; }просмотр HTML-разметки (с помощью события click и простой URL-адрес):
<script type="text/javascript"> $(document).ready(function () { $("#btn").click(function () { // httproute = "" - using this to construct proper web api links. window.location.href = "@Url.Action("GetFile", "Data", new { httproute = "" })"; }); }); </script> <button id="btn"> Button text </button> <a href=" @Url.Action("GetFile", "Data", new { httproute = "" }) ">Data</a>
Я не совсем уверен, какая часть виновата, но вот почему
MemoryStreamне работает:как вы пишете в
MemoryStreamувеличивает этоPositionсобственность. КонструкторStreamContentучитывает текущий потокPosition. Так что если вы пишете в поток, то передайте его вStreamContent, ответ будет начинаться с небытия в конце потока.есть два способа правильно исправить это:
1) построить контент, написать поток
[HttpGet] public HttpResponseMessage Test() { var stream = new MemoryStream(); var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StreamContent(stream); // ... // stream.Write(...); // ... return response; }2) запись в поток, сброс позиции, построить контент
[HttpGet] public HttpResponseMessage Test() { var stream = new MemoryStream(); // ... // stream.Write(...); // ... stream.Position = 0; var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StreamContent(stream); return response; }2) выглядит немного лучше, если у вас есть свежий поток, 1) проще, если ваш поток не начинается с 0
для меня это была разница между
var response = Request.CreateResponse(HttpStatusCode.OK, new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");и
var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");первый возвращал представление JSON StringContent: {"Headers": [{"Key": "Content-Type", "Value": ["application / octet-stream; charset=utf-8"]}]}
в то время как второй возвращал файл правильно.
Кажется, что запрос.CreateResponse имеет перегрузку, которая принимает строку в качестве второго параметра, и это, похоже, было причиной Сам объект StringContent будет отображаться как строка, а не фактическое содержимое.
Comments