WinBatch® Technical Support Forum

All Things WinBatch => WinBatch => Topic started by: stanl on June 27, 2019, 05:28:09 AM

Title: .net Restful queries
Post by: stanl on June 27, 2019, 05:28:09 AM
Consider this another learning experience.  I would like to set up a script using the WB CLR to return geocode results from: https://geocode.xyz


My understanding is queries are best made with urlencoded address.  I discovered 2 ways to encode [ script below ]. In looking at existing .net code it appears that the namespace System.Net.Http is required.  System.Net.Http.dll is on my laptop as a referenced assembly in VS Community 2019. However, ObjectClrOption() or ObjectClrNew() both return an error that the dll cannot be found. Google is full of problems with that assembly, so I'm sure it is not a WB problem that it cannot be used in a script. I can access the site with Powershell and encapsulate PS code within a WB script as the PS REST cmdlets are quite powerful. Any suggestions as to pursuing with WB CLR appreciated.
Code (WINBATCH) Select


; Winbatch 2018A - Prepare address for REST API call
;
;====================================================================================


;using last known address for Antonio Banderas
address = 'Baum Halls - 8388 Wilshire Blvd., Ste. 444 - Beverly Hills, CA 90211'
ObjectClrOption("useany", "System")


oNet = ObjectClrNew('System.Net.WebUtility')
encoded = oNet.UrlEncode(address)
Pause("Prepare address for REST API - with System.Net.WebUtility","address: ":address:@LF:"encoded: ":encoded)
oNet=0


ObjectClrOption("useany", "System.Web")
oNet = ObjectClrNew('System.Web.HttpUtility')
encoded = oNet.UrlEncode(address)
Pause("Prepare address for REST API - with System.Web.HttpUtility","address: ":address:@LF:"encoded: ":encoded)
oNet=0


Exit
 
Title: Re: .net Restful queries
Post by: td on June 27, 2019, 07:04:07 AM
Maybe missing something (have been doing a lot of that lately) but this works on my system:

Code (winbatch) Select
ObjectClrOption("useany", "System.Net.Http")
objHttpClient = ObjectClrNew('System.Net.Http.HttpClient')
Title: Re: .net Restful queries
Post by: stanl on June 27, 2019, 09:52:35 AM
Quote from: td on June 27, 2019, 07:04:07 AM
Maybe missing something (have been doing a lot of that lately) but this works on my system:

Code (winbatch) Select
ObjectClrOption("useany", "System.Net.Http")
objHttpClient = ObjectClrNew('System.Net.Http.HttpClient')



Well, those lines errored when I wrote the post, but after a huge update of VS Studio 2019 the error is gone. BTW: that address is owned by Melanie Griffith.
Title: Re: .net Restful queries
Post by: td on June 27, 2019, 02:18:42 PM
The docs claim that System.Net.Http has been around since .NET Framework 4.5 and .NET Core 1.0.  So I guess you were either a bit behind or an earlier version was a bit buggy.
Title: Re: .net Restful queries
Post by: stanl on June 30, 2019, 04:08:18 AM
Quote from: td on June 27, 2019, 02:18:42 PM
The docs claim that System.Net.Http has been around since .NET Framework 4.5 and .NET Core 1.0.  So I guess you were either a bit behind or an earlier version was a bit buggy.


My win 10 updates have a message that 1903 is coming but my pc is just not ready yet..... but as I said I can initialize the httpclient object, but can't go any further.


EDIT: I changed oClient.GetAsync(request,0) to oClient.GetAsync(request) and no longer errors. Will continue parsing the json object.


Code (WINBATCH) Select


; Winbatch 2018A - Prepare address for REST API call
;
;====================================================================================


gosub udfs
IntControl(73,1,0,0,0)
;using last known address for Antonio Banderas
url = 'https://geocode.xyz/'
address = 'Baum Halls - 8388 Wilshire Blvd., Ste. 444 - Beverly Hills, CA 90211'
ObjectClrOption("useany", "System")


oNet = ObjectClrNew('System.Net.WebUtility')
encoded = oNet.UrlEncode(address)
oNet=0


ObjectClrOption("useany", "System.Net.Http")
oClient = ObjectClrNew('System.Net.Http.HttpClient')


request =  url:encoded:'?json=1'
response = oClient.GetAsync(request,0) ;errors here, nethod not found
Pause("JSON Response",response)


