Since One Drive/ Sharepoint integration is the need of the hour for Dynamics 365 Business Central, I am going to write on how a file can be uploaded into One Drive from Dynamics 365 Business central.
It's been a while since Business central started supporting Rest APIs. These days, Power-Automate and Azure logic apps are making it easier to integrate with Business central. Business central has a lot of potential to integrate with office 365 products. I've read the blogs discussing how it can be achieved using azure functions or power automate and I wanted to do this the pure AL way!
Since there are lots of other blogs where App Registration in Azure AD,
API Permissions are shared in a detailed manner, I'm going to skip to the part
where we get to the see how this integration is achieved.
For Starters, we are going to need a table to capture the One Drive
credentials and Drive Folder Name. For this specific exercise, am capturing the
Client ID, Client Secret, Directory ID, Drive ID (One Drive), Folder Name in
the table OneDrive Setup.
1 2 3 4 5 6 7 8 9 | OnedriveSetup.Get(); TempBlob.CreateInStream(InStr); UploadIntoStream('Import', '', ' All Files (*.*)|*.*', FilePath, InStr); FileName := GetFileType(FilePath); IStream := InStr; LengthOfFile := TempBlob.Length(); TempBlob.CreateInStream(InStr); IStream := InStr; FileName := GetFileType(FilePath); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | procedure GetFileType(pFilename: Text): Text; begin if StrPos(pFilename, '\') = 0 then exit(pFilename) else begin FilenamePos := StrLen(pFilename); while (pFilename[FilenamePos] <> '\') or (FilenamePos < 1) do FilenamePos -= 1; if FilenamePos = 0 then exit(''); exit(CopyStr(pFilename, FilenamePos + 1, StrLen(pFilename))); end; end; |
Next, we create a function to retrieve the bearer token which will
enable us to upload the file. In this exercise, am using the Content type x-www-form-urlencoded.
we use POST method to get the Bearer Token. Then, we parse the HTTP response
content to a text variable, which is then read into a JSON Object. from there,
getting the access token is pretty straight forward. am adding the function
right below for those who need to try it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | procedure GetBearerToken(): Text var lClient: HttpClient; lResponse: HttpResponseMessage; lContent: HttpContent; lHeaders: HttpHeaders; lUrl: Text; lJsonObj: JsonObject; lJsonToken: JsonToken; Token: text; lClientID: text[250]; lSecret: text[250]; BaseTxt: Text[1024]; APITokenLocal: Text; begin lUrl := 'https://login.microsoftonline.com/' + OnedriveSetup."Directory ID" + '/oauth2/v2.0/token'; lClientID := Onedrivesetup."Client ID"; lSecret := OnedriveSetup."Client Secret"; BaseTxt := 'grant_type=client_credentials&client_id=' + lClientID + '&client_secret=' + lSecret + '&scope=https://graph.microsoft.com/.default'; lContent.Clear(); lContent.WriteFrom(BaseTxt); lHeaders.Clear(); lContent.GetHeaders(lHeaders); lHeaders.Remove('Content-Type'); lHeaders.Add('Content-Type', 'application/x-www-form-urlencoded'); lContent.GetHeaders(lHeaders); if lClient.Post(lUrl, lContent, lResponse) then begin lResponse.Content().ReadAs(Token); lJsonObj.ReadFrom(Token); lJsonObj.Get('access_token', lJsonToken); lJsonToken.WriteTo(APITokenLocal); APITokenLocal := DelChr(APITokenLocal, '=', '"'); Exit(APITokenLocal); end else error('API Token Request failed'); end; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | Procedure CreateUploadURL(FileName: Text; BearerToken: Text): Text begin lUrl := 'https://graph.microsoft.com/v1.0/drives/' + OnedriveSetup."Drive ID" + '/root:/' + FolderName + '/' + FileName + ':/createUploadSession'; Bearer := 'Bearer ' + BearerToken; lHeaders.Clear(); lContent.GetHeaders(lHeaders); lHeaders.Remove('Content-Type'); lHeaders.Add('Content-Type', 'application/json'); lreqHeaders := lClient.DefaultRequestHeaders(); lreqHeaders.Add('Authorization', Bearer); lreqHeaders.Remove('Accept'); lreqHeaders.Add('Accept', 'application/json'); lRequest.GetHeaders(lReqHeaders); lContent.GetHeaders(lHeaders); lRequest.Method := 'POST'; lRequest.SetRequestUri(lUrl); lRequest.GetHeaders(lReqHeaders); Clear(BaseTxt); if lClient.Send(lRequest, lResponse) then begin lResponse.Content().ReadAs(BaseTxt); lJsonObj.ReadFrom(BaseTxt); if lResponse.IsSuccessStatusCode() then begin lJsonObj.Get('uploadUrl', lJsonToken); lJsonToken.WriteTo(WebUrl); WebUrl := DelChr(WebUrl, '=', '"'); exit(WebUrl); end else Error(Text50001Lbl); end; end; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | procedure PutFileUsingUploadSession(UploadUrl: Text; BearerToken: Text) begin lUrl := UploadUrl; Bearer := 'Bearer ' + BearerToken; lHeaders.Clear(); lContent.GetHeaders(lHeaders); lHeaders.Remove('Content-Type'); lHeaders.Add('Content-Type', 'application/octet-stream'); lHeaders.Add('Content-Length', format(LengthOfFile)); lHeaders.Add('Content-Range', 'bytes 0-' + format(LengthofFile - 1) + '/' + format(LengthOfFile)); lreqHeaders := lClient.DefaultRequestHeaders(); lreqHeaders.Add('Authorization', Bearer); lRequest.GetHeaders(lReqHeaders); lContent.WriteFrom(InStr); lContent.GetHeaders(lHeaders); lRequest.Method := 'PUT'; lRequest.SetRequestUri(lUrl); lRequest.GetHeaders(lReqHeaders); lRequest.Content(lContent); Clear(BaseTxt); if lClient.Send(lRequest, lResponse) then begin lResponse.Content().ReadAs(BaseTxt); lJsonObj.ReadFrom(BaseTxt); if lResponse.IsSuccessStatusCode() then begin lJsonObj.Get('webUrl', lJsonToken); lJsonToken.WriteTo(WebUrl); WebUrl := DelChr(WebUrl, '=', '"'); //At this point, the file is uploaded. The WebUrl is retrieved so that you can use it to store it as per your requirement end else Error(Text50001Lbl); end; end; |
So far, I have tested this out with various file-types such as PDF, JPEG, PNG, PPT, XLSX, DOCX, MP4, etc. This code works for files within 40 MB. in order to upload large files, we need to break down into multiple recurrences of the last function. But that's a content for another post. Hope this helps anyone looking out to uploading files to one-drive using pure AL code.
If you find this interesting or if you have any suggestion/feedback, please leave a comment below! Cheers!!✌
Sathyanarayanan.S