2

I call a Web API Controller from my UI which then gets a report from SSRS. It inserts the bytes in the content of the response and sends it to the UI where it gets downloaded as a PDF.

Inside my Web API Controller I write the report bytes to a test PDF file to inspect the contents of the pdf and to see if the data is correct, which it is. But when the PDF gets downloaded from my UI and I open it, I get a blank paged document. When I inspect the reponse content in Fiddler, I can see that the data is corrupted and doesn't match the test PDF file data.

Server side:

[HttpPost]
public HttpResponseMessage GetInstancePdf(InstancePdfModel model) {
  var bytes = _digitalFormService.GetInstancePdf(model.ClientGuid, model.InstanceGuid, model.InstanceVersion);

  File.WriteAllBytes(@ "c:\temp\test.pdf", bytes);

  var response = Request.CreateResponse();

  response.Content = new ByteArrayContent(bytes);
  response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue(DispositionTypeNames.Inline) {
    FileName = "file.pdf"
  };
  response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");

  return response;
}

Client side:

$scope.downloadPdf = function(instance) {
  $scope.isBusy = true;
  digitalFormService.getInstancePdf(instance.instanceGuid, instance.instanceVersion).then(function(data) {
    if (data.status === 200) {
      const file = new Blob([data.data], {
        type: data.headers("Content-Type")
      });
      if (navigator.appVersion.toString().indexOf(".NET") > 0) {
        window.navigator.msSaveBlob(file, (`${instance.name} ${(new Date()).toLocaleString()}`).replace(",", ""));
      } else {
        //trick to download, store a file having its URL
        const fileUrl = URL.createObjectURL(file);
        const a = document.createElement("a");
        a.href = fileUrl;
        a.target = "_blank";
        a.download = (`${instance.name} ${(new Date()).toLocaleString()}`).replace(",", "");
        document.body.appendChild(a);
        a.click();
      }
    } else {
      debugger;
    }
    $scope.isBusy = false;
  });
};

function getInstancePdf(instanceGuid, instanceVersion) {
  var data = {
    clientGuid: digitalFormConfig.clientToken,
    instanceGuid: instanceGuid,
    instanceVersion: instanceVersion
  };
  return $http({
    url: digitalFormConfig.serverUrl +
      "api/DigitalForm/GetInstancePdf",
    dataType: "json",
    data: data,
    method: "POST"
  }).then(function(response) {
      return response;
    },
    function() {
      return $q.reject("No Data");
    });
}

I expect my downloaded PDF to be an informational document, matching the test PDF file saved inside the Web API Controller, but I get a blank document instead (same number of pages as test file, but blank).

I used Fiddler to inspect the response body. When I save the response body from within Fiddler as a pdf - everything is fine. So I am sure my server side code is correct. The problem must be somewhere on the client side.

Any help? Thanks.

  • Not an authority on this but looks like you are receiving binary data and JS expecting string in response. getting a link from server and opening it in tab would be a better option i suppose – Glance Mar 26 '19 at 15:01
  • Possible duplicate of [How to return a file using Web API?](https://stackoverflow.com/questions/11125535/how-to-return-a-file-using-web-api) – Danny Fardy Jhonston Bermúdez Mar 26 '19 at 15:48
  • I used Fiddler to inspect the response body. When I save the response body from within Fiddler as a pdf - everything is fine. So I am sure my server side code is correct. The problem must be somewhere on the client side. – Hardus Lombaard Mar 27 '19 at 08:44
  • Possible duplicate of [Returning binary file from controller in ASP.NET Web API](https://stackoverflow.com/questions/9541351/returning-binary-file-from-controller-in-asp-net-web-api) – mortb Mar 27 '19 at 08:48
  • It would be easier to make this work if you didn't post the data. I can't really think of any reason that `ClientGuid` `InstanceGuid` and `InstanceVersion` should not be used as query string parameters instead of being put in an object and posted. Serving a file as a get request is much easier than serving it as a response to a JQuery json post. – mortb Mar 27 '19 at 08:58

1 Answers1

1

I found the mistake. The bug was in the client side service. Code should look as follows:

function getInstancePdf(instanceGuid, instanceVersion) {
    var data = {
        clientGuid: digitalFormConfig.clientToken,
        instanceGuid: instanceGuid,
        instanceVersion: instanceVersion
    };
    return $http({
        responseType: "arraybuffer",
        url: digitalFormConfig.serverUrl +
            "api/DigitalForm/GetInstancePdf",
        dataType: "json",
        data: data,
        method: "POST"
    }).then(function (response) {
            return response;
        },
        function () {
            return $q.reject("No Data");
        });
}

The line responseType: "arraybuffer", was omitted previously.