oClient = 0


Exit
;====================================================================================


:WBERRORHANDLER
oClient=0
geterror()
Message("Error Encountered",errmsg)
Exit
;====================================================================================


:udfs
#DefineSubRoutine geterror()
   wberroradditionalinfo = wberrorarray[6]
   lasterr = wberrorarray[0]
   handlerline = wberrorarray[1]
   textstring = wberrorarray[5]
   linenumber = wberrorarray[8]
   errmsg = "Error: ":lasterr:@LF:textstring:@LF:"Line (":linenumber:")":@LF:wberroradditionalinfo
   Return(errmsg)
#EndSubRoutine
Return
Title: Re: .net Restful queries
Post by: stanl on June 30, 2019, 06:00:44 AM
think I'm just digging myself a deeper hole -


EDITED: I added oMsg = ObjectClrNew('System.Net.Http.HttpResponseMessage') and the script runs w/out error. Still a ways to go.

Code (WINBATCH) Select


; Winbatch 2018A - Prepare address for REST API call
;
;====================================================================================
gosub udfs
IntControl(73,1,0,0,0)
;using last known address for Antonio Banderas
url = 'https://geocode.xyz/'
address = 'Baum Halls - 8388 Wilshire Blvd., Ste. 444 - Beverly Hills, CA 90211'
ObjectClrOption("useany", "System")


oNet = ObjectClrNew('System.Net.WebUtility')
encoded = oNet.UrlEncode(address)
oNet=0


ObjectClrOption("useany", "System.Net.Http")
oClient = ObjectClrNew('System.Net.Http.HttpClient')


request =  url:encoded:'?json=1'
;FilePut(dirscript():'geocode.txt',request) ;used to make manual request to check encoding


response = oClient.GetAsync(request).Result
TimeDelay(1) ;probably not needed


oMsg = ObjectClrNew('System.Net.Http.HttpResponseMessage')
Msg = "StatusCode: ":oMsg.StatusCode:@LF
Msg = Msg:"Reason Phrase: ":oMsg.ReasonPhrase:@LF
Msg = Msg:"Content: ":oMsg.Content




Pause("Status",Msg)


oClient = 0
Exit
;====================================================================================
:WBERRORHANDLER
oClient=0
geterror()
Message("Error Encountered",errmsg)
Exit
;====================================================================================
:udfs
#DefineSubRoutine geterror()
   wberroradditionalinfo = wberrorarray[6]
   lasterr = wberrorarray[0]
   handlerline = wberrorarray[1]
   textstring = wberrorarray[5]
   linenumber = wberrorarray[8]
   errmsg = "Error: ":lasterr:@LF:textstring:@LF:"Line (":linenumber:")":@LF:wberroradditionalinfo
   Return(errmsg)
#EndSubRoutine
Return
;====================================================================================

Title: Re: .net Restful queries
Post by: stanl on July 01, 2019, 04:59:19 AM
I began to realize my initial scripting had some confusion between System.Net and Windows.Web Namespaces as they share similar classes and objects.  But using System.Net I can make requests either as


response = oClient.GetAsync(request).Result or response = oClient.GetStringAsync(request)


I can then run Pause("Result",response.ToString()) for either one.  The first returns a string with status 403: Forbidden; the second returns a string indicating a Task has been returned. In either case, the HttpResponseMessage returns 200: OK.


At this point, more interest than frustration.  I'm still in the freshman league when it comes to interpreting MSFT and .Net docs. So, Tony [or anyone else who follows this] be gentle.... I'm trying :o
Title: Re: .net Restful queries
Post by: td on July 01, 2019, 02:39:55 PM
The "oClient.GetAsync(request).Result" call returns the "System.Net.Http.HttpResponseMessage" object. You don't need to create one.  The resulting 403 error is likely because your request does not have the proper entity heads, your URL parameters are not quite right, or they simply don't want you there... 
Title: Re: .net Restful queries
Post by: td on July 01, 2019, 02:57:41 PM
Modified the URL a bit and did get a result using this replacement snippet in your code.
Code (winbatch) Select
response = oClient.GetAsync(request).Result

if Response.IsSuccessStatusCode
   TaskStr = Response.Content.ReadAsStringAsync()
   Content=TaskStr.Result
   Pause( "response",Content)
