【发布时间】:2016-07-02 17:48:59
【问题描述】:
我有一个在服务器上运行的 Web API 项目。它应该从两种不同的来源返回 PDF:实际的可移植文档文件 (PDF) 和存储在数据库中的 base64 字符串。我遇到的麻烦是将文档发送回客户端 MVC 应用程序。剩下的就是关于发生的一切以及我已经尝试过的细节。
我编写的代码成功地将这两种格式转换为 C# 代码,然后(返回)为 PDF 格式。我已经成功传输了一个应该代表其中一个文档的字节数组,但我无法让它在浏览器中显示(在新选项卡中)。我总是收到某种“无法显示”的错误。
最近,我做了一种在服务器端查看文档的方法,以确保我至少可以让它做到这一点。它将文档放入代码中并用它创建一个 FileStreamResult,然后它作为(隐式转换)ActionResult 返回。我把它返回到服务器端 MVC 控制器并将其放入一个简单的返回(无视图)中,在浏览器中显示 PDF 就好了。但是,尝试直接访问 Web API 函数只会返回类似于 FileStreamResult 的 JSON 表示形式。
当我试图让它正确地返回到我的客户端 MVC 应用程序时,它告诉我不能直接设置“_buffer”。一些错误消息,大意是返回并抛出到对象中的某些属性是私有的,无法访问。
当转换为 base64 字符串时,上述 PDF 的字节数组表示形式似乎与 FileStreamResult 在 JSON 中返回的“_buffer”字符串的字符数不同。它最后缺少大约 26k 'A'。
关于如何让这个 PDF 正确返回的任何想法?如有必要,我可以提供代码,但必须有一些已知的方法将 PDF 从服务器端 Web API 应用程序返回到客户端 MVC 应用程序并在浏览器中将其显示为网页。
附:我确实知道“客户端”应用程序在技术上并不在客户端。它也将是一个服务器应用程序,但在这种情况下这无关紧要。相对于 Web API 服务器,我的 MVC 应用程序是“客户端”。
代码 获取pdf:
private System.Web.Mvc.ActionResult GetPDF()
{
int bufferSize = 100;
int startIndex = 0;
long retval;
byte[] buffer = new byte[bufferSize];
MemoryStream stream = new MemoryStream();
SqlCommand command;
SqlConnection sqlca;
SqlDataReader reader;
using (sqlca = new SqlConnection(CONNECTION_STRING))
{
command = new SqlCommand((LINQ_TO_GET_FILE).ToString(), sqlca);
sqlca.Open();
reader = command.ExecuteReader(CommandBehavior.SequentialAccess);
try
{
while (reader.Read())
{
do
{
retval = reader.GetBytes(0, startIndex, buffer, 0, bufferSize);
stream.Write(buffer, 0, bufferSize);
startIndex += bufferSize;
} while (retval == bufferSize);
}
}
finally
{
reader.Close();
sqlca.Close();
}
}
stream.Position = 0;
System.Web.Mvc.FileStreamResult fsr = new System.Web.Mvc.FileStreamResult(stream, "application/pdf");
return fsr;
}
从GetPDF获取的API函数:
[AcceptVerbs("GET","POST")]
public System.Web.Mvc.ActionResult getPdf()
{
System.Web.Mvc.ActionResult retVal = GetPDF();
return retVal;
}
用于显示 PDF 服务器端:
public ActionResult getChart()
{
return new PDFController().GetPDF();
}
随着时间的推移,MVC 应用程序中的代码发生了很大变化。现在的方式是,它没有进入尝试在浏览器中显示的阶段。在此之前它会出错。
public async Task<ActionResult> get_pdf(args,keys)
{
JObject jObj;
StringBuilder argumentsSB = new StringBuilder();
if (args.Length != 0)
{
argumentsSB.Append("?");
argumentsSB.Append(keys[0]);
argumentsSB.Append("=");
argumentsSB.Append(args[0]);
for (int i = 1; i < args.Length; i += 1)
{
argumentsSB.Append("&");
argumentsSB.Append(keys[i]);
argumentsSB.Append("=");
argumentsSB.Append(args[i]);
}
}
else
{
argumentsSB.Append("");
}
var arguments = argumentsSB.ToString();
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync(URL_OF_SERVER+"api/pdf/getPdf/" + arguments).ConfigureAwait(false);
jObj = (JObject)JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result);
}
return jObj.ToObject<ActionResult>();
}
我直接从 Web API 控制器运行该方法得到的 JSON 是:
{
"FileStream":{
"_buffer":"JVBER...NjdENEUxAA...AA==",
"_origin":0,
"_position":0,
"_length":45600,
"_capacity":65536,
"_expandable":true,
"_writable":true,
"_exposable":true,
"_isOpen":true,
"__identity":null},
"ContentType":"application/pdf",
"FileDownloadName":""
}
我缩短了“_buffer”,因为它太长了。 我目前在 get_pdf(args,keys) 的返回行上收到以下错误消息
异常详细信息:Newtonsoft.Json.JsonSerializationException:无法创建 System.Web.Mvc.ActionResult 类型的实例。类型是接口或抽象类,不能实例化。路径“文件流”。
当我曾经得到一个空白的pdf阅读器(阅读器是空白的。没有文件)时,我使用了这个代码:
public async Task<ActionResult> get_pdf(args,keys)
{
byte[] retArr;
StringBuilder argumentsSB = new StringBuilder();
if (args.Length != 0)
{
argumentsSB.Append("?");
argumentsSB.Append(keys[0]);
argumentsSB.Append("=");
argumentsSB.Append(args[0]);
for (int i = 1; i < args.Length; i += 1)
{
argumentsSB.Append("&");
argumentsSB.Append(keys[i]);
argumentsSB.Append("=");
argumentsSB.Append(args[i]);
}
}
else
{
argumentsSB.Append("");
}
var arguments = argumentsSB.ToString();
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/pdf"));
var response = await client.GetAsync(URL_OF_SERVER+"api/webservice/" + method + "/" + arguments).ConfigureAwait(false);
retArr = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
}
var x = retArr.Skip(1).Take(y.Length-2).ToArray();
/*Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition", "inline;filename=document.pdf");
Response.BufferOutput = true;
Response.BinaryWrite(x);
Response.Flush();
Response.End();*/
return new FileStreamResult(new MemoryStream(x),MediaTypeNames.Application.Pdf);
}
注释掉的是来自其他一些尝试的代码。当我使用该代码时,我正在从服务器返回一个字节数组。它看起来像:
JVBER...NjdENEUx
【问题讨论】:
-
显示一些示例代码、具体错误信息等
-
@Mr.T 我刚刚添加了所有我想添加到我的编辑中的内容。
-
你为什么把它标记为 Web API 和 MVC?您说的是 Web API,但您的所有代码似乎都是 MVC。
-
那是不是 Web API。那只是MVC。 Web API 2 和 MVC 5 彼此不同。据我所知,您实际上根本没有使用 Web API。您以与 Web API 类似的方式使用 MVC,但这并不能使其成为 Web API。
-
在 MVC 5 中,您不能混合搭配 Web API 和 MVC。 WebAPI 控制器继承自 ApiController 并且不是 MVC 控制器类的子类型。所以这真的没有意义。
标签: c# asp.net pdf asp.net-mvc-5 asp.net-web-api2