Using Rest API in C#

9475
3
06-19-2013 05:00 AM
MarkAndrews
New Contributor
I have a rather simple problem that I would like a simple solution to.  I have a non-GIS website that I want to be able to use the query and buffer functions of ArcGIS Server to query data in the GIS database.  The website is written in .Net and the version of ArcGIS Server is 10.1.  In the previous version of the APP I used ArcObjects and the WebADF to do this query, but I would like to move away from that if I can.  I have consumed the REST API using C# in another application but never the Buffer Operation and it seemed deserializing the JSON of a complex polygon is rather difficult.  I must be missing something simple and wanted some direction.

Here is the steps:

1.  User makes some advanced query requests, Give me all the property with X,Y,Z within a mile or two of a certain piece of property.

2.  If there is no spatial component, I would just query the SQL database using C#.  There are multiple tables not registered with the Geodatabase that need to be queried.

3.  With the spatial component, I want to get a list of properties that meet the spatial query criteria and then see which one of those meet the criteria for the non-spatial data queries (or vice versa whichever is simpler)

Which technology should I use to achieve this function in C#.

Mark
0 Kudos
3 Replies
MarkAndrews
New Contributor
Private Function doBuffer() As String
        Dim y1 = 551215.00819465192
        Dim y2 = 613015.459091723
        Dim x1 = 584470.22833333921
        Dim x2 = 770134.56166666746

        Dim x As Double = ((x2 - x1) / 2) + x1
        Dim y As Double = ((y2 - y1) / 2) + y1

        Dim sb As New StringBuilder(100)
        sb.Append("{""geometryType"" : ""esriGeometryPoint"",""geometries"" : [ {""x"" :")
        sb.Append(x)
        sb.Append(", ""y"" :")
        sb.Append(y)
        sb.Append("}]}")


        'Dim sb As New StringBuilder(100)
        'sb.Append("{'geometryType' : 'esriGeometryPoint','geometries' : [ {'x' :")
        'sb.Append(x)
        'sb.Append(", 'y' :")
        'sb.Append(y)
        'sb.Append("}]}")

        Dim sb2 As String = String.Format("geometries=%7B%0D%0AgeometryType+%3A+esriGeometryPoint%2C%0D%0Ageometries+%3A+%5B%0D%0A+%7Bx+%3A+{0}%2C+y+%3A+{1}%7D%0D%0A%0D%0A%5D%0D%0A%7D", x, y)

        Dim buffer As String = ""

        Dim requestUri As String = "http://server2.co.orange.nc.us/ArcGIS/rest/services/Geometry/GeometryServer/buffer"
        Dim data As New StringBuilder(100)
        data.AppendFormat("?geometries={0}", sb.ToString())
        'data.AppendFormat("?geometries={0}", sb2)
        data.Append("&inSR=%7B+wkid%3A+2264+%7D&outSR=&bufferSR=&distances=2000&unit=9002&unionResults=false&f=json")

        Dim request As HttpWebRequest = WebRequest.Create(requestUri & data.ToString())

        Dim response As HttpWebResponse = request.GetResponse
        Using response
            Dim reader As StreamReader = New StreamReader(response.GetResponseStream())
            Dim responseString As String = reader.ReadToEnd()
            Dim jss As System.Web.Script.Serialization.JavaScriptSerializer = New JavaScriptSerializer
            Dim results As Dictionary(Of String, Object) = jss.DeserializeObject(responseString)
            If (results IsNot Nothing And results.ContainsKey("geometries")) Then
                'IEnumerable<object> features = results["features"] as IEnumerable<object>;
                Dim geometries As IEnumerable(Of Object) = results("geometries")

                'foreach (IDictionary<string, object> feature in features)
                Dim bufferObject As New StringBuilder()
                For Each g As Dictionary(Of String, Object) In geometries
                    bufferObject.Append("{rings:[")
                    Dim rings As IEnumerable(Of Object) = g("rings")

                    For Each ring() As Object In rings
                        bufferObject.Append("[")
                        For Each pt As Object In ring
                            bufferObject.Append("[")
                            bufferObject.Append(pt(0) & "," & pt(1))
                            bufferObject.Append("],")
                        Next
                        bufferObject.Remove(bufferObject.Length - 1, 1)
                        bufferObject.Append("],")
                    Next
                    bufferObject.Remove(bufferObject.Length - 1, 1)
                    bufferObject.Append("], spatialReference : {wkid : 4326}}")

                    buffer = bufferObject.ToString()

                    Exit For
                Next

            End If
         

        End Using
        Return buffer


    End Function

    Private Sub ExecuteGISSearch()

        Dim searchresults As List(Of SearchResult) = New List(Of SearchResult)
        Dim pinList As New List(Of String)
        Dim requestUri As String = "http://gis2.maconnc.org/ArcGIS/rest/services/Advanced/MapServer/7/query?f=json"
        Dim data As New StringBuilder(100)
        'data.AppendFormat("?f={0}", "json")
        data.Append("&returnGeometry=false")
        data.Append("&geometryType=esriGeometryPolygon")
        Dim sBuffer As String = Me.doBuffer()
        data.AppendFormat("&geometry={0}", sBuffer)
        data.AppendFormat("&outFields={0}", "PIN")

        Dim request As HttpWebRequest = WebRequest.Create(requestUri)
        request.Method = "POST"

        Dim postData As String = data.ToString()
        Dim encoding As New ASCIIEncoding()
        Dim byte1 As Byte() = encoding.GetBytes(postData)
        request.ContentType = "application/x-www-form-urlencoded"
        request.ContentLength = byte1.Length

        Dim newStream As Stream = request.GetRequestStream()
        newStream.Write(byte1, 0, byte1.Length)
        newStream.Close()

        Dim response As HttpWebResponse = request.GetResponse
        Using response

            Dim reader As StreamReader = New StreamReader(response.GetResponseStream())
            Dim responseString As String = reader.ReadToEnd()
            Dim jss As System.Web.Script.Serialization.JavaScriptSerializer = New JavaScriptSerializer
            Dim results As Dictionary(Of String, Object) = jss.DeserializeObject(responseString)
            If (results IsNot Nothing And results.ContainsKey("features")) Then
                Dim features As IEnumerable(Of Object) = results("features")
                For Each f As Dictionary(Of String, Object) In features
                    Dim attributes As IDictionary(Of String, Object) = f("attributes")
                    Dim result As New SearchResult
                    'result.Owner_Name = attributes("OWNER_NAME").ToString()
                    'result.PIN = attributes("PIN").ToString()
                    'result.Property_Address = attributes("PROP_ADDR").ToString()
                    'searchresults.Add(result)
                    pinList.Add(attributes("PIN").ToString())
                Next

            End If


        End Using



        mPinList = pinList.ToArray()

    End Sub