else
   Pause("response",Response.StatusCode)
endif
Title: Re: .net Restful queries
Post by: stanl on July 02, 2019, 02:45:43 AM
Hmmmm....


so my request is: https://geocode.xyz/Baum+Halls+-+8388+Wilshire+Blvd.%2C+Ste.+444+-+Beverly+Hills%2C+CA+90211?json=1 (https://geocode.xyz/Baum+Halls+-+8388+Wilshire+Blvd.%2C+Ste.+444+-+Beverly+Hills%2C+CA+90211?json=1)


If I open a browser and post it I get

{ "success": false, "error": { "code": "006", "message": "Request Throttled." } }



and if I leave off ?json=1 the entire HTML is returned. You mentioned tweaking the URL - was that a matter of re-formatting the request, or adding more .NET code earlier in the script? Your snippet [and thanks for that and the explanation] returns 403
Title: Re: .net Restful queries
Post by: td on July 02, 2019, 07:32:14 AM
The 403 error is likely the result of the URL being incorrect or the site requiring something like an app key.   I don't know what the correct form is. You have to check with the site's documentation.  I just dumped the entire page to verify that I had identified the correct FCL syntax and class objects.
Title: Re: .net Restful queries
Post by: stanl on July 02, 2019, 09:18:04 AM
Thanks.  It does work in Powershell. Only thing different 'session' is referenced,




'One Microsoft Way, Redmond',
'Baum Halls - 8388 Wilshire Blvd., Ste. 444 - Beverly Hills, CA 90211' |
ForEach-Object -Begin {$url = 'https://geocode.xyz'
   $null = Invoke-RestMethod $url -S session
} -Process {
   $address = $_
   $encoded = [Net.WebUtility]::UrlEncode($address )
   Invoke-RestMethod "$url/${encoded}?json=1" -W $session|
     ForEach-Object {
       [PSCustomObject]@{
         Address = $address
         Long = $_.longt
         Lat = $_.latt
       }
     }
}
Title: Re: .net Restful queries
Post by: JTaylor on July 02, 2019, 09:25:30 AM
Try

    https://geocode.xyz/Baum+Halls+-+8388+Wilshire+Blvd.%2C+Ste.+444+-+Beverly+Hills%2C+CA+90211?json=true

in the browser anyway.  Not sure about the other.

Jim
Title: Re: .net Restful queries
Post by: td on July 02, 2019, 11:18:32 AM
If it's not the URL then it could be a header problem or simply the site does not like some http messages the FCL class is sending.
Title: Re: .net Restful queries
Post by: JTaylor on July 02, 2019, 12:14:56 PM
That address seems a bit screwy in regards to the geocode service.  It always switches to 9107 Wilshire on me so I used my address and it returns a clean, accurate response on the web.   Oddly enough it returns the webpage with the correct mapping via WinBatch rather than the JSON.   Not sure this helps anything but I tried :)


Jim
Title: Re: .net Restful queries
Post by: td on July 02, 2019, 01:31:17 PM
Quote from: stanl on July 02, 2019, 09:18:04 AM
Thanks.  It does work in Powershell. Only thing different 'session' is referenced,




'One Microsoft Way, Redmond',
'Baum Halls - 8388 Wilshire Blvd., Ste. 444 - Beverly Hills, CA 90211' |
ForEach-Object -Begin {$url = 'https://geocode.xyz'
   $null = Invoke-RestMethod $url -S session
} -Process {
   $address = $_
   $encoded = [Net.WebUtility]::UrlEncode($address )
   Invoke-RestMethod "$url/${encoded}?json=1" -W $session|
     ForEach-Object {
       [PSCustomObject]@{
         Address = $address
         Long = $_.longt
         Lat = $_.latt
       }
     }
}


There is more than "session" being referenced that is different.
Title: Re: .net Restful queries
Post by: stanl on July 02, 2019, 02:28:31 PM
Quote from: td on July 02, 2019, 01:31:17 PM
There is more than "session" being referenced that is different.


Yes, after the results are returned, the JSON is parsed.  But, funny if I click on the url I posted or Jim followed up with the address comes up as 9107 Wilshire, but then I click again and it comes up 'throttled'. The site, I believe is the Google Geocode site and according to on thread I read -  Last year, Google changed their terms and requires an individual API key now to use their geocode API.


