【问题标题】:How to return a URL Access generated PDF from a Web API method如何从 Web API 方法返回 URL 访问生成的 PDF
【发布时间】:2016-02-04 15:39:10
【问题描述】:

我见过许多使用 Web API 从存储在磁盘上的文件返回 PDF(或其他文件类型)的示例。但是,就我而言,我正在尝试使用 SSRS 的 URL Access 动态生成文档。以下是 URL 的示例:

https://reporting.mydomain.biz/_layouts/ReportServer/RSViewerPage.aspx?rv:RelativeReportUrl=%2fquest%2fQUEST%2520Reports%2fReview.rdl&rp%3aReview=220

我尝试了多种方法,但其中大多数都可以追溯到 2012 年,并且与 ASP.Net MVC 相关,例如:

public async Task<FileStreamResult> GenerateReport()
{

    CredentialCache credentialCache = new CredentialCache();
    credentialCache.Add(new Uri("http://domainORipaddress"), "NTLM", new NetworkCredential(
        ConfigurationManager.AppSettings["username"],
        ConfigurationManager.AppSettings["password"]
    ));

    Stream report = null;
    using (var httpClient = new HttpClient(new HttpClientHandler { Credentials = credentialCache }))
    {

        httpClient.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite);
        report = await httpClient.GetStreamAsync("reportUrl");
    }

    var contentDisposition = new ContentDisposition
    {
        FileName = "Report.pdf",
        Inline = false
    };
    Response.AppendHeader("Content-Disposition", contentDisposition.ToString());
    return File(report, "application/pdf");    

    //or use
    //Response.AppendHeader("Content-Disposition", String.Format("attachment;filename=\"{0}\"", reportName));
    //return File(reportPath, MediaTypeNames.Application.Pdf);
}

此示例代码来自本网站:http://webstackoflove.com/sql-server-reporting-service-with-asp-net-mvc/

这是一个类似的问题,但基于ASP.NETReporting services: Get the PDF of a generated report

我尝试使用上面的代码返回一个HttpResponseMessage,但我得到一个没有数据的文件。

这是我现在使用的,它返回一个 0 KB 的文件:

public HttpResponseMessage PrintQualityReview([FromUri] int reviewId)
{
    var reportUrl = String.Format("https://reporting.mydomain.biz/quest/_vti_bin/reportserver?https://reporting.mydomain.biz/quest/QUEST%20Reports/{0}Review.rdl&rs:Format=PDF&Review={1}",
    ConfigurationManager.AppSettings["ReportingServiceDatabase"],
    reviewId);

    CredentialCache credentialCache = new CredentialCache();
    credentialCache.Add(new Uri("https://reporting.mydomain.biz"), "NTLM", new NetworkCredential(
        ConfigurationManager.AppSettings["ReportingServiceAccount"],
        ConfigurationManager.AppSettings["ReportingServiceAccountPwd"]
    ));

    MemoryStream mStream = new MemoryStream();

    using (WebClient wc = new WebClient()) 
    {
        wc.Credentials = credentialCache;

        using (Stream stream = wc.OpenRead(reportUrl))
        {
            stream.CopyTo(mStream);
        }
    }            

    HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
    response.Content = new StreamContent(mStream);
    response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
    response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
    response.Content.Headers.ContentDisposition.FileName = "Report.pdf";

    return response;
}

我想知道如何处理ASP.Net Web API

【问题讨论】:

  • 我觉得这是一个两部分的问题。第一部分是如何将 URL 生成的 PDF 转换为流?第二部分是如何获取流对象并将其传递到我发送给客户端的响应中?

标签: c# pdf asp.net-web-api reporting-services urlaccess


【解决方案1】:

你得到 0 个字节的原因是你没有设置响应头的ContentLength

这是您的更新代码