0 Kudos
MarkAndrews
New Contributor
The above code works using a point as input.

I'll try to get the code to first query the parcels service and get the geometry or I may create a table using python at night with a x,y pair for the centroid and the pin number just to get around having large irregular polygons.

Again, I'm not sure if this is something other people have problems with.  I just wanted to not have to deal with referencing a version of ArcObjects libraries in the code.

Mark
0 Kudos
BobCarberry
New Contributor
Mark,

Here is what I have come up with and it does NOT use any ArcObjects.  It consists of  functions that will buffer an inputted polygon and then use the outputted polygon to perform a spatial query on a layer and return an attribute. Within the example code, you filnd notes explaining what I did, such as storing complex geometries in a text file.  Please look at the documentation for the buffer operation, it will explain how to set the units, buffer distances, etc.  I hope this is what you are looking for and it helps.

This example creates a 100 foot buffer:


Public Function Buffer_Geometry(ByVal jsonGeom As String) As string
 
     Dim attributeA as string
    

    ' where jsonGeom is a serialized json string storing polygon geometry
    ' add geometryType if it's not already included in the json string
            json = "{" + """" + "geometryType" + """" + ":" + """" + "esriGeometryPolygon" + """" + "," + """" + "geometries" + """" + ":[" + jsonGeom + "]}"
          
    ' reference a text file to store the json string (solution for very complex geometries)
    ' this text file should be stored in a folder within the website.  Make sure all web users have write access to it. 
     Dim txtFile = <string: name of text file>
            Dim path As String = System.Web.HttpContext.Current.Server.MapPath(<string: path of textfile>)
           ' write jon to text file
     Dim writer As New StreamWriter(path + "/" + txtFile, False, System.Text.Encoding.ASCII)
            writer.Write(json)
            writer.Close()
           ' NOTE: instead of passing geometry directly, you are passing in areference to the text file
            Dim data As String = "&geometries={" + """" + "url" + """" + ":" + """" + txtFile + """" + " }" + _
                                 "&inSR=3857" + _
                                 "&outSR=3857" + _
                                 "&bufferSR=3857" + _
                                 "&distances=100" + _
                                 "&unit=9002" + _
                                 "&unionResults=true" + _
                                 "&f=json"
            ' url for buffer operation
     Dim bufferURI As String = <string: url of buffer operation>

          
     ' calls funcion called PostIt that does a POST
     Dim responseString As String = PostIt(bufferURI, data)

            Dim jss As New System.Web.Script.Serialization.JavaScriptSerializer()
            jss.MaxJsonLength = 1000000
            Dim results As IDictionary(Of String, Object) = TryCast(jss.DeserializeObject(responseString), IDictionary(Of String, Object))

            If results IsNot Nothing AndAlso results.ContainsKey("geometries") Then
              
                Dim obj As Object = results("geometries")
                 ' output for buffer is geometries, to perform a spatial query, need to input a 'geometry' so grab one form geometries
  json2 = jss.Serialize(obj(0))

              
            End If

            'call the query function, parameters: mapservice url, layerID (layerid of the layer you are doing query on), geometry
            Dim results2 As IEnumerable = DrillDown(<string: mapservice url>, <string: layerID>, json2)

            For Each feature As IDictionary(Of String, Object) In results2

                Dim attributes As IDictionary(Of String, Object) = TryCast(feature("attributes"), IDictionary(Of String, Object))

               attributeA  = (attributes.Item(<string: field name attributeA>))
                  
                End If
            Next

              return attributeA

       End function

       --------------------------------------------------------------------------------------------------------------------------

        Private Shared Function PostIt(ByVal baseUrl As String, ByVal input As String) As String
        Dim responseString As String
        Dim request As HttpWebRequest
        Dim response As HttpWebResponse = Nothing
        Dim reader As StreamReader

        Dim byteData() As Byte
        Dim postStream As Stream = Nothing

        request = DirectCast(WebRequest.Create(baseUrl), HttpWebRequest)
        ' Set type to POST 
        request.Method = "POST"
        request.ContentType = "application/x-www-form-urlencoded"
        ' Create a byte array of the data we want to send 
        byteData = UTF8Encoding.UTF8.GetBytes(input)
        ' Set the content length in the request headers 
        request.ContentLength = byteData.Length

        Try

            postStream = request.GetRequestStream()
            postStream.Write(byteData, 0, byteData.Length)
        Finally

            If Not postStream Is Nothing Then postStream.Close()
        End Try

    
        Try

            ' Get response 
            response = DirectCast(request.GetResponse(), HttpWebResponse)

            ' Get the response stream into a reader 

            reader = New StreamReader(response.GetResponseStream())

            responseString = reader.ReadToEnd

        Catch

        Finally

            If Not response Is Nothing Then response.Close()

        End Try



        Return responseString

    End Function

    -------------------------------------------------------------------------------------------------------------------------

    Public Shared Function DrillDown(ByVal baseUrl As String, ByVal layerID As Integer, ByVal jsonGeom As String) As IEnumerable
              
        Dim data As String
        Dim txtFile = Dim txtFile = <string: name of text file>
        Dim path As String = System.Web.HttpContext.Current.Server.MapPath(<string: path of textfile>)
       


            Dim writer As New StreamWriter(path + "/" + txtFile", False, System.Text.Encoding.ASCII)
            writer.Write(jsonGeom)
            writer.Close()

        


            data = "&geometry=" + jsonGeom + _
                   "&geometryType=esriGeometryPolygon" + _
                   "&inSR=" + _
                   "&spatialRel=esriSpatialRelIntersects" + _
                   "&relationParam=" + _
                   "&objectIds=" + _
                   "&where=" + _
                   "&time=" + _
                   "&returnIdsOnly=false" + _
                   "&returnGeometry=false" + _
                   "&maxAllowableOffset=" + _
                   "&outSR=" + _
                   "&outFields=*" + _
                   "&f=json"


            Dim responseString As String = PostIt(baseUrl.ToString + layerID.ToString + "/query", data)
          

                Dim jss As New System.Web.Script.Serialization.JavaScriptSerializer()
                jss.MaxJsonLength = 100000000
                Dim results As IDictionary(Of String, Object) = TryCast(jss.DeserializeObject(responseString), IDictionary(Of String, Object))
                Dim json As String = ""
                Dim DrillDownResult As IEnumerable

                If results IsNot Nothing AndAlso results.ContainsKey("features") Then

                    Dim features As IEnumerable(Of Object) = TryCast(results("features"), IEnumerable(Of Object))
                    DrillDownResult = features
                End If




                Return DrillDownResult
          
    End Function
0 Kudos