and the encoded REST query was purported as a alternative. Oh, and Jim - when you said it worked with WB rather than json where you referring to a COM script, i.e. WINHTTP:
Title: Re: .net Restful queries
Post by: JTaylor on July 02, 2019, 02:32:53 PM
I was using the script you provided.     I meant that in the browser the url returned JSON results.  In the script it returns the web page with the correct results.

Jim
Title: Re: .net Restful queries
Post by: stanl on July 02, 2019, 03:34:58 PM
Finally!  A little clunky but added a For...Next loop with slight Timedelay() and I get the json. Now to try to parse with Newtonsoft.
Code (WINBATCH) Select


; Winbatch 2018A - Prepare address for REST API call
; Stan Littlefield - July 2, 2019
;====================================================================================
gosub udfs
IntControl(73,1,0,0,0)
;using last known address for Antonio Banderas
url = 'https://geocode.xyz/'
address = 'Baum Halls - 8388 Wilshire Blvd., Ste. 444 - Beverly Hills, CA 90211'


ObjectClrOption("useany", "System")


oNet = ObjectClrNew('System.Net.WebUtility')
encoded = oNet.UrlEncode(address)
oNet=0


ObjectClrOption("useany", "System.Net.Http")
oClient = ObjectClrNew('System.Net.Http.HttpClient')


request =  url:encoded:'?json=1'      ;'?json=1'


FilePut(dirscript():'geocode.txt',request) ;used to make manual request to check encoding


success =0


For i = 1 To 10
   response = oClient.GetAsync(request).Result


   if Response.IsSuccessStatusCode
      TaskStr = Response.Content.ReadAsStringAsync()
      Content=TaskStr.Result
      Pause( "response",Content)
      success = 1
      Break
   Endif
   Timedelay(1)
Next


If ! success Then Pause("response",Response.StatusCode)








oClient = 0
Exit
;====================================================================================
:WBERRORHANDLER
oClient=0
geterror()
Message("Error Encountered",errmsg)
Exit
;====================================================================================
:udfs
#DefineSubRoutine geterror()
   wberroradditionalinfo = wberrorarray[6]
   lasterr = wberrorarray[0]
   handlerline = wberrorarray[1]
   textstring = wberrorarray[5]
   linenumber = wberrorarray[8]
   errmsg = "Error: ":lasterr:@LF:textstring:@LF:"Line (":linenumber:")":@LF:wberroradditionalinfo
   Return(errmsg)
#EndSubRoutine
Return
;====================================================================================


Title: Re: .net Restful queries
Post by: td on July 02, 2019, 04:05:39 PM
A simple synchronization problem with a clever workaround.
Title: Re: .net Restful queries
Post by: stanl on July 03, 2019, 02:35:47 AM
A simple tweak and you can do the reverse - find address based on lat/long. No encoding is required and it appears it might even return a phone number
Code (WINBATCH) Select


; Winbatch 2018A - Obtain Address from Latitude, Longitude
; Stan Littlefield - July 3, 2019
;====================================================================================
gosub udfs
IntControl(73,1,0,0,0)
url = 'https://geocode.xyz/'
LatLong = '34.06711,-118.39047'
ObjectClrOption("useany", "System")
;encoding is not required


ObjectClrOption("useany", "System.Net.Http")
oClient = ObjectClrNew('System.Net.Http.HttpClient')
request =  url:LatLong:'?geoit=json' 
success =0


For i = 1 To 10
   response = oClient.GetAsync(request).Result
   if Response.IsSuccessStatusCode
      TaskStr = Response.Content.ReadAsStringAsync()
      Content=TaskStr.Result
      Pause( "response",Content)
      success = 1
      Break
   Endif
   Timedelay(1)
Next


If ! success Then Pause("response",Response.StatusCode)


oClient = 0
Exit
;====================================================================================
:WBERRORHANDLER
oClient=0
geterror()
Message("Error Encountered",errmsg)
Exit
;====================================================================================
:udfs
#DefineSubRoutine geterror()
   wberroradditionalinfo = wberrorarray[6]
   lasterr = wberrorarray[0]
   handlerline = wberrorarray[1]
   textstring = wberrorarray[5]
   linenumber = wberrorarray[8]
   errmsg = "Error: ":lasterr:@LF:textstring:@LF:"Line (":linenumber:")":@LF:wberroradditionalinfo
   Return(errmsg)
