我在ASP.Net核心中创建了Wep API以返回PDF。这是我的代码:
public HttpResponseMessage Get(int id)
{
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
var stream = new System.IO.FileStream(@"C:\Users\shoba_eswar\Documents\REquest.pdf", System.IO.FileMode.Open);
response.Content = new StreamContent(stream);
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "NewTab";
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
return response;
}
但它只返回JSON响应:
{
"version":{
"major":1,
"minor":1,
"build":-1,
"revision":-1,
"majorRevision":-1,
"minorRevision":-1
},
"content":{
"headers":[
{
"key":"Content-Disposition",
"value":[
"attachment; filename=NewTab"
]
},
{
"key":"Content-Type",
"value":[
"application/pdf"
]
}
]
},
"statusCode":200,
"reasonPhrase":"OK",
"headers":[
],
"requestMessage":null,
"isSuccessStatusCode":true
}
我在这里做错了吗?
答案 0 :(得分:41)
正如ASP.NET Core HTTPRequestMessage returns strange JSON message中所述,ASP.NET Core不支持返回HttpResponseMessage
(您安装了哪些软件包以访问该类型?)。
因此,序列化程序只是将HttpResponseMessage
的所有公共属性写入输出,就像使用任何其他不受支持的响应类型一样。
要支持自定义响应,您必须返回IActionResult
- 实现类型。有plenty of those。在您的情况下,我会查看FileStreamResult
:
public IActionResult Get(int id)
{
var stream = new FileStream(@"path\to\file", FileMode.Open);
return new FileStreamResult(stream, "application/pdf");
}
或者只需使用PhysicalFileResult
,即可为您处理流:
public IActionResult Get(int id)
{
return new PhysicalFileResult(@"path\to\file", "application/pdf");
}
当然,使用辅助方法可以简化所有这些,例如Controller.File()
:
public IActionResult Get(int id)
{
var stream = new FileStream(@"path\to\file", FileMode.Open);
return File(stream, "application/pdf", "FileDownloadName.ext");
}
这简单地抽象了FileContentResult
或FileStreamResult
的创建(对于这个重载,后者)。
或者,如果您要转换较旧的MVC或Web API应用程序并且不想一次转换所有代码,请添加对WebApiCompatShim (NuGet)的引用并将当前代码包装在ResponseMessageResult
中:
public IActionResult Get(int id)
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
var stream = ...
response.Content...
return new ResponseMessageResult(response);
}
如果您不想使用return File(fileName, contentType, fileDownloadName)
,则FileStreamResult
不支持从构造函数或属性设置content-disposition标头。
在这种情况下,您必须在返回文件结果之前自己将响应标头添加到响应中:
var contentDisposition = new ContentDispositionHeaderValue("attachment");
contentDisposition.SetHttpFileName("foo.txt");
Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
答案 1 :(得分:6)
由于我的声誉不够高,我无法评论CodeCaster的答案。 尝试
时public IActionResult Get(int id)
{
using (var stream = new FileStream(@"path\to\file", FileMode.Open))
{
return File(stream, "application/pdf", "FileDownloadName.ext");
}
}
我们有一个
ObjectDisposedException:无法访问已处置的对象。对象名称: “无法访问已关闭的文件。”。 System.IO.FileStream.BeginRead(byte [] 数组,整数偏移量,整数numBytes,AsyncCallback回调,对象状态)
我们删除了
[HttpGet]
[Route("getImageFile")]
public IActionResult GetWorkbook()
{
var stream = new FileStream(@"pathToFile", FileMode.Open);
return File(stream, "image/png", "image.png");
}
那行得通。这是在IIS Express中运行的ASP.NET Core 2.1。
答案 2 :(得分:0)
我没有足够的声誉来发表此评论,所以发表评论。 @CodeCaster的前三个解决方案和@BernhardMaertl的解决方案是正确的。
但是,对于某些可能不经常使用文件的人(例如我),请注意,如果运行此代码的进程(例如API)仅具有文件的读取权限,则需要将其指定为第三个创建FileStream
时的参数,否则默认行为是打开文件进行读/写操作,因为您没有写权限,因此会出现异常。
@CodeCaster的第三个解决方案将如下所示:
public IActionResult Get(int id)
{
var stream = new FileStream(@"path\to\file", FileMode.Open, FileAccess.Read);
return File(stream, "application/pdf", "FileDownloadName.ext");
}