创建代理以下载 SRS 的 PDF 报告






3.40/5 (4投票s)
如何创建代理来下载 SRS 的 PDF 报告,然后将它们流式传输回客户端浏览器。
引言
以下文章介绍了如何创建一个代理页面,将 SQL Server 报告转换为 PDF 文件。当代码执行时,它将调用 SQL Reporting Services 服务器上的报告,生成 PDF 文件,然后将其作为下载选项呈现给用户。
此过程的一个好处是您永远不必将物理文件保存在服务器上,然后将客户端定向到该文件。所有操作都在内存中完成,因此不会有文件权限问题或磁盘空间问题需要处理。
背景
虽然此代码对于创建 SRS 报告的 PDF 副本很有用,但真正的价值在于您不再需要授予每个人访问 Reporting Services 中的报告的权限。为此,您只需登录 Reporting Services 网站并设置一个可以访问报告的单一用户帐户。从那里,请务必在设置 Web 请求时在凭据中引用此相同的用户帐户。
此代码也可以轻松修改,以下载其他 URL 中的其他类型的文件。
Using the Code
首先,我们必须构造一个指向报告服务器上报告的 URI。
string url = "https:///ReportServer/Pages/ReportViewer.aspx?%2fInvoices%2fCurrent&rs%3aCommand=Render&rs%3AFormat=PDF&InvoiceId=1";
上述 URL 的分解
http://localhost/ReportServer/Pages/ReportViewer.aspx
- 这应该指向 Reporting Services 附带的 ReportViewer 页面。发票
/- 这是您在 Reporting Services 中设置的文件夹。如果您的报告位于子文件夹中,则需要指定用 %2f 分隔的完整路径Current
- 这是您在 Reporting Services 中看到的报告的名称Command=Render
- 这是告诉服务器生成报告所必需的Format=PDF
- 这将以 PDF 格式呈现输出。Reporting Services 也可以用其他格式呈现InvoiceId=1
- 这是一个传递到报告中的自定义参数。在此实例中,我们只需传递 ID #1
可以在客户端下载 PDF 时为其创建自定义文件名。
// this name is what the user will see when they are prompted for download. string customFileName = "NewFileName.pdf";
本节介绍如何设置用户凭据以访问 Report Server。我在 localhost 上使用 CredentialCache.DefaultCredentials
进行测试。在远程服务器上访问此内容时,您可能需要传入用户凭据。
// Create a request object that will make a call to the reporting server WebRequest request = WebRequest.Create(url); request.ContentType = @"application/pdf"; // If you require authentication to access your report server, set the variables below string userName = ""; string password = ""; string domain = ""; // If your server requires authentication, you will have to pass them into the request object if (userName.Length > 0) { // Create and then pass in network credentials to acecss the reporting server System.Net.NetworkCredential credentials = new NetworkCredential(userName, password, domain); request.Credentials = credentials; } else // use the default credentials request.Credentials = CredentialCache.DefaultCredentials;
此代码捕获来自 Report Server 的响应,然后将结果保存到 MemoryStream
对象中,以便将其传递回客户端。为了实现这一点,我们调用 ReadFully
方法将 Stream
转换为字节数组,然后将其馈送到 MemoryStream。
此方法的源代码可以在 http://www.developerfusion.co.uk/show/4696/ 找到,并且也包含在示例项目中。
MemoryStream ms; // Send a request to download the pdf document and then get the response using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { // Get the stream from the server using (Stream stream = response.GetResponseStream()) { // Use the ReadFully method from the link above: byte[] data = ReadFully(stream, response.ContentLength); // Return the memory stream. ms = new MemoryStream(data); } }
ReadFully 的代码可以在下面看到。这最初发布在 http://www.developerfusion.co.uk/show/4696/
/// Reads data from a stream until the end is reached. The /// data is returned as a byte array. An IOException is /// thrown if any of the underlying IO calls fail. /// /// Original code can be found at http://www.developerfusion.co.uk/show/4696/ public static byte[] ReadFully(Stream stream, long initialLength) { // If we've been passed an unhelpful initial length, just // use 32K. if (initialLength < 1) { initialLength = 32768; } byte[] buffer = new byte[initialLength]; int read = 0; int chunk; while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0) { read += chunk; // If we've reached the end of our buffer, check to see if there's // any more information if (read == buffer.Length) { int nextByte = stream.ReadByte(); // End of stream? If so, we're done if (nextByte == -1) { return buffer; } // Nope. Resize the buffer, put in the byte we've just // read, and continue byte[] newBuffer = new byte[buffer.Length * 2]; Array.Copy(buffer, newBuffer, buffer.Length); newBuffer[read] = (byte)nextByte; buffer = newBuffer; read++; } } // Buffer is now too big. Shrink it. byte[] ret = new byte[read]; Array.Copy(buffer, ret, read); return ret; }
最后一段代码清除了当前的 Response
对象,然后将其发送到客户端以下载。我们还添加了一个标头来声明来自上面的自定义文件名,然后将内容类型设置为 PDF,以便浏览器知道如何处理该文件。代码的最后一行只是将 MemoryStream
对象发送到浏览器,然后提示用户下载。
// Clear out the headers that may already exist, then set content type and add a header to name the file Response.Clear(); Response.ContentType = "application/pdf"; Response.AddHeader("content-disposition", "inline; filename=" + customFileName); // Write the memory stream containing the pdf file directly to the Response object that gets sent to the client ms.WriteTo(Response.OutputStream);
关注点
虽然此示例显示了如何从 SRS 下载 PDF 文件,但还有更多格式可用,例如 CSV 和 Excel。要使用这些格式,请在 URI 中找到 Format=PDF
命令,并将 PDF 更改为 CSV 或 Excel。您还必须相应地更新 Response.ContentType
。
此代码使用 SQL Reporting Services 作为示例,但不仅限于 SRS。您可以轻松更改 URL 并更改内容类型以访问 Web 上的任何类型的文件。