#EndSubRoutine
Return
;====================================================================================


Title: Re: .net Restful queries
Post by: stanl on July 04, 2019, 05:19:46 AM
NOTES:
Title: Re: .net Restful queries
Post by: td on July 04, 2019, 08:31:59 AM
You can't load the assemblies because they are not in the GAC.  For example, on my system I would need to do the following:

Code (winbatch) Select
ObjectClrOption('Appbase', 'C:\Program Files (x86)\Microsoft Visual Studio\Shared\Packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45')
ObjectClrOption("useany", "System.Web.Helpers")


Of course you can move the assembly to a different location or install it into the GAC.
Title: Re: .net Restful queries
Post by: stanl on July 04, 2019, 12:03:19 PM
That would have been my next question. But I was worried about when to call 'appbase' in the script - i.e. if called early would it override subsequent calls to ObjectClrOption() that might be in the GAC? For example:
Code (WINBATCH) Select


ObjectClrOption("useany", "System")
ObjectClrOption('Appbase', 'C:\Program Files (x86)\Microsoft Visual Studio\Shared\Packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45')


will error that 'Runtime has already been loaded'.  Who's on First...What's on second : you know the drill


EDIT: But put it in the GAC - thanks


C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.7.2 Tools>gacutil /i "C:\Program Files (x86)\Microsoft Visual Studio\Shared\Packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll"
Microsoft (R) .NET Global Assembly Cache Utility.  Version 4.0.30319.0
Copyright (c) Microsoft Corporation.  All rights reserved.


Assembly successfully added to the cache


Title: Re: .net Restful queries
Post by: td on July 04, 2019, 05:40:51 PM
Setting the "appbase" should not affect the loading of GAC assemblies.  However, you need to set "appBase" at the beginning of your script.
Title: Re: .net Restful queries
Post by: stanl on July 05, 2019, 02:31:59 AM
Quote from: td on July 04, 2019, 05:40:51 PM
Setting the "appbase" should not affect the loading of GAC assemblies.  However, you need to set "appBase" at the beginning of your script.


Thanks. Added a UDS to call the System.Web.Helpers.Json.Decode() method and that errors as 'Ambiguous Match Found'. This seems to be a problem with the same name of an element with different cases.
Code (WINBATCH) Select


; Winbatch 2018A - Prepare address for REST API call
; Stan Littlefield - July 2, 2019
;====================================================================================
gosub udfs
IntControl(73,1,0,0,0)
;using last known address for Antonio Banderas
url = 'https://geocode.xyz/'
fmts = '?json=1,?geoit=xml,?geoit=csv'
fmt = Itemextract(1,fmts,",")
address = 'Baum Halls - 8388 Wilshire Blvd., Ste. 444 - Beverly Hills, CA 90211'     


ObjectClrOption("useany", "System")


oNet = ObjectClrNew('System.Net.WebUtility')
encoded = oNet.UrlEncode(address)
oNet=0


ObjectClrOption("useany", "System.Net.Http")
oClient = ObjectClrNew('System.Net.Http.HttpClient')


request =  url:encoded:fmt     
FilePut(dirscript():'geocode.txt',request) ;used to make manual request to check encoding


success =0


For i = 1 To 10
   response = oClient.GetAsync(request).Result


   if Response.IsSuccessStatusCode
      TaskStr = Response.Content.ReadAsStringAsync()
      Content=TaskStr.Result
      If fmt== '?json=1'
         Pause("response",parsejson())
      Else
         Pause( "response",Content)
      Endif
      success = 1
      Break
   Endif
   Timedelay(1)
Next


If ! success Then Pause("response",Response.StatusCode)








oClient = 0
Exit
;====================================================================================
:WBERRORHANDLER
oClient=0
geterror()
Message("Error Encountered",errmsg)
Exit
;====================================================================================
:udfs
#DefineSubRoutine geterror()
   wberroradditionalinfo = wberrorarray[6]
   lasterr = wberrorarray[0]
   handlerline = wberrorarray[1]
   textstring = wberrorarray[5]
   linenumber = wberrorarray[8]
   errmsg = "Error: ":lasterr:@LF:textstring:@LF:"Line (":linenumber:")":@LF:wberroradditionalinfo
   Return(errmsg)
