1

Thanks for taking your time to read this question.

What do I need:

We have a SOAP web service hosted somewhere that will take a couple of parameters and generate reports by using SQL Server Reporting Services. The format of the report file could be a couple including excel and pdf. We don't own that service and we cannot change it.

We need a web app that calls the SOAP web service I mentioned above, generate a report, and stream the file back to the browser.

It has to be a web api 2/ angularjs app.

What do I have:

So far I got client calling web api no problem, and i can see the result all the way back from the SOAP web service, but I cannot download the file, or even I got the file downloaded, it's either saying the file is corrupted or the file is blank.

My Code:

-server side:

        var reportResponse = new RequestResponse();
            try
            {
                reportResponse = client.RenderReport(reportHeader);

                if (!reportResponse.Successful)
                {
                    return new HttpResponseMessage(HttpStatusCode.InternalServerError)
                    {
                        Content = new StringContent(reportResponse.ErrorMessage)
                    };
                }


                var stream = new MemoryStream(reportResponse.Result);
                var response = new HttpResponseMessage(HttpStatusCode.OK);
                response.Content = new StreamContent(stream);
                response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
                response.Content.Headers.ContentDisposition.FileName = outputName + fileExtension;
                response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

                return response;

            }
            catch (Exception exception)
            {
                return new HttpResponseMessage(HttpStatusCode.BadRequest)
                    {
                        Content = new StringContent(exception.Message)
                    };
            }

-client side:

function getReport(request) {
        return $http.get('/api/reports/', {
            params: request
        }, { responseType: 'arraybuffer' })
            .then(
                function (result) {
                    var octetStreamMime = 'application/octet-stream';

                var success = false;

                // Get the headers
                var headers = result.headers;

                // Get the filename from the x-filename header or default to "download.bin"
                var filename = headers['x-filename'] || 'download.bin';

                // Determine the content type from the header or default to "application/octet-stream"
                var contentType = headers['content-type'] || octetStreamMime;

                try {
                    // Try using msSaveBlob if supported
                    console.log("Trying saveBlob method ...");
                    var blob = new Blob([result.data], { type: contentType });
                    if (navigator.msSaveBlob)
                        navigator.msSaveBlob(blob, filename);
                    else {
                        // Try using other saveBlob implementations, if available
                        var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob;
                        if (saveBlob === undefined) throw "Not supported";
                        saveBlob(blob, filename);
                    }
                    console.log("saveBlob succeeded");
                    success = true;
                } catch (ex) {
                    console.log("saveBlob method failed with the following exception:");
                    console.log(ex);
                }

                if (!success) {
                    // Get the blob url creator
                    var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL;
                    if (urlCreator) {
                        // Try to use a download link
                        var link = document.createElement('a');
                        if ('download' in link) {
                            // Try to simulate a click
                            try {
                                // Prepare a blob URL
                                console.log("Trying download link method with simulated click ...");
                                var blob = new Blob([result.data], { type: contentType });
                                var url = urlCreator.createObjectURL(blob);
                                link.setAttribute('href', url);

                                // Set the download attribute (Supported in Chrome 14+ / Firefox 20+)
                                link.setAttribute("download", filename);

                                // Simulate clicking the download link
                                var event = document.createEvent('MouseEvents');
                                event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
                                link.dispatchEvent(event);
                                console.log("Download link method with simulated click succeeded");
                                success = true;

                            } catch (ex) {
                                console.log("Download link method with simulated click failed with the following exception:");
                                console.log(ex);
                            }
                        }

                        if (!success) {
                            // Fallback to window.location method
                            try {
                                // Prepare a blob URL
                                // Use application/octet-stream when using window.location to force download
                                console.log("Trying download link method with window.location ...");
                                var blob = new Blob([result.data], { type: octetStreamMime });
                                var url = urlCreator.createObjectURL(blob);
                                window.location = url;
                                console.log("Download link method with window.location succeeded");
                                success = true;
                            } catch (ex) {
                                console.log("Download link method with window.location failed with the following exception:");
                                console.log(ex);
                            }
                        }

                    }
                }

                if (!success) {
                    // Fallback to window.open method
                    console.log("No methods worked for saving the arraybuffer, using last resort window.open");
                    window.open(httpPath, '_blank', '');
                }
                },
                function (error) {
                    logger.error('Error getting report', error);
                })
            .catch(function (error) {
                logger.error('Error getting report', error);
            });
    }

For the client side code, I referenced this post. I tried to get a report in pdf, and I did get the file saved on the client side named download.bin. I can take a look at the header and figure it out, but I don't think that's the problem. In this case, download.bin can be opened with Adobe Reader, and it even knows it's a two page pdf file, but it shows blank.

I tried to save the file from my api controller, it has no problem at all, which means the web service I called has no problem.

I use chrome to check the get response, in my result.data, it is something like this(I delete some of the chars between "stream" and "endstream"):

    [/PDF /Text /ImageB /ImageC /ImageI]
endobj
6 0 obj
<< /Length 3655 /Filter /FlateDecode >> stream 
x­Ë·÷ô
D;iÞ/ÚÙpdØâdg1I$=9ÐÛ§Èî.Vߦx`ñÿë;d7Éfw|òÇ`¼CBÛ48+ágJ
·§áÃÛHuèoRÁ%'btVQxí  .þúfª¦Zv¬eæZEà«ÃOÌ äðâ×AÿuZO¥HJ^jÒÃWç?\}xsz{7ützyºþóôjøúêîôÙðâ?ÿ{ñàë·³®ªõy7Æ
wàýË77ïI
endstream
endobj
8 0 obj
<< /Type /Page /Parent 7 0 R /MediaBox [0 0 612.0 792.0] /Contents 9 0 R /Resources << /ProcSet 1 0 R /XObject << /Im5 5 0 R >> /Font << /F3 3 0 R /F4 4 0 R >> >> >>
endobj
3 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding >>
endobj
4 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >>
endobj
7 0 obj
<< /Type /Pages /Kids [ 2 0 R 8 0 R ] /Count 2 >>
endobj
10 0 obj
<< /Type /Catalog /Pages 7 0 R >>
endobj
11 0 obj
<< /Title <feff004700520050005f00410053004f005000610079006d0065006e0074>
/Author <>
/Subject <>
/Creator (Microsoft Reporting Services 10.0.0.0)
/Producer (Microsoft Reporting Services PDF Rendering Extension 10.0.0.0)
/CreationDate (D:20150922094257-04'00')
>>
endobj
xref
0 12
0000000000 65535 f
0000000010 00000 n
0000003799 00000 n
0000079131 00000 n
0000079236 00000 n
0000003983 00000 n
0000000065 00000 n
0000079336 00000 n
0000078947 00000 n
0000077371 00000 n
0000079404 00000 n
0000079457 00000 n
trailer << /Size 12 /Root 10 0 R /Info 11 0 R >>
startxref
79744
%%EOF

If I understand this correctly, it could very well be an encoding problem. I tried to use Uint8Array() for creating the blob, it did not work.

I also tried to use FileSaver.js, and got the same thing.

Could someone point me to the right direction? Thanks so much.

Community
  • 1
  • 1
Raymond Wang
  • 1,484
  • 2
  • 18
  • 33

0 Answers0