Bla*_*ise 158 c# asp.net asp.net-mvc asp.net-web-api
在常规的MVC控制器中,我们可以用a输出pdf FileContentResult
.
public FileContentResult Test(TestViewModel vm)
{
var stream = new MemoryStream();
//... add content to the stream.
return File(stream.GetBuffer(), "application/pdf", "test.pdf");
}
Run Code Online (Sandbox Code Playgroud)
但是我们怎样才能把它变成一个ApiController
?
[HttpPost]
public IHttpActionResult Test(TestViewModel vm)
{
//...
return Ok(pdfOutput);
}
Run Code Online (Sandbox Code Playgroud)
这是我尝试过但它似乎不起作用.
[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);
}
Run Code Online (Sandbox Code Playgroud)
浏览器中显示的返回结果为:
{"Headers":[{"Key":"Content-Type","Value":["application/pdf"]},{"Key":"Content-Length","Value":["152844"]}]}
Run Code Online (Sandbox Code Playgroud)
在SO上有类似的帖子:从ASP.NET Web API中的控制器返回二进制文件 .它讨论输出现有文件.但我无法使用流.
有什么建议?
Bla*_*ise 187
而不是返回的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;
}
Run Code Online (Sandbox Code Playgroud)
Ogg*_*las 86
如果你想返回,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;
}
Run Code Online (Sandbox Code Playgroud)
ale*_*eha 41
这个问题对我有帮助.
所以,试试这个:
控制器代码:
[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;
}
Run Code Online (Sandbox Code Playgroud)
查看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>
Run Code Online (Sandbox Code Playgroud)
我不确定应该责怪哪一部分,但这就是为什么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;
}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
2)如果你有一个新的流看起来好一点,1)如果你的流不是从0开始就更简单
对我来说,这是之间的区别
var response = Request.CreateResponse(HttpStatusCode.OK, new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");
Run Code Online (Sandbox Code Playgroud)
和
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");
Run Code Online (Sandbox Code Playgroud)
第一个返回 StringContent 的 JSON 表示形式: {"Headers":[{"Key":"Content-Type","Value":["application/octet-stream; charset=utf-8"]}]}
而第二个正在正确返回文件。
似乎 Request.CreateResponse 有一个重载,它将字符串作为第二个参数,这似乎是导致 StringContent 对象本身呈现为字符串而不是实际内容的原因。
这是一种无需缓冲就可以流式传输文件内容的实现(如果是大文件,则在byte [] / MemoryStream等中进行缓冲可能是服务器的问题)。
public class FileResult : IHttpActionResult
{
public FileResult(string filePath)
{
if (filePath == null)
throw new ArgumentNullException(nameof(filePath));
FilePath = filePath;
}
public string FilePath { get; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(File.OpenRead(FilePath));
var contentType = MimeMapping.GetMimeMapping(Path.GetExtension(FilePath));
response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
return Task.FromResult(response);
}
}
Run Code Online (Sandbox Code Playgroud)
它可以像这样简单地使用:
public class MyController : ApiController
{
public IHttpActionResult Get()
{
string filePath = GetSomeValidFilePath();
return new FileResult(filePath);
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
241085 次 |
最近记录: |