我有一个运行在服务器上的Web API项目。它应该从两种不同的来源返回PDF文件:实际的便携式文档格式(PDF)和存储在数据库中的base64字符串。我遇到的问题是将文档发送回客户端MVC应用程序时。以下是关于已经发生和尝试过的一切细节。
我编写了成功将这两种格式转换为C#代码,然后(重新)转换为PDF形式的代码。我已经成功传输了一个字节数组,它应该代表其中一个文档,但我无法在浏览器中显示它(在新标签页中)。我总是得到某种“无法显示”的错误。
最近,我制定了一种查看服务器端文档的方法,以确保我至少可以使其执行。它将文档获取到代码中,并创建一个FileStreamResult,然后将其作为(隐式转换)ActionResult返回。我让它返回到服务器端MVC控制器并将其放入简单的返回(无视图)中,在浏览器中正常显示PDF。但是,尝试直接转到Web API函数只会返回看起来像FileStreamResult的JSON表示。
当我尝试使其正确返回到我的客户端MVC应用程序时,它告诉我“_buffer”不能直接设置。类似于所返回并抛入对象中的某些属性是私有的,无法访问的错误消息。
所述PDF的字节数组表示在翻译为base64字符串时,似乎没有与FileStreamResult返回的JSON中的“_buffer”字符串相同数量的字符。它缺少大约26k个'A'。
有什么想法可以使此PDF正确返回吗?如有必要,我可以提供代码,但必须有某种已知方法可以从服务器端Web API应用程序返回PDF到客户端MVC应用程序并在浏览器中显示为Web页面。
P.S. 我知道“客户端”应用程序在技术上不在客户端。它也将是一个服务器应用程序,但这在这种情况下并不重要。相对于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;
}
获取PDF的API函数:GetPDF
[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的实例。该类型是接口或抽象类,无法实例化。路径'FileStream'。
以前我遇到过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