如何拦截.NET MVC3中当前actionresult的输出流?

嗨,谢谢你的期待!

背景

我正在使用Rotativa pdf工具将视图(html)读入PDF。 它工作得很好,但它本身并没有提供将PDF保存到文件系统的方法。 相反,它仅在操作后将文件返回给用户的浏览器。

这是代码的样子:

public ActionResult PrintQuote(FormCollection fc) { int revisionId = Int32.Parse(Request.QueryString["RevisionId"]); var pdf = new ActionAsPdf( "Quote", new { revisionId = revisionId }) { FileName = "Quote--" + revisionId.ToString() + ".pdf", PageSize = Rotativa.Options.Size.Letter }; return pdf; } 

此代码调用另一个actionresult(“Quote”),将其视图转换为PDF,然后将PDF作为文件下载返回给用户。

如何拦截文件流并将PDF保存到我的文件系统。 将PDF发送给用户是完美的,但我的客户也希望PDF同时保存到文件系统。

有任何想法吗?

谢谢!

马特

我有同样的问题,这是我的解决方案:

您需要基本上对您自己的URL发出HTTP请求,并将输出保存为二进制文件。 简单,没有重载,辅助类和膨胀代码。

你需要这个方法:

  // Returns the results of fetching the requested HTML page. public static void SaveHttpResponseAsFile(string RequestUrl, string FilePath) { try { HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(RequestUrl); httpRequest.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"; httpRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate"); HttpWebResponse response = null; try { response = (HttpWebResponse)httpRequest.GetResponse(); } catch (System.Net.WebException ex) { if (ex.Status == WebExceptionStatus.ProtocolError) response = (HttpWebResponse)ex.Response; } using (Stream responseStream = response.GetResponseStream()) { Stream FinalStream = responseStream; if (response.ContentEncoding.ToLower().Contains("gzip")) FinalStream = new GZipStream(FinalStream, CompressionMode.Decompress); else if (response.ContentEncoding.ToLower().Contains("deflate")) FinalStream = new DeflateStream(FinalStream, CompressionMode.Decompress); using (var fileStream = System.IO.File.Create(FilePath)) { FinalStream.CopyTo(fileStream); } response.Close(); FinalStream.Close(); } } catch { } } 

然后在你的控制器内,你这样称呼它:

 SaveHttpResponseAsFile("http://localhost:52515/Management/ViewPDFInvoice/" + ID.ToString(), "C:\\temp\\test.pdf"); 

瞧! 该文件位于您的文件系统上,您可以双击并打开PDF,或通过电子邮件发送给您的用户,或者您需要的任何内容。

  return new Rotativa.ActionAsPdf("ConvertIntoPdf") { FileName = "Test.pdf", PageSize = Rotativa.Options.Size.Letter }; 

在这里查看MVC管道图: http : //www.simple-talk.com/content/file.ashx? file = 6068

在呈现ActionResult之后调用OnResultExecuted()方法。

您可以使用属性覆盖此方法或使用ActionFilter应用和OnResultExecuted拦截器。

编辑:在此论坛主题的末尾,您将找到一个回复​​,其中提供了一个ActionFilter的示例,该ActionFilter读取(并更改)操作的响应流。 然后,您可以将流复制到文件,还可以将其返回到客户端。

我成功使用了Aaron的’SaveHttpResponseAsFile’方法,但我不得不改变它,因为当前登录用户的凭证未被应用(因此它转发到MVC4的登录URL)。

 public static void SaveHttpResponseAsFile(System.Web.HttpRequestBase requestBase, string requestUrl, string saveFilePath) { try { *snip* httpRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate"); httpRequest.Headers.Add(HttpRequestHeader.Cookie, requestBase.Headers["Cookie"]); *snip*

然后在调用Controller方法中,只需将“Request”添加到SaveHttpResponseAsFile调用中。

您也可以使用Rotativa来实现,这实际上非常简单。

 Using Rotativa; ... byte[] pdfByteArray = Rotativa.WkhtmltopdfDriver.ConvertHtml( "Rotativa", "-q", stringHtmlResult ); File.WriteAllBytes( outputPath, pdfByteArray ); 

我在winforms应用程序中使用它,从我们的Web应用程序中使用的Razor Views生成和保存PDF。

我能够让Eric Brown – Cal的解决方案工作,但我需要一个小小的调整来防止我得到关于找不到目录的错误。

(另外,看看Rotativa代码,看起来默认情况下已经传递了-q开关,因此可能没有必要,但我没有更改它。)

 var bytes = Rotativa.WkhtmltopdfDriver.ConvertHtml(Server.MapPath(@"/Rotativa"), "-q", html);