65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.40/5 (4投票s)

2008年5月12日

CPOL

3分钟阅读

viewsIcon

24796

如何创建代理来下载 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 上的任何类型的文件。

© . All rights reserved.