1

I've uploaded a PDF file (Size 30MB) on a File type Field.

I'm then trying to display the PDF from the field on a web resource but it doesnt show. If I try to display the same PDF from annotation entity, it displays fine. This is how I'm fetching the data from file type field:

            var startBytes = 0;
            var req;
            var increment = 4194304;
            var clientUrl = Xrm.Utility.getGlobalContext().getClientUrl();
            var url = clientUrl + "/api/data/v9.1/my_entity(" + recId + ")/my_fields?size=full";

            while (startBytes <= fileSize) {
                var result = await makeRequest("GET", url, startBytes, increment);
                req = result.target;
                if (req.status === 206) {
                    finalContent += JSON.parse(req.responseText).value;
                    startBytes += increment;
                    if (fileSize === 0) {
                        fileSize = req.getResponseHeader("x-ms-file-size");
                        fileName = req.getResponseHeader("x-ms-file-name");
                    }
                }
                else if (req.status === 404) {
                    break;
                }
            }

        if (fileBodyAndMimeType[1] === "pdf") {
            var newSrc = "data:application/pdf;base64," + finalContent;
            const blob = dataURItoBlob(newSrc);
            var temp_url = window.URL.createObjectURL(blob);
            $("#myframe").attr("data", temp_url);
            document.getElementById("myImage").style.display = "none";
        }

The above dataURItoBlob methog gives me the following error:

DOMException: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.

How to display the PDF from file type field on a web resource correctly?

3iL
  • 2,146
  • 2
  • 23
  • 47

1 Answers1

1

a sample code to get the content of a File column is the following:

$.ajax({
    type: "GET",
    contentType: "application/json; charset=utf-8",
    xhr: function() { var xhr = new XMLHttpRequest(); xhr.responseType = "blob"; return xhr; },
    url: Xrm.Utility.getGlobalContext().getClientUrl() + "/api/data/v9.1/sample_customtables(2fb4d8e0-4ac9-f27a-939e-e52621aae0d8)/sample_file/$value",
    beforeSend: function (req) {
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.setRequestHeader("Accept", "application/json");
    },
    async: true,
    success: function (data, textStatus, xhr) {
        var fileContent = data;
        var fileName = "file.bin"; // default name
        
        // NOTE: the following code decodes the file name from the header
        var contentDisposition = xhr.getResponseHeader("content-disposition");
        try {
            var strToCheck = "filename=";
            var mimeEncodingCheck = "\"=?utf-8?B?";
            if (contentDisposition.indexOf(strToCheck) > 0) {
                var parseFileName = contentDisposition.substring(contentDisposition.indexOf(strToCheck) + strToCheck.length);
                if (parseFileName.indexOf(mimeEncodingCheck) === -1) { fileName = parseFileName; }
                else {
                    var parseFileNameBase64 = parseFileName.substring(parseFileName.indexOf(mimeEncodingCheck) + mimeEncodingCheck.length, parseFileName.length - 3);
                    fileName = decodeURIComponent(atob(parseFileNameBase64).split("").map(function (c) { return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); }).join(""));
                }
            }
        } catch {}

        console.log("File retrieved. Name: " + fileName);

        // NOTE: Uncomment the following lines to download the file
        // var saveFile = new Blob([fileContent], { type: "application/octet-stream" });
        // var customLink = document.createElement("a");
        // customLink.href = URL.createObjectURL(saveFile);
        // customLink.download = fileName;
        // customLink.click();
    },
    error: function (xhr, textStatus, errorThrown) {
        console.log("Error retrieving the File");
    }
});

in this sample you can get a Blob by doing this line (that is commented)

var saveFile = new Blob([fileContent], { type: "application/octet-stream" });

the returned content from a File column is binary and not a Base 64 like you get from an annotation.

After you get the blob you can use the createObjectURL method

For Dynamics 365/Dataverse you can use Dataverse REST Builder to generate the sample code.

Guido Preite
  • 14,905
  • 4
  • 36
  • 65
  • Hi Guido, thanks for the answer. I implemented your code but I'm getting the following error: JqueryJS:12 Uncaught DOMException: Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is '' or 'text' (was 'blob'). – 3iL Dec 27 '21 at 11:38
  • @3iL the error is not straightforward because responseText is not present inside the code I posted. Try with Dataverse REST Builder (if possible the Managed Solution version) and try to retrieve the file using the "Manage File Data" request type. (With the XrmToolBox version you are able to retrieve the file but the name is not parsed) – Guido Preite Dec 27 '21 at 12:04
  • XMLHttpRequest made in Dataverse REST Builder worked for me! Thanks. – 3iL Dec 29 '21 at 13:51
  • @3iL thanks for the feedback, the "Manage File Data" request is quite complex and I am improving it in the next release – Guido Preite Dec 30 '21 at 09:06