#EndSubRoutine


#DefineSubRoutine parsejson()
   IntControl(73,1,0,0,0)
   ObjectClrOption("useany", "System.Web.Helpers")
   oJson = ObjectClrNew('System.Web.Helpers.Json')
   result= oJson.Decode(Content)
   Pause("decoded",ObjectTypeGet(result))
   oJson=0
   Return(result)
   
   :WBERRORHANDLER
   oJson=0
   oClient=0
   geterror()
   Message("Error Encountered",errmsg)
   Exit
#EndSubRoutine
Return
;====================================================================================


Title: Re: .net Restful queries
Post by: td on July 05, 2019, 09:15:53 AM
I think you have encountered a side-effect of generic programming. Mscorelib can't resolve the method signature because of the template based return type.  Don't know that there is a workaround that would allow you to call the "Decode" method directly.
Title: Re: .net Restful queries
Post by: stanl on July 05, 2019, 09:26:15 AM
Quote from: td on July 05, 2019, 09:15:53 AM
I think you have encountered a side-effect of generic programming. Mscorelib can't resolve the method signature because of the template based return type.  Don't know that there is a workaround that would allow you to call the "Decode" method directly.


Yeah. Tested it directly [below]. Maybe try serialization class next. Funny that Json is so poplar and .net json parsing is so frustrating.
Code (WINBATCH) Select


j = '{   "standard" : {      "stnumber" : "9107",      "addresst" : "WILSHIRE BLVD",      "postal" : "90210-5596",      "region" '
j = j: ': "CA",      "prov" : "US",      "city" : "BEVERLY HILLS",      "countryname" : "United States of America",      "confidence" : "0.7"   }, '   
j = j: '"longt" : "-118.39047",   "alt" : {},   "elevation" : {},   "latt" : "34.06711"}'
ObjectClrOption("useany", "System.Web.Helpers")
oJ = ObjectClrNew('System.Web.Helpers.Json')
myj= oJ.Decode(j)
Pause("decoded",ObjectTypeGet(myj))
oj=0
Exit
Title: Re: .net Restful queries
Post by: td on July 05, 2019, 10:21:02 AM
I suppose you could try wrapping the Parse method in a c# class that you compile on the fly or into an assembly that you load and call from WinBatch.
Title: Re: .net Restful queries
Post by: stanl on July 06, 2019, 03:31:03 AM
Quote from: td on July 05, 2019, 10:21:02 AM
I suppose you could try wrapping the Parse method in a c# class that you compile on the fly or into an assembly that you load and call from WinBatch.


Or I suppose I could revert to COM and dig out an old function I dug up for a script I put together with Delev in 2012. It does a fair job with the JSON. but StrReplace() lines fail for invalid Null Character. I checked the tech db for removing nulls but cam up blank.
Code (WINBATCH) Select


; Winbatch 2018A - Prepare address for REST API call
; Stan Littlefield - July 2, 2019
;
; Revision: CreateObject ("MSScriptControl.ScriptControl")  used for JSON
;           instead of .net class
;====================================================================================
gosub udfs
IntControl(73,1,0,0,0)
;using last known address for Antonio Banderas
url = 'https://geocode.xyz/'
fmts = '?json=1,?geoit=xml,?geoit=csv'
fmt = Itemextract(1,fmts,",")
address = 'Baum Halls - 8388 Wilshire Blvd., Ste. 444 - Beverly Hills, CA 90211'     


ObjectClrOption("useany", "System")


oNet = ObjectClrNew('System.Net.WebUtility')
encoded = oNet.UrlEncode(address)
oNet=0


ObjectClrOption("useany", "System.Net.Http")
oClient = ObjectClrNew('System.Net.Http.HttpClient')


request =  url:encoded:fmt     
;FilePut(dirscript():'geocode.txt',request) ;used to make manual request to check encoding


success =0


For i = 1 To 10
   response = oClient.GetAsync(request).Result


   if Response.IsSuccessStatusCode
      TaskStr = Response.Content.ReadAsStringAsync()
      Ct=TaskStr.Result
      ;FilePut(dirscript():'results.txt',Ct)
      If fmt== '?json=1'
         Ct = GetJSON(Ct)
         ;Ct = StrReplace(Ct,"|",""}
         ;Ct = StrReplace(Ct,",","="}
         ;Ct = StrReplace(Ct,@LF,@CRLF}
         FilePut(dirscript():'results.txt',Ct)
         Pause("response",Ct)
      Else
         Pause( "response",Content)
      Endif
      success = 1
      Break
   Endif
   Timedelay(1)