public HttpResponseMessage PrintQualityReview([FromUri] int reviewId) {
        var reportUrl = String.Format("https://reporting.mydomain.biz/quest/_vti_bin/reportserver?https://reporting.mydomain.biz/quest/QUEST%20Reports/{0}Review.rdl&rs:Format=PDF&Review={1}",
            ConfigurationManager.AppSettings["ReportingServiceDatabase"],
            reviewId);

        CredentialCache credentialCache = new CredentialCache();
        credentialCache.Add(new Uri("https://reporting.mydomain.biz"), "NTLM", new NetworkCredential(
            ConfigurationManager.AppSettings["ReportingServiceAccount"],
            ConfigurationManager.AppSettings["ReportingServiceAccountPwd"]
        ));

        MemoryStream mStream = new MemoryStream();

        using (WebClient wc = new WebClient()) {
            wc.Credentials = credentialCache;

            using (Stream stream = wc.OpenRead(reportUrl)) {
                stream.CopyTo(mStream);
            }
        }

        var contentLength = mStream.Length; //content length for header
        var contentType = new MediaTypeHeaderValue("application/pdf");
        var contentDispositionValue = "attachment; filename=Report.pdf";

        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
        response.Content = new StreamContent(mStream);
        response.Content.Headers.ContentType = contentType;
        response.Content.Headers.ContentLength = contentLength;
        ContentDispositionHeaderValue contentDisposition = null;            
        if (ContentDispositionHeaderValue.TryParse(contentDispositionValue , out contentDisposition)) {
            response.Content.Headers.ContentDisposition = contentDisposition;
        }

        return response;
    }

【讨论】:

    【解决方案2】:

    不幸的是,简单地在标题中添加 content-length 并不能解决问题。诀窍是让 AngularJS $http 服务返回一个 ArrayBuffer 响应。

    网络 API

            [System.Web.Http.HttpGet]
            [System.Web.Http.Route("api/print/qualityreview/{reviewId:int}")]
            public HttpResponseMessage PrintQualityReview([FromUri] int reviewId)
            {
                logger.Info("Printing quality review for QR Id {0}", reviewId);
    
                HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
                var reportUrl = String.Format("https://example.com/quest/_vti_bin/reportserver?https://example.com/quest/QUEST%20Reports/{0}Review.rdl&rs:Format=PDF&Review={1}",
                    ConfigurationManager.AppSettings["ReportingServiceDatabase"],
                    reviewId);            
                CredentialCache credentialCache = new CredentialCache();
                credentialCache.Add(new Uri("https://example.com"), "NTLM", new NetworkCredential(
                    ConfigurationManager.AppSettings["ReportingServiceAccount"],
                    ConfigurationManager.AppSettings["ReportingServiceAccountPwd"]
                ));
    
    
                using (WebClient webClient = new WebClient())
                {
                    webClient.Credentials = credentialCache;
                    var reportStream = webClient.OpenRead(reportUrl);
    
                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        reportStream.CopyTo(memoryStream);
    
                        response.Content = new ByteArrayContent(memoryStream.ToArray());  //new StreamContent(reportStream);
                        response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
                        response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
                        //response.Content.Headers.ContentLength = reportStream.Length;
                        response.Content.Headers.ContentDisposition.FileName = "QualityReview.pdf";
                        response.StatusCode = HttpStatusCode.OK;
    
                        return response;
                    }
                }
            }
        }
    

    AngularJS

    在控制器中:

    /**
    * Prints the quality review
    */
    function printQualityReview() {
        questAPIService.printQualityReview(reviewId)
            .then(function (response) {
                var outputFilename = vm.reviewee.lastName + ', ' + vm.reviewee.firstName + ' ' + $filter('date')(vm.review.reviewDate, 'MMddyyyy') + '.pdf';
                var blob = new Blob([response.data], { type: 'application/pdf' });                    
                saveAs(blob, outputFilename);
    
            }, function (error) {
                $log.error('Printing failed: ', error);
                toastr.error('There was an error attempting to print the quality review.');
            });
    }
    

    服务调用:

    /**
    * Prints a quality review
    * 
    * @param {number} reviewId Id of the quality review to print
    * @returns {Promise} Promise including content and response data
    */
    function printQualityReview(reviewId) {
        return $http({
            url: 'api/print/qualityReview/' + reviewId,
            method: 'GET',
            responseType: 'arraybuffer'
        });
    }
    

    诀窍是确保在响应内容中返回一个字节数组,并在调用 API 方法时将响应类型设置为 ArrayBuffer。

    【讨论】:

      猜你喜欢
      • 2014-05-14
      • 1970-01-01
      • 2016-07-02
      • 1970-01-01
      • 1970-01-01
      • 2011-06-20
      • 1970-01-01
      • 2020-08-05
      • 2019-11-14
      相关资源
      最近更新 更多