codeunit 50124 CreateFileNew { procedure CreateFileNew(FileName: Text) var requestMethod: Text; request: HttpRequestMessage; RequestHeader: HttpHeaders; hhtpres: HttpResponseMessage; canonicalizedResource: Text; canonicalizedHeaders: Text; urlPath: Text; client: HttpClient; content: HttpContent; test: Boolean; MethodType: Text; authorizationHeader: Text; stringToSign: Text; msVersion: Text; cha: Char; contenttype: Text; contentLength: Integer; dat: DateTime; res: Text; keyss: Text; dateInRfc1123Format: Text; // <------------ Changed //EncryptionManagement: Codeunit "Encryption Management"; EncryptionManagement: Codeunit "Cryptography Management"; // <------------ Changed BC15 uri: Text; begin cha := 10; //13; <------------ Changed msVersion := '2015-02-21';//'2015-04-05';//;'02-14-2014'; <------------ Changed MethodType := 'CreateFile'; keyss := GetAccountAccessKey(); dateInRfc1123Format := GetUTCDateTimeText(); // <------------ Changed requestMethod := 'PUT'; urlPath := GetAccountSharedRessource() + '/lables/' + FileName; // you need a folder lables inside your Shared ressource //canonicalizedResource := '/bcstorage/lables/tre11.csv'; CanonicalizedResource := StrSubstNo('/%1/%2', GetAccountName(), urlPath); canonicalizedHeaders := 'x-ms-content-length:' + '1024' + Format(cha) + 'x-ms-date:' + dateInRfc1123Format + Format(cha) + 'x-ms-type:' + 'file' + Format(cha) + 'x-ms-version:' + msVersion; stringToSign := (requestMethod + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + canonicalizedHeaders + Format(cha) + // <------------ Changed canonicalizedResource); authorizationHeader := 'SharedKey ' + GetAccountName() + ':' + EncryptionManagement.GenerateBase64KeyedHashAsBase64String(stringToSign, keyss, 2); //Message((authorizationHeader)); uri := StrSubstNo('https://%1.file.core.windows.net/%2', GetAccountName(), urlPath); request.SetRequestUri(uri); request.Method := requestMethod; RequestHeader.Clear(); request.GetHeaders(RequestHeader); RequestHeader.Add('Authorization', authorizationHeader); RequestHeader.Add('x-ms-content-length', '1024'); RequestHeader.Add('x-ms-date', dateInRfc1123Format); RequestHeader.Add('x-ms-type', 'file'); RequestHeader.Add('x-ms-version', msVersion); client.Send(request, hhtpres); if not hhtpres.IsSuccessStatusCode then Error(hhtpres.ReasonPhrase); end; procedure GetUTCDateTimeText(): Text var TypeHelper: Codeunit "Type Helper"; begin exit(TypeHelper.GetCurrUTCDateTimeAsText()); end; procedure GetAccountName(): Text begin // Your Account name exit('bc365storage'); end; procedure GetAccountSharedRessource(): Text begin // Your Shared ressource exit('bcstorage'); end; procedure GetAccountAccessKey(): Text begin // Your Access Key exit('i0PNZ6Ykse7oSSfUzFeA36rQfAvaaJiL9LYbv9UZnol0NRM4sal4s8B3ipkjvfzcsP8/gnI58G6A=='); end; }
procedure WriteRange(FileName: Text; TempBlob: Record TempBlob temporary) var requestMethod: Text; request: HttpRequestMessage; RequestHeader: HttpHeaders; hhtpres: HttpResponseMessage; canonicalizedResource: Text; canonicalizedHeaders: Text; urlPath: Text; client: HttpClient; content: HttpContent; ContentHeaders: HttpHeaders; test: Boolean; authorizationHeader: Text; stringToSign: Text; msVersion: Text; cha: Text[1]; contenttype: Text; contentLength: Integer; res: Text; keyss: Text; dateInRfc1123Format: Text; EncryptionManagement: Codeunit "Encryption Management"; uri: Text; Range: Text; InStr: InStream; begin if not TempBlob.Blob.HasValue() then exit; cha[1] := 10; msVersion := '2015-02-21'; keyss := GetAccountAccessKey(); dateInRfc1123Format := GetUTCDateTimeText(); // <------------ Changed requestMethod := 'PUT'; urlPath := GetAccountSharedRessource() + '/lables/' + FileName + '?comp=range'; CanonicalizedResource := ConvertStr(StrSubstNo('/%1/%2', GetAccountName(), urlPath), '?=', cha + ':'); TempBlob.Blob.CreateInStream(InStr, TextEncoding::UTF8); content.WriteFrom(InStr); ContentLength := TempBlob.Blob.Length; ContentHeaders.Clear(); content.GetHeaders(ContentHeaders); ContentHeaders.Add('Content-Length', Format(ContentLength, 0, 9)); ContentHeaders.Remove('Content-Type'); request.Content := content; Range := 'bytes=0-' + Format(contentLength - 1, 0, 9); canonicalizedHeaders := 'x-ms-date:' + dateInRfc1123Format + Format(cha) + 'x-ms-range:' + Range + Format(cha) + 'x-ms-version:' + msVersion + Format(cha) + 'x-ms-write:' + 'update'; stringToSign := (requestMethod + Format(cha) + Format(cha) + Format(cha) + Format(contentLength, 0, 9) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + Format(cha) + canonicalizedHeaders + Format(cha) + // <------------ Changed canonicalizedResource); authorizationHeader := 'SharedKey ' + GetAccountName() + ':' + EncryptionManagement.GenerateBase64KeyedHashAsBase64String(stringToSign, keyss, 2); uri := StrSubstNo('https://%1.file.core.windows.net/%2', GetAccountName(), urlPath); request.SetRequestUri(uri); request.Method := requestMethod; RequestHeader.Clear(); request.GetHeaders(RequestHeader); RequestHeader.Add('Authorization', authorizationHeader); RequestHeader.Add('x-ms-date', dateInRfc1123Format); RequestHeader.Add('x-ms-range', Range); RequestHeader.Add('x-ms-version', msVersion); RequestHeader.Add('x-ms-write', 'update'); client.Send(request, hhtpres); if not hhtpres.IsSuccessStatusCode then Error(hhtpres.ReasonPhrase) else Message(hhtpres.ReasonPhrase); end; procedure WriteText2File(FileName: Text; qText: Text) var OutStr: OutStream; TempBlob: Record TempBlob temporary; begin TempBlob.Blob.CreateOutStream(OutStr, TextEncoding::UTF8); OutStr.WriteText(qText); WriteRange(FileName, TempBlob); end;
FileName := 'AzureSharedFile.txt'; CreateFileNew(FileName); WriteText2File(FileName, 'This is a test !!!!');
Answers
I changed your code a little to make it works
The EncryptionManagement codeunit changed in BC15 and I added some procedures to get your account data and the DateTime format expected.
Regards
Thanks for the reply, But i am working on BC14 so i cannot find the codeunit "Cryptography Management" .
In this case you can use the codeunit that you are already using (Encryption Management).
Regards.
I am having this error now.
A call to System.Convert.FromBase64String failed with this message: Invalid length for a Base-64 char array or string.
Well this happens because the Access Key you posted is not a valid one, I think that that was on purpose invalid,
Check that that access key is your valid access key.
Regards
And using your original access key you get the same error?
Regards.
You can add this code to the previous one:
And call the code whit something like this:
Regards
i am trying to test using BC170 CU 5 on prem
I test to export txt file to my azure storage account.
i created button in the page :
and then codeunit exactly the same
but i got this error message
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
any advise?
Thanks.
and here is my config
1. GetAccountName
2. GetAccountAccessKey
SAS
is there anything that i miss?
You could check your AccountAccessKey
Because if I provide a wrong one I got your error message:
Regards.
here is my screen shot
--> HYyXRecMzl/GEKQtCwWVCN9P4jehmIGa0k51KhukUMAj1fWsjVDzUC12rzDROOHjhpv5S4FKeS24zP6iDn+SXA==
and here is my code :
is there something wrong?
No, there is nothing wrong.
The only thing I can assure you is that the code works.
Here is a GitHub repository with a solution to deal with Azure Blob Storage, take a look and see if this help.
https://github.com/cosmoconsult/D365BC-Blob-Storage-API
Regards
is it because of Msversion difference ?
or maybe I created wrong azure storage?
what i need is just to export txt or files as a file to specific path.
I don't know, if you want you could pass me the data in a private message and I test it.
Regards.
thanks so much.
i have sent you via private message
your code is working.
error was because i put space in my file name!
thanks.
because if write txt file is very limited .. i think max only 5-10mb
maybe like pdf/ jpg
Something like this:
And you can use this action:
Regards
is there any limitation to copy file?
I tested
png file 3 kb - Successfull
jpg file 3.7 mb - Successfull
pdf file 2.7 mb - Failed
pdf file 52 kb - Successfull
jpg file 500 kb - Failed
error message : Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
i managed to solve this issue.
same like last time.. the file name is not allowed to have space..
so i remove the space before i copy..
but i tested to copy pdf 30 mb
it show me error message :
The request body is too large and exceeds the maximum permissible limit.
Maybe an improvement to the code is to urlencode the file name.
Anyway there is a limit in the file size.
Regards.
yeah it seems there is this limitation
max is 4mb
https://docs.microsoft.com/en-us/troubleshoot/azure/general/request-body-large
@julkifli33
I tried the same code but I'm getting this error.
I just replace this line
uri := StrSubstNo('https://%1.file.core.windows.net/%2', GetAccountName(), urlPath);
with this
uri := StrSubstNo('https://%1.blob.core.windows.net/%2', GetAccountName(), urlPath);
I replace the value of the storage account, Name and Key with my own details.
Can you help me figure out what I'm missing.
They are two different API (file and blob).
How I already posted, here is a GitHub repository with a solution to deal with Azure Blob Storage, take a look and see if this help.
https://github.com/cosmoconsult/D365BC-Blob-Storage-API
Regards.
This resolved my issue. thank you. cheers