Next
If ! success Then Pause("response",Response.StatusCode)
oClient = 0
Exit
;====================================================================================
:WBERRORHANDLER
oClient=0
geterror()
Message("Error Encountered",errmsg)
Exit
;====================================================================================
:udfs
#DefineSubRoutine geterror()
   wberroradditionalinfo = wberrorarray[6]
   lasterr = wberrorarray[0]
   handlerline = wberrorarray[1]
   textstring = wberrorarray[5]
   linenumber = wberrorarray[8]
   errmsg = "Error: ":lasterr:@LF:textstring:@LF:"Line (":linenumber:")":@LF:wberroradditionalinfo
   Return(errmsg)
#EndSubRoutine




#DefineFunction GetJSON(strJSON)
If strJSON == "" Then Return ""
objJSC = CreateObject ("MSScriptControl.ScriptControl")
objJSC.Language = "JScript"
objJSC.AddCode(: `function json2txt(obj,path){var txt='';for(var key in obj){if(obj.hasOwnProperty(key)){if('object'==typeof(obj[key])){txt+=json2txt(obj[key],path+(path?'|':'')+key);}else{txt+=path+'|'+key+','+obj[key]+'\n';}}}return txt;}`)
Return objJSC.Eval(: `json2txt(` : strJSON : `,'')`)
; JS code from Patrick Fisher at "http://stackoverflow.com/questions/10221229/list-all-keys-and-values-of-json" ; 2012-04-19T03:48:24.
#EndFunction
Return
;====================================================================================


Title: Re: .net Restful queries
Post by: td on July 06, 2019, 09:44:30 AM
Likely missing something again but not sure what you mean by "StrReplace() lines fail for invalid Null Character".  I uncommented the three StrReplace lines in your script, correct the right-brace typo, and the script completed without error.

I am still interested in discovering what MSFT's Decode method produces as a data object.  Might take a hack at this weekend if time permits.
Title: Re: .net Restful queries
Post by: stanl on July 07, 2019, 06:40:09 AM
Quote from: td on July 06, 2019, 09:44:30 AM
Likely missing something again but not sure what you mean by "StrReplace() lines fail for invalid Null Character".  I uncommented the three StrReplace lines in your script, correct the right-brace typo, and the script completed without error.

I am still interested in discovering what MSFT's Decode method produces as a data object.  Might take a hack at this weekend if time permits.


Yeah, I fat-fingered the braces. Been having problems getting to the forum since my last post. Kept getting 404 server error.
Title: Re: .net Restful queries
Post by: td on July 07, 2019, 05:44:29 PM
Notices the same problem this afternoon.  Either our ISP or DNS provider is having "issues."
Title: Re: .net Restful queries
Post by: stanl on July 07, 2019, 05:46:05 PM
For fun instead of GetAsync I tried:
Code (WINBATCH) Select

response = oClient.PostAsync(url,encoded:fmt).Result



and that returned 'unsupported variant type'
Title: Re: .net Restful queries
Post by: td on July 08, 2019, 07:42:06 AM
Not sure what you attempting to do with the "encoded:fmt" parameter but "encoded" certainly isn't a valid variant type.  In order to supply parameter type information with a call to a class method, type information must be a valid variant type or a valid fully qualified .Net assembly type.  For example, "System.Net.Http.HttpContent" is the type indicated for the second parameter to the PostAsync method.  Of course, the parameter's value would also need to be an instance of an HttpContent object.
Title: Re: .net Restful queries
Post by: td on July 08, 2019, 09:26:11 AM
Did a quick search on the system for .burgerFlipper examples parsing json and surprisingly found several.  Here is one of them:

