Create file on azure storage in Business Central

Rahila
Member Posts: 16
I am trying to create a file on azure storage using PUT request, Below is my code and i get the error The value for one of the HTTP headers is not in the correct format.
The Code and the headers formed are:
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: DateTime;
EncryptionManagement: Codeunit "Encryption Management";
begin
cha := 13;
msVersion := '2015-04-05';//;'02-14-2014';
MethodType := 'CreateFile';
keyss := 'i0PNZ6Ykse7oSSfUzFeA36rQfAvaaJiL9LYbv9UZnol0NRM4sal4s8B3ipkjvfzcsP8/gnI58G6A==';
dateInRfc1123Format := CurrentDateTime;
requestMethod := 'PUT';
urlPath := 'lables/' + 'tre11.csv';
canonicalizedResource := '/bcstorage/lables/tre11.csv';
canonicalizedHeaders := 'x-ms-date:' + Format(dateInRfc1123Format) + Format(cha) + 'x-ms-range:bytes=0-1024' + Format(cha) + 'x-ms-version:' + msVersion
+ Format(cha) + 'x-ms-write:update' + Format(cha);
//canonicalizedHeaders := 'x-ms-content-length:1024' + Format(cha) + 'x-ms-date:' + FORMat(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 + canonicalizedResource);
authorizationHeader := 'SharedKey bc365storage:' + EncryptionManagement.GenerateBase64KeyedHashAsBase64String(stringToSign, keyss, 2);
Message((authorizationHeader));
request.SetRequestUri('https://bcstorage.file.core.windows.net/lables/tre11.csv');
request.Method := requestMethod;
RequestHeader.Add('x-ms-date', FORMat(dateInRfc1123Format));
RequestHeader.Add('x-ms-version', msVersion);
RequestHeader.Add('Authorization', authorizationHeader);
RequestHeader.Add('Accept-Charset', 'UTF-8');
if MethodType = 'CreateFile' then begin
RequestHeader.Add('x-ms-content-length', '1024');
RequestHeader.Add('x-ms-type', 'file');
end;
client.Put('https://bcstorage.file.core.windows.net/lables/tre11.csv', content, hhtpres);
hhtpres.Content.ReadAs(res);
Message(res);
test := client.Send(request, hhtpres);
end;
The Code and the headers formed are:
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: DateTime;
EncryptionManagement: Codeunit "Encryption Management";
begin
cha := 13;
msVersion := '2015-04-05';//;'02-14-2014';
MethodType := 'CreateFile';
keyss := 'i0PNZ6Ykse7oSSfUzFeA36rQfAvaaJiL9LYbv9UZnol0NRM4sal4s8B3ipkjvfzcsP8/gnI58G6A==';
dateInRfc1123Format := CurrentDateTime;
requestMethod := 'PUT';
urlPath := 'lables/' + 'tre11.csv';
canonicalizedResource := '/bcstorage/lables/tre11.csv';
canonicalizedHeaders := 'x-ms-date:' + Format(dateInRfc1123Format) + Format(cha) + 'x-ms-range:bytes=0-1024' + Format(cha) + 'x-ms-version:' + msVersion
+ Format(cha) + 'x-ms-write:update' + Format(cha);
//canonicalizedHeaders := 'x-ms-content-length:1024' + Format(cha) + 'x-ms-date:' + FORMat(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 + canonicalizedResource);
authorizationHeader := 'SharedKey bc365storage:' + EncryptionManagement.GenerateBase64KeyedHashAsBase64String(stringToSign, keyss, 2);
Message((authorizationHeader));
request.SetRequestUri('https://bcstorage.file.core.windows.net/lables/tre11.csv');
request.Method := requestMethod;
RequestHeader.Add('x-ms-date', FORMat(dateInRfc1123Format));
RequestHeader.Add('x-ms-version', msVersion);
RequestHeader.Add('Authorization', authorizationHeader);
RequestHeader.Add('Accept-Charset', 'UTF-8');
if MethodType = 'CreateFile' then begin
RequestHeader.Add('x-ms-content-length', '1024');
RequestHeader.Add('x-ms-type', 'file');
end;
client.Put('https://bcstorage.file.core.windows.net/lables/tre11.csv', content, hhtpres);
hhtpres.Content.ReadAs(res);
Message(res);
test := client.Send(request, hhtpres);
end;
0
Best Answers
-
Hello @Rahila
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.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; }
Regards6 -
Hello @Rahila,
You can add this code to the previous one: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;
And call the code whit something like this:FileName := 'AzureSharedFile.txt'; CreateFileNew(FileName); WriteText2File(FileName, 'This is a test !!!!');
Regards5
Answers
-
Hello @Rahila
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.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; }
Regards6 -
Hello @Rahila
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.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; }
Regards
Thanks for the reply, But i am working on BC14 so i cannot find the codeunit "Cryptography Management" .0 -
Hello @Rahila
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.procedure GetAccountAccessKey(): Text begin // Your Access Key exit('i0PNZ6Ykse7oSSfUzFeA36rQfAvaaJiL9LYbv9UZnol0NRM4sal4s8B3ipkjvfzcsP8/gnI58G6A=='); end;
Regards0 -
Hello @Rahila,
You can add this code to the previous one: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;
And call the code whit something like this:FileName := 'AzureSharedFile.txt'; CreateFileNew(FileName); WriteText2File(FileName, 'This is a test !!!!');
Regards5 -
hi @ftornero ..
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 :action(Create) { ApplicationArea = All; Promoted = True; PromotedCategory = Process; PromotedIsBig = True; trigger OnAction() Var FileName: Text; begin FileName := 'Test ' + FORMAT(CurrentDateTime, 0, '<Year4><Month,2><Day,2>_<Hours24,2><Filler Character,0><Minutes,2><Seconds,2>') + '.txt'; CodeunitCreateNewFile.CreateFileNew(FileName); CodeunitCreateNewFile.WriteText2File(FileName, 'This is a test !!!!'); end; }
and then codeunit exactly the sameprocedure 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;
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.0 -
and here is my config
1. GetAccountName
2. GetAccountAccessKey
SAS
is there anything that i miss?
0 -
Hello @julkifli33,
You could check your AccountAccessKey
Because if I provide a wrong one I got your error message:
Regards.0 -
Hi @ftornero
here is my screen shot
--> HYyXRecMzl/GEKQtCwWVCN9P4jehmIGa0k51KhukUMAj1fWsjVDzUC12rzDROOHjhpv5S4FKeS24zP6iDn+SXA==
and here is my code :procedure GetAccountAccessKey(): Text begin // Your Access Key exit('HYyXRecMzl/GEKQtCwWVCN9P4jehmIGa0k51KhukUMAj1fWsjVDzUC12rzDROOHjhpv5S4FKeS24zP6iDn+SXA=='); end;
is there something wrong?0 -
Hello @julkifli33
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
Regards0 -
hi ftornero,
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.
0 -
Hello @julkifli33,
I don't know, if you want you could pass me the data in a private message and I test it.
Regards.0 -
0
-
0
-
Hi @ftornero do you have any idea how to copy file (instead of writing) from local to azure storage?
because if write txt file is very limited .. i think max only 5-10mb
maybe like pdf/ jpg0 -
Hello @julkifli33,
Something like this:procedure CreateFileNew(FileName: Text; size: Integer) 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:' + Format(size, 0, 9) + 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', Format(size, 0, 0)); 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 CopyFile2AzureBlob(FileName: Text; TempBlob: Codeunit "Temp Blob") begin createFileNew(FileName, TempBlob.Length()); WriteRange(FileName, TempBlob); end;
And you can use this action:action(CopyFile) { Caption = 'CopyFile'; ToolTip = 'CopyFile'; Promoted = true; PromotedIsBig = true; Image = Copy; ApplicationArea = All; trigger OnAction(); var codunit: codeunit CreateFileNew; fileMgt: Codeunit "File Management"; fileName: Text; tmpBlob: Codeunit "Temp Blob"; begin fileName := fileMgt.BLOBImportWithFilter(tmpBlob, 'Choose file', fileName, 'All Files (*.*)|*.*', '*.*'); if fileName <> '' then codunit.CopyFile2AzureBlob(fileName, tmpBlob); end; }
Regards0 -
Hi @ftornero ,
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 - Failed0 -
error
error message : Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
0 -
Hi @ftornero ,
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.
0 -
Hello @julkifli33,
Maybe an improvement to the code is to urlencode the file name.
Anyway there is a limit in the file size.
Regards.0 -
Hi @ftornero ,
yeah it seems there is this limitation
max is 4mb
https://docs.microsoft.com/en-us/troubleshoot/azure/general/request-body-large0 -
julkifli33 wrote: »
@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.
0 -
Hello @mchruss27,
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.0 -
Hello @mchruss27,
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. cheers0
Categories
- All Categories
- 73 General
- 73 Announcements
- 66.6K Microsoft Dynamics NAV
- 18.7K NAV Three Tier
- 38.4K NAV/Navision Classic Client
- 3.6K Navision Attain
- 2.4K Navision Financials
- 116 Navision DOS
- 851 Navision e-Commerce
- 1K NAV Tips & Tricks
- 772 NAV Dutch speaking only
- 617 NAV Courses, Exams & Certification
- 2K Microsoft Dynamics-Other
- 1.5K Dynamics AX
- 320 Dynamics CRM
- 111 Dynamics GP
- 10 Dynamics SL
- 1.5K Other
- 990 SQL General
- 383 SQL Performance
- 34 SQL Tips & Tricks
- 35 Design Patterns (General & Best Practices)
- 1 Architectural Patterns
- 10 Design Patterns
- 5 Implementation Patterns
- 53 3rd Party Products, Services & Events
- 1.6K General
- 1.1K General Chat
- 1.6K Website
- 83 Testing
- 1.2K Download section
- 23 How Tos section
- 252 Feedback
- 12 NAV TechDays 2013 Sessions
- 13 NAV TechDays 2012 Sessions