11.7
Why do I get an array error doing this?
UploadValues(Uri, String, NameValueCollection) |
Uploads the specified name/value collection to the resource identified by the specified URI, using the specified Method. |
The UploadValues method of the web client returns a Byte array.
def var foo as "System.Byte[]".
foo = <your statement>.
Now you need to do something with the byte array. You could either pass it to another .net method if appropriate or convert it to something usable in the Progress world. The method below will convert a byte array to a memptr. From there you can do what's needed.
METHOD PUBLIC STATIC MEMPTR ByteArrayToMemptr( nBytes AS "System.Byte[]" ):
DEFINE VARIABLE nPtr AS System.IntPtr NO-UNDO.
DEFINE VARIABLE mPtr AS MEMPTR NO-UNDO.
DEFINE VARIABLE PointerLoc AS INT64 NO-UNDO.
set-size(mPtr) = nBytes:LENGTH.
/* In 11.7, due to the new compile used, Progress is much more likely to choose
a memory pointer that exceeds the 32 bit limit of an integer.
Using this intermediate INT64 solves the problem */
PointerLoc = GET-POINTER-VALUE(mPtr).
nPtr = NEW System.IntPtr(PointerLoc).
System.Runtime.InteropServices.Marshal:Copy(nBytes, 0, nPtr, nBytes:LENGTH).
RETURN mPtr.
FINALLY:
nPtr = ?.
nBytes = ?.
set-size(mPtr) = 0.
END.
END METHOD.
Array on the right-hand side is the Byte[] array returned by UploadValues. You're assigning it to what appears to be a longchar. That does not compute...
aaah, what would be the correct approach ? Can't do a
def var lcResponse as longchar extent no-undo.
The UploadValues method of the web client returns a Byte array.
def var foo as "System.Byte[]".
foo = <your statement>.
Now you need to do something with the byte array. You could either pass it to another .net method if appropriate or convert it to something usable in the Progress world. The method below will convert a byte array to a memptr. From there you can do what's needed.
METHOD PUBLIC STATIC MEMPTR ByteArrayToMemptr( nBytes AS "System.Byte[]" ):
DEFINE VARIABLE nPtr AS System.IntPtr NO-UNDO.
DEFINE VARIABLE mPtr AS MEMPTR NO-UNDO.
DEFINE VARIABLE PointerLoc AS INT64 NO-UNDO.
set-size(mPtr) = nBytes:LENGTH.
/* In 11.7, due to the new compile used, Progress is much more likely to choose
a memory pointer that exceeds the 32 bit limit of an integer.
Using this intermediate INT64 solves the problem */
PointerLoc = GET-POINTER-VALUE(mPtr).
nPtr = NEW System.IntPtr(PointerLoc).
System.Runtime.InteropServices.Marshal:Copy(nBytes, 0, nPtr, nBytes:LENGTH).
RETURN mPtr.
FINALLY:
nPtr = ?.
nBytes = ?.
set-size(mPtr) = 0.
END.
END METHOD.
The correct approach would be to read the manuals so that you actually know what you are doing ;-)
An even better approach would be to stop using .NET and use the 4GL instead, although with SSL/TLS that can be tricky I have to admit.
Byte[] suggests memptr...
I am taking the Learning by trying, but I should probably do learning by Reading [:)].
I forgot to check the Return value… It went from string to byte array… my bad ! [:)]
I was uploading and was not thinging that the returnvalue was changed.
Sorry for that !
I've created an ABL equivalent using the HTTP client. It's at https://github.com/PeterJudge-PSC/http_samples/blob/master/http_client/post_form_name_value.p
The meat of it is below (minus variable defs and usings)
assign hc = ClientBuilder:Build():Client // the first param is a realm you can leave blank creds = new Credentials('':u, clientId, clientSecret) . // build the request req = RequestBuilder:Post(tokenEndpoint, // prior to 11.7.3 you had to pass in a valid object here. in 11.7.3+ you can not new StringStringMap() ) :AddFormData('client_id', 'oidc_ovf_conf') :AddFormData('grant_type','authorization_code') :UsingBasicAuthentication(creds) :Request. // make the request resp = hc:Execute(req). // process the response message resp:StatusCode skip // 200 is all went well resp:ContentType skip // something like application/json or application/x-www-form-urlencoded resp:ContentLength skip // number of bytes, if you care view-as alert-box. // this Entity property is DEFINED as Progress.Lang.Object // but the actual class/type will be something else; typically something that matches the ContentType // now get the response data in a nice, strongly-typed Object form // We can either decide what to do based on the ContentType or on the object's type // approach 1 case resp:ContentType: when 'application/json':u then assign jsonData = cast(resp:Entity, JsonObject). // other types end case.