Code (winbatch) Select
jsonText=$"{"menu":: {
    "header":: "SVG Viewer",
    "items":: [
        {"id"::  "Open"},
        {"id"::  "OpenNew", "label":: "Open New"},
        null,
        {"id"::  "ZoomIn", "label":: "Zoom In"},
        {"id"::  "ZoomOut", "label":: "Zoom Out"},
        {"id"::  "OriginalView", "label":: "Original View"},
        null,
        {"id":: "Quality"},
        {"id":: "Pause"},
        {"id":: "Mute"},
        null,
        {"id":: "Find", "label":: "Find..."},
        {"id":: "FindAgain", "label":: "Find Again"},
        {"id":: "Copy"},
        {"id":: "CopyAgain", "label":: "Copy Again"},
        {"id":: "CopySVG", "label":: "Copy SVG"},
        {"id":: "ViewSVG", "label":: "View SVG"},
        {"id":: "ViewSource", "label":: "View Source"},
        {"id":: "SaveAs", "label":: "Save As"},
        null,
        {"id":: "Help"},
        {"id":: "About", "label":: "About Adobe CVG Viewer..."}
    ]
}}$"


; Assemblies used.
ObjectClrOption("useany", 'System.Xml.Linq')
ObjectClrOption("useany", 'System.Runtime.Serialization')

; Load the json text into a byte array.
Encoding = ObjectClrNew('System.Text.Encoding')
ByteArrayJson = Encoding.UTF8.GetBytes(jsonText)

;Creates An XmlDictionaryReader that can process JavaScript Object Notation (JSON) data.
objJsonRWFactory = ObjectClrNew('System.Runtime.Serialization.Json.JsonReaderWriterFactory')
XmlDictionaryReaderQuotas = ObjectClrNew('System.Xml.XmlDictionaryReaderQuotas')
objReader = objJsonRWFactory.CreateJsonReader( ByteArrayJson, XmlDictionaryReaderQuotas.Max)

objXElement = objectClrNew("System.Xml.Linq.XElement")
objRoot     = objXElement.Load(objReader)

;; Create a few XName objects for later use.
objXName     = objectClrNew("System.Xml.Linq.XName")
objNameItems = objXName.Get("items")
objNameItem  = objXName.Get("item")
objNameId    = objXName.Get("id")

; Get the Id values.
objColMenus = objRoot.Elements(objXName.Get("menu"))
foreach objMenus in objColMenus
   objColItems = objMenus.Elements(objNameItems)
   foreach objItems in objColItems
      objColItem = objItems.Elements(objNameItem)
      foreach objItem in objColItem
         objColId = objItem.Elements(objNameId)
         foreach objId in objColid
            Pause("objId.Value", objId.Value)
         next
      next
   next
next
Title: Re: .net Restful queries
Post by: stanl on July 08, 2019, 02:07:02 PM
Quote from: td on July 08, 2019, 07:42:06 AM
Not sure what you attempting to do with the "encoded:fmt" parameter but "encoded" certainly isn't a valid variant type. 


Basically these were variables created earlier in the script, so the line would be interpreted as:


response oClient.PostAsync('https://geocode.xyz/','Baum Halls - 8388 Wilshire Blvd., Ste. 444 - Beverly Hills, CA 90211?json=1'.Result


and one of the classes of PostAsync was uri,string
Title: Re: .net Restful queries
Post by: stanl on July 08, 2019, 02:29:39 PM
Quote from: td on July 08, 2019, 09:26:11 AM
Did a quick search on the system for .burgerFlipper examples parsing json and surprisingly found several.  Here is one of them:


Yeah, in a earlier post I mentioned about trying serialization. Probably would have generated a whole new thread walking through re-fitting C# examples into WB - but you have significantly added to the topic.
Title: Re: .net Restful queries
Post by: td on July 09, 2019, 07:57:19 AM
Quote from: stanl on July 08, 2019, 02:07:02 PM
Quote from: td on July 08, 2019, 07:42:06 AM
Not sure what you attempting to do with the "encoded:fmt" parameter but "encoded" certainly isn't a valid variant type. 


Basically these were variables created earlier in the script, so the line would be interpreted as:


response oClient.PostAsync('https://geocode.xyz/','Baum Halls - 8388 Wilshire Blvd., Ste. 444 - Beverly Hills, CA 90211?json=1'.Result


and one of the classes of PostAsync was uri,string

The PostAsync method has 4 overloads.  Two of them take two parameters.  In both cases, the second parameter is a reference to a HttpContent class object.  The HttpContent object contains the data enclosed in the body of the HTTP POST request message that is sent to the server.