在常规的MVC控制器中,我们可以输出带有FileContentResult的pdf。
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 Web API
。它讨论的是输出一个现有文件。但是我不能让它在溪流中工作。
有什么建议吗?
这个问题帮助了我。
所以,试试这个:
控制器代码:
[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标记(点击事件和简单的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的构造函数会考虑流的当前位置。因此,如果您写入流,然后将其传递给StreamContent,响应将从流末尾的虚无开始。
有两种方法可以正确解决这个问题:
construct content, write to stream
[HttpGet]
public HttpResponseMessage Test()
{
var stream = new MemoryStream();
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StreamContent(stream);
// ...
// stream.Write(...);
// ...
return response;
}
write to stream, reset position, construct content
[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;
}
looks a little better if you have a fresh Stream, 1) is simpler if your stream does not start at 0
对我来说,这就是
var response = Request.CreateResponse(HttpStatusCode.OK, new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");
and
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");
第一个是返回StringContent的JSON表示形式:{"Headers":[{"Key":"Content-Type","Value":["application/octet-stream;charset = utf - 8”]}]}
而第二个则是正常返回文件。
似乎请求。CreateResponse有一个重载,它将字符串作为第二个参数,这似乎是导致StringContent对象本身呈现为字符串而不是实际内容的原因。