Retrieve contents of File Data Type field in Dynamics 365/ CDS using JavaScript/ client code.

Follow my blog for more interesting topics on Dynamics 365, Portals and Power Platform. For training and consulting, write to us at info@xrmforyou.com


Few months back I wrote an article on File Data type in Dynamics 365/ CDS where I explained the details of this data type and explained how you download the content of the field using C# code.
After that I received loads of request on how I can do the same using JavaScript. And here is this blog where I show in detail on how you can do that.
For this demo, I have created a file data type field on contact entity – File Content (cr947_filecontent)
image
Then I go ahead an upload a file on one contact record.
image


Ok now the tough part. How to download this file content from your client script if required? Well, let’s see how you can do this.
First things first. Below is the URL Format to download the file content for a file field for a contact record.
https://<crmurl>/api/data/v9.1/contacts(<contact_id>)/cr947_filecontent?size=full – This will download the content in base64 format string.
https://<crmurl>/api/data/v9.1/contacts(<contact_id>)/cr947_filecontent/$value?size=full – This will download the content as byte array.
If your file size is less than 16 MB, then depending on how you want to download the file, you can use the appropriate URL.
However if your filesize is more than 16MB, it wont’ work. This is because you if you use the same URL to download the content for a filesize more than 16MB, you will get an error – “Maximum file size supported for download is [16] MB. File of [17 MB] size may only be downloaded using staged chunk download.”
So let’s see how we can have a common function to handle all these scenarios. Below is the code for the same. I have decided to go ahead with the base64 content.
Also if you observe here, I am downloading the file content in chunk of 4MB. Also observe I am using the “Range” header to set the bytes count that I want to download.

function makeRequest(method, url, startBytes, increment) {
    return new Promise(function (resolve, reject) {
       var request = new XMLHttpRequest();
       request.open(method, url);
       request.setRequestHeader("Range", "bytes=" + startBytes + "-" + (startBytes + increment - 1));
       request.onload = resolve;
       request.onerror = reject;
       request.send();
    });
}
async function PrepareFile() {
    var startBytes = 0;
    var increment = 4194304;
    var url = "https://<crmurl>/api/data/v9.1/contacts(8da6e5b9-88df-e311-b8e5-6c3be5a8b200)/<field_name>?size=full";
    var finalContent = "";
    var fileSize = 0;
    var fileName = '';
   while (startBytes <= fileSize) {
       debugger;
       var result = await makeRequest("GET", url, startBytes, increment);
       var 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");
          }
       }
    }
}
PrepareFile();

I am calling PrepareFile() method which is doing the loop through. “finalcontent” is the variable which will have the entire base64 content.
How to use the base64 content and download it through browser? I am leaving that for a homework.
Hope this helps!
Debajit Dutta
(Microsoft MVP)