我正在使用C#,MVC3和.NET 3.5在Azure VM(通过Web角色)中使用Prince XML生成PDF文件。使用PdfFilter()
属性标记的操作方法将HTML转发给Prince XML;创建PDF后,使用以下代码将新文件写入客户端:
public class PdfFilterAttribute : ActionFilterAttribute
{
private HtmlTextWriter tw;
private StringWriter sw;
private StringBuilder sb;
private HttpWriter output;
public override void OnActionExecuting(ActionExecutingContext context)
{
// Hijack the HttpWriter and write it to a StringBuilder instead of the normal response (http://goo.gl/RCNey).
sb = new StringBuilder();
sw = new StringWriter(sb);
tw = new HtmlTextWriter(sw);
output = (HttpWriter)context.RequestContext.HttpContext.Response.Output;
context.RequestContext.HttpContext.Response.Output = tw;
}
public override void OnResultExecuted(ResultExecutedContext context)
{
// Get the HTML from the request.
string html = sb.ToString();
// PdfController is where the PDF generation logic lives; instantiate it.
var pdfController = new PdfController();
// Generate a user-friendly filename for the PDF.
string filename = pdfController.GetPdfFilename(html);
// Generate the PDF and convert it to a byte array.
FileInfo pdfInfo = pdfController.HtmlToPdf(html);
// If the PDF or a user-friendly filename could not be generated, return the raw HTML instead.
if (pdfInfo == null || !pdfInfo.Exists || pdfInfo.Length == 0 || String.IsNullOrWhitespace(filename))
{
output.Write(html);
return;
}
// If a PDF was generated, stream it to the browser for downloading.
context.HttpContext.Response.Clear();
context.HttpContext.Response.AddHeader("Content-Type", "application/pdf");
context.HttpContext.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename + "\";");
context.HttpContext.Response.WriteFile(pdfInfo.FullName);
context.HttpContext.Response.Flush();
context.HttpContext.Response.Close();
context.HttpContext.Response.End();
}
}
我已确认在服务器上成功创建了PDF。但是当我尝试通过调用Response.WriteFile()
将其发送回客户端时,客户端只将下载视为0字节的PDF - 它无法使用。
没有抛出任何异常,Prince XML日志文件表明文件都已成功生成。我已经通过C#和远程桌面验证到Azure虚拟机中,实际上正在创建PDF并且可以通过PDF阅读器在那里读取。
还有什么我可能会遗失的吗?提前致谢!
答案 0 :(得分:0)
我解决了自己的问题 - 似乎将PDF视为一个字节数组,使用不同的方法将字节写入响应,并添加额外的标头来定义PDF工作的大小。它仍然不是100%干净,但它正在按预期运行......无论如何,这是更新的代码,以防其他任何人发现它有用。
public override void OnResultExecuted(ResultExecutedContext context)
{
// Get the HTML from the request.
string html = sb.ToString();
// PdfController is where the PDF generation logic lives; instantiate it.
var pdfController = new PdfController();
// Generate a user-friendly filename for the PDF.
string filename = pdfController.GetPdfFilename(html);
// Generate the PDF and convert it to a byte array.
FileInfo pdfInfo = pdfController.HtmlToPdf(html);
// Render the PDF as a byte array; if it can't be rendered, use an empty byte array instead.
byte[] pdfBytes = (pdfInfo.Exists && pdfInfo.Length > 0 ? File.ReadAllBytes(pdfInfo.FullName) : new byte[]{});
// If the PDF or a user-friendly filename could not be generated, return the raw HTML instead.
if (pdfBytes.Length == 0 || String.IsNullOrWhitespace(filename))
{
output.Write(html);
return;
}
// If a PDF was generated, stream it to the browser for downloading.
context.HttpContext.Response.Clear();
context.HttpContext.Response.AddHeader("Content-Type", "application/pdf");
context.HttpContext.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename + "\";");
context.HttpContext.Response.AddHeader("Content-Length", pdfBytes.Length.ToString());
output.WriteBytes(pdfBytes, 0, pdfBytes.Length);
context.HttpContext.Response.Flush();
context.HttpContext.Response.Close();
context.HttpContext.Response.End();
}