0

我已经看到了许多使用 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.NET报告服务:获取生成报告的 PDF

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

这是我现在使用的,它返回一个 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

4

2 回答 2

0

您获得 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;
    }
于 2016-02-07T16:26:45.230 回答
0

不幸的是,简单地将 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。

于 2016-02-12T21:16:15.007 回答