Workflow WebRequest conversion to featureset
Hi,
I have a workflow that captures a geometry and sends it to an extension by WebRequest.
The WebRequest receives its response as a Byte Array. The response is in JSON and contains a series of PolyLines and MapPoints. Is there any way to convert this Byte Array to a FeatureSet or Collection of Geometry?
Kind Regards,
Ibrahim
-
Hi Ibrahim,
You may want to first convert the byte array to a string. Assuming you have a variable called "bytes" you can use an Assign activity with an expression like this to get the JSON string:
System.Text.Encoding.Unicode.GetString(bytes)
Parsing the JSON into geometry objects may be more difficult. It will really depend on the structure of your JSON object.
-
If your JSON represents an Esri FeatureSet then you can use:
- ESRI.ArcGIS.Client.Tasks.FeatureSet.FromJson(json)
-
If your JSON represents a single Esri geometry you can use:
- Geocortex.Essentials.Client.RestUtility.GetGeometryFromJson(json)
- If your JSON represents some other structure you'll probably need to parse it manually. I'd suggest writing a custom activity to do this.
--Ryan
0 -
If your JSON represents an Esri FeatureSet then you can use:
-
Hi Ryan
I have a similar issue raised (http://support.geocortex.com/Forums/Thread.aspx?pageid=0&mid=2&ItemID=20&thread=47258) here that I need to be able to parse the JSON returned from a 'Cut' request to the Geometry Server.
When you suggest writing a Custom Activity to do this do you have a methodology for dealing with JSON already? My current thoughts are using (http://json.codeplex.com/) JSON.Net in terms of being a tool that will hopefully fit tidily in the Workflow environment.
Unfortunately your suggestion above in regards to dealing with a Featureset or single Geometry doesn't quite match what will be returned from a Cut operation as far as I can make out. Similar but not quite.
Thanks
Ralph
0 -
Ah I see, guess I'll have to make my own activity then. Can't seem to find anything about it in the manual though, am I just missing it or will I have to search for instructions about writing custom activities elsewhere? A push in the right direction would be nice. :)
Also, when I convert the byte array to String and then run a simulation that outputs that string in an Alert, the String is just jumbled characters. What am I doing wrong? Perhaps I need to wait for the response to be completely received, or does the WebRequest activity handle that already in itself?
EDIT: Is it possible to decode the JSON to an Object so that I could call specific fields in the response?
0 -
Figured out the second part of my question myself, it was just a matter of decoding UTF8 instead of Unicode, d'Oh!
0 -
I have assigned the JSON string (traceResultJSON) to an Object by using Jayrock.Json.Conversion.JsonConvert.Import(traceResultJSON).
I now want to assign a attribute of the Object to a String type variable, but I can't seem to get it working. All I get is a "disallows late binding" error. I know this error pops up when types don't match, but even if I call traceResultsObject.records and assign it to a Object type variable i get that error message.
At first I thought it was a syntax thing (I'm new to VB) but I looked it up and it seems like I'm using the correct syntax.
An explicit cast doesn't seem to do the trick either.
/customer/servlet/servlet.FileDownload?file=00P6000000e88HUEAY
/customer/servlet/servlet.FileDownload?file=00P6000000e88BDEAY
0 -
Hi Ibrahim,
Parsing JSON using in a workflow using Assign activities and VB expressions is possible but it is usually quite awkward.
Jayrock.Json.Conversion.JsonConvert.Import(traceResultJSON) will return an Object, however that object is typically really a Jayrock.Json.JsonObject or a Jayrock.Json.JsonArray. If you cast to the appropriate type you can then access the child properties. It might look something like this in VB:
CType(traceResultObject, Jayrock.Json.JsonObject)("records")
We are taking the plain old Object, casting it to a JsonObject, then accessing the "records" index/value. This will return an Object again, so we might need to cast again. You can see that this will get pretty messy if you need to drill into the JSON to get your values. We generally prefer to create specific activities or utility methods to handle this sort of scenario. This keeps the workflow much cleaner.
--Ryan
0 -
It is possible to parse a JSON string in a Workflow without external libraries using a 'Geocortex.Workflow.ExternalObject'. See this page for a discussion of the technique:
https://support.geocortex.com/parcel-selection-buffering-and-report-workflow
Scroll down to the section 'Parsing a REST endpoint in Workflow (ADVANCED)'. This is used in the attached workflow to get a list of valid reports from the site.
0 -
Hi Ralph,
You asked about JSON parsing libraries... both JSON.NET and Jayrock.Json are currently used by Essentials under the hood so you can use either of them. Both of these work well and offer very similar capabilities.
My first recommendation would be to use this utility method that is part of the Geocortex API:
Geocortex.Workflow.Runtime.Serialization.SerializationUtility.JsonDecode(json)
It uses .NET's built-in JavaScriptSerializer (rather than depending on a 3rd party library). It really depends on the JSON text you pass to it, but this will usually return you an IDictionary<string, object> or an IEnumerable<object>.
--Ryan
0 -
Hi Jonathan and Ryan
i have been this morning trying to follow through getting the section on this page https://support.geocortex.com/parcel-selection-buffering-and-report-workflow that you suggested with my own problem/situation but was having no joy so have now resorting to just getting the Parcel Report Workflow to work. (This is with GE3.10 and SL1.6)
Unfortunately it is not with getting an 'Aborted Exception: The given key was not present in the dictionary'
The URL that I am using is http://gisagsdev.rdc.govt.nz/Geocortex/Essentials/REST/sites/AddressEditing/map/mapservices/1/layers/2/reports?f=pjson
which if I manually run it returned this JSON:
{
There is a Assign activity immediately before the ForEach loop that is looking for 'reports' which I would expect to be present
When I try to show in an Alert what I get an exception regarding not being able to serialize a System.Net.Webrequest+WebProxyWrapper
Do you have any recommendations about how best to track down what key is not present?
Thanks
Ralph
0 -
If there is security present on this REST endpoint it may be that Workflow cannot make the connection to download this JSON string, leading to the error. This is a known issue, and in this case you may just have to hardcode the list of reports into the Workflow.
An Alert task cannot be used for debugging here, as the 'WebClient' object cannot be serialized. You should be able to use the 'Log' task though. This will write messages to your REST logs, located in ..\REST Elements\REST\App_Data\Logs.
0 -
Hi Jonathan and Ryan
part of the problem was inmy configuration of the workflow where there was a mis-spelling of one of Layer id. Once that was resolved then it worked.
So from there I was then trying to use the methodology for the JSON that I really wanted to deal with. Essentially I want to process the JSON that makes up features for use in a Cut operation.
I assume that there is documentation for the ExternalObject object in the Essentials API documentation at: https://resources.geocortex.com/Login.aspx?ReturnUrl=%2fessentials%2fapis
Unfortunately I am currently getting an error accessing that resource as far as what methods are available against it.
I am getting the following:
Exception has been thrown by the target of an invocation.
when I am trying an Assign using:
CType(jsonResponseObject.GetValue("paths"),object())
when trying to get the paths in the JSON representing the feature:
{
The above feature is going to be the basis of the cutter of my Cut request.
I also need to do the same with the target geometry to be cut and then process the results to get a couple of new features and then I will want to know how long those lines are.
So parsing the JSON is core to what I am doing since the Cut Activity is yet to be included in the list of ArcGIS Server activities.
Thanks
Ralph Price
0 -
Thanks Jonathan and Ryan,
Your indications has helped me a bit further down the path. I now get no more compile time errors, but I do get a runtime error and I can't seem to find anything on the error by traditional means.
I tried converting the JSON string using the method described in the link Jonathan provided. It's the assignment of the JSON string to the ExternalObject.Json that throws the error.
screenshot of the relevant workflow part:
/customer/servlet/servlet.FileDownload?file=00P6000000e88HZEAY
The JSON as String:
"{\"edgeGeometries\":[{\"paths\":[]}],\"junctionGeometries\":[{\"paths\":[]},{\"points\":[]}],\"records\":\"Soort water_label:86469,86468,86465,86464,86467,86466,90893,95702,95753,95789,95863,95746,95664,95672,95406,95435,95432,95436,95942,95410,95946,95948,95066,95065,95870,95878,95881,83579,83580,83593,83594,86531,86347,86346,86419,86418,86534,86535,86282,86283,86540,86538,86539,86536,90550,90551,86514,86513,90560,90554,90555,90609,90650,90649,91258,91266,86542,90898,90861,90904,90864,90863,90854,90812,90870,90805,90813,90820,90821,91427,91385,91428,91436,95879,95895,95084,95899,95896,95897,95904,95913,95905,95919,95924,95920,95923,95925,96590,95968,96048,96047,96054,96046,96589,96584,95966,96640|Pomp:133,131,132,137,138,139,12,404|Interne persleiding:154,155,153,24,142,143,144,158,159|Overstort:501,451,236,41|Schuif:197|Rooster:14|Putten / knopen:50223,50222,50266,50265,54251,58427,58462,58553,58497,58470,58399,58406,58165,58166,58202,58205,58171,58206,58623,58626,58628,58630,58629,58568,58560,58571,47596,47595,50085,50086,50148,50147,50324,50323,50326,50327,53947,53948,53956,53957,53958,53951,53952,54004,54053,54052,54462,54469,50330,50331,54228,54255,54222,54189,54190,54233,54183,54197,54198,54609,54610,54617,54572,54575,58604,58569,58584,58645,58588,58585,58586,58593,58601,58594,58603,58608,58607,58609,58672,58674,58741,58739,58740,43456,43458,43452|Connectiepunten:3192,3191,3916,3918,3917,3970,2939,2940,3198,3201,3189,3190,3477,3195,3196,3478,3479,3476,2248,2241,2240,3985,4046,4049,4048,4045\"}"
The error:
/customer/servlet/servlet.FileDownload?file=00P6000000e88HeEAI
0 -
Nevermind, I fixed it by combining Jonathan's and Ryan's approaches. I'm still curious about what caused that "L-value" error though.
0 -
Hi Ibrahim
could you post what you did to solve your problem when you say you combined Jonathan's and Ryan's approaches?
Thanks
Ralph
0 -
I took the byte stream from my web request and converted it to a String:
traceResultJSON = System.Text.Encoding.UTF8.GetString(traceResultStream)
Then I converted that String to an Object:
traceResultObject = Jayrock.Json.Conversion.JsonConvert.Import(traceResultJSON)
Converted the Object to JSONObject:
traceResultJSONObject = CType(traceResultObject, Jayrock.Json.JsonObject)
From there I could access the parameters in the JSONObject:
records = traceResultJSONObject("records").toString()
0 -
@Ralph
If you examine that JSON object closely you will see that the 'paths' object array is contained within another array called 'features', which in this case contains only a single element.
So, since 'paths' is not present at the top level you get a 'key not present in dictionary' error when trying to access it. If you add an extra step and assign the element(s) of the 'features' array to some sort of JSON object you should then be able in turn to extract the 'paths'.
0 -
Hi Jonathan and Ibrahim
I managed to bash the problem enough that I got it to work. ;-)
One thing I have done is to make a Custom Activity for use in Workflow that takes the polyline (target) that I want to Cut as a Json serialized FeatureSet along with another Featureset (cutter), a Geometry service and I end up returned a serialized Featureset. I make use of JSON.Net within the Custom Activity.
The returned featureSet is then used in a Lengths activity and an Alert informs the user of the two centreline lengths.
I guess that I was hoping that there was a syntax (and probably there is with LINQ) to get all of the "paths" at once in a similar way that you might using XPath with XML to get a NodeList ie xmlDoc.SelectNodes("//paths")
Thanks for your assistance
Ralph
0 -
Glad it is working now. Inspired by your hard work... we will be adding an activity for the next release that wraps the Cut geometry service operation. It will have a little different signature, but should get to the same result.
--Ryan
0 -
Hi Ryan
that is great news. Happy to have had the experience. Curious on what other functions would be covered. See https://support.geocortex.com/SupportForums/Thread.aspx?thread=47258&mid=2&pageid=0&ItemID=20
Thanks
Ralph
0 -
Hey guys,
I know this is an old thread, but I'm having a hard time with deserializing a JSON object, returned from a web request and I'm not sure why....
I have followed Ibrahim's guidance and have got so for to getting my web request's text into a JSONObject, but where it fails, is getting a parameter from the object. If I cast the Object to a string, I get the full JSON as text:
{
"workspaceID":"vt20150615091336171000",
{
"name":"delineatedbasin",
"geometryType":"esriGeometryPolygon",
"wkid":102100
},
{
"geometry":{
"rings":[
[
[
-8122241.7254000008,
],
-8122241.6466000006,
],
-8122255.5976,
],
-8122241.7254000008,
]
]
]
},
"objectid":1,
}
}
]
}
}
],
"Start Time: Mon Jun 15 09:13:45 2015 Delineating global watershed for batchpoint 1 of 1. dt=0.03s 1 global watershed(s) successfully delineated. Succeeded at Mon Jun 15 09:13:53 2015 (Elapsed Time: 8.00 seconds)"
]
}
Now, if I try to access the "delineatedbasin" parameter as: JSONObject("delineatedbasin").ToString
I get a: "Object reference not set to an instance of an object."
Any ideas why that may be? The JSON is properly formatted. It's validated. I have had this working before... I don't know what I did.
0
Please sign in to leave a comment.
Comments
20 comments