ArcGIS Geocode Search service
ArcGIS_Geocode_Search_VBNet\App_Code\SchoolDistrictLocatorService.vb
' Copyright 2010 ESRI
' 
' All rights reserved under the copyright laws of the United States
' and applicable international laws, treaties, and conventions.
' 
' You may freely redistribute and use this sample code, with or
' without modification, provided you include the original copyright
' notice and use restrictions.
' 
' See the use restrictions.
' 

Imports Microsoft.VisualBasic
Imports System
<System.Web.Services.WebService(Namespace := "http://localhost/ArcGIS_SchoolDistrictGeocode_WebService/"), System.Web.Services.WebServiceBinding(ConformsTo := System.Web.Services.WsiProfiles.BasicProfile1_1)> _
Public Class SchoolDistrictLocatorService
  Inherits System.Web.Services.WebService

  Public Sub New()
  End Sub

    <System.Web.Services.WebMethod(Description:="Locates SchoolDistrict within the specified distance of the input address." & "Output is returned in an array.  To see an example, input '1575 Apple Ln', '48304', '10000.'" & "Note that this method implements its functionality using ArcObjects.")> _
 Public Function FindSchoolDistrictLocationsArcObjects(ByVal FullAddress As String, ByVal Distance As String) As SchoolDistrict()
        ' Make sure all inputs were specified

        If FullAddress Is Nothing OrElse String.IsNullOrEmpty(Distance.ToString) OrElse CDbl(Distance) = 0.0 Then
            Return Nothing
        End If

        ' Declare server context variables
        Dim mapServerContext As ESRI.ArcGIS.Server.IServerContext = Nothing
        Dim geocodeServerContext As ESRI.ArcGIS.Server.IServerContext = Nothing
        Dim geometryServerContext As ESRI.ArcGIS.Server.IServerContext = Nothing

        Try
            ' Connect to ArcGIS Server
            Dim adfIdentity As New ESRI.ArcGIS.ADF.Identity("username", "password", "domainOrmachine")
            Dim agsServerConnection As New ESRI.ArcGIS.ADF.Connection.AGS.AGSServerConnection("localhost", adfIdentity)
            agsServerConnection.Connect()

            ' Get a reference to the server object manager to use in creating server objects
            Dim serverObjectManager As ESRI.ArcGIS.Server.IServerObjectManager = agsServerConnection.ServerObjectManager

            '      #Region "Geocode the input address"

            ' Create a server context for and get a reference to the RoadCenterline_Locator geocode service
            geocodeServerContext = serverObjectManager.CreateServerContext("RoadCenterline_Locator", "GeocodeServer")
            Dim geocodeServer As ESRI.ArcGIS.Location.IGeocodeServer = TryCast(geocodeServerContext.ServerObject, ESRI.ArcGIS.Location.IGeocodeServer)

            ' Instantate and populate a property set holding geocode operation input parameters
            Dim aoInputPropertySet As ESRI.ArcGIS.esriSystem.IPropertySet = TryCast(geocodeServerContext.CreateObject("esriSystem.PropertySet"), ESRI.ArcGIS.esriSystem.IPropertySet)
            aoInputPropertySet.SetProperty("Single Line Input", FullAddress)


            ' Execute the geocoding operation
            Dim aoResultsPropertySet As ESRI.ArcGIS.esriSystem.IPropertySet = geocodeServer.GeocodeAddress(aoInputPropertySet, Nothing)

            ' Retrieve the geocoded point from the operation results
            Dim aoLocationPoint As ESRI.ArcGIS.Geometry.IPoint = TryCast(aoResultsPropertySet.GetProperty("Shape"), ESRI.ArcGIS.Geometry.IPoint)

            '      #End Region

            '      #Region "Buffer the geocoded point"

            ' Create a server context for and get a reference to the geometry service.  We will use this
            ' to execute buffer and project operations.
            geometryServerContext = serverObjectManager.CreateServerContext("Geometry", "GeometryServer")

            ' The point generated by the geocode operation is in the geocode server object's server context. 
            ' It will be used in a geometry service operation, thus it must be available in the geometry
            ' server objects's server context.  SaveObject serializes the ArcObjects point to a string. 
            ' LoadObject deserializes the string to create an object in server context. 
            Dim aoLocationPointInGeometryServer As ESRI.ArcGIS.Geometry.IPoint = CType(geometryServerContext.LoadObject(geocodeServerContext.SaveObject(aoLocationPoint)), ESRI.ArcGIS.Geometry.IPoint)

            Dim geometryServer As ESRI.ArcGIS.Geometry.IGeometryServer = TryCast(geometryServerContext.ServerObject, ESRI.ArcGIS.Geometry.IGeometryServer)

            ' Create a spatial reference in which to execute the buffer operation.  This spatial
            ' reference's projection is optimized to minimize distortion in the vicinity of the
            ' operation.
            Dim aoBufferSpatialReference As ESRI.ArcGIS.Geometry.ISpatialReference = Utility.CreateOperationSpatialReference(aoLocationPointInGeometryServer, geometryServerContext)

            ' Store output spatial reference for use in the buffer operation.  Also use to assign spatial reference 
            ' to buffer generated by operation.
            Dim outputSpatialReference As ESRI.ArcGIS.Geometry.ISpatialReference = aoLocationPointInGeometryServer.SpatialReference

            ' Create a server context for and get a reference to the BloomfieldTownship map service.  We will
            ' use this to access map information and query features.
            mapServerContext = serverObjectManager.CreateServerContext("BloomfieldTownship", "MapServer")
            Dim mapServer As ESRI.ArcGIS.Carto.IMapServer2 = TryCast(mapServerContext.ServerObject, ESRI.ArcGIS.Carto.IMapServer2)

            ' Get a reference to the map service's server info object
            Dim mapServerInfo As ESRI.ArcGIS.Carto.IMapServerInfo = mapServer.GetServerInfo(mapServer.DefaultMapName)

            ' Create a spatial reference environemnt for use by the ConvertUnitType method
            Dim spatialReferenceEnvironment As ESRI.ArcGIS.Geometry.SpatialReferenceEnvironment = TryCast(geometryServerContext.CreateObject("esriGeometry.SpatialReferenceEnvironment"), ESRI.ArcGIS.Geometry.SpatialReferenceEnvironment)

            ' Convert the map service's units to the type required by the buffer operation
            Dim bufferUnit As ESRI.ArcGIS.Geometry.IUnit = Utility.ConvertUnitType(mapServerInfo.MapUnits, spatialReferenceEnvironment)

            ' Package the geocoded point and buffer distance in arrays to pass to the buffer 
            ' operation
            Dim aoInputGeometryArray As ESRI.ArcGIS.Geometry.IGeometryArray = TryCast(geometryServerContext.CreateObject("esriGeometry.GeometryArray"), ESRI.ArcGIS.Geometry.IGeometryArray)
            aoInputGeometryArray.Add(aoLocationPointInGeometryServer)

            Dim distancesArray As ESRI.ArcGIS.esriSystem.IDoubleArray = TryCast(geometryServerContext.CreateObject("esriSystem.DoubleArray"), ESRI.ArcGIS.esriSystem.IDoubleArray)
            distancesArray.Add(CDbl(Distance))

            ' Execute the buffer operation
            Dim aoBufferGeometryArray As ESRI.ArcGIS.Geometry.IGeometryArray = geometryServer.Buffer(aoLocationPointInGeometryServer.SpatialReference, aoBufferSpatialReference, outputSpatialReference, distancesArray, bufferUnit, False, aoInputGeometryArray)

            ' Retrieve the buffer geometry from the operation results
            Dim aoBuffer As ESRI.ArcGIS.Geometry.IPolygon = TryCast(aoBufferGeometryArray.Element(0), ESRI.ArcGIS.Geometry.IPolygon)

            ' Assign output spatial reference to buffer geometry 
            aoBuffer.SpatialReference = outputSpatialReference

            ' The polygon generated by the buffer operation is in the geometry server object's server context. 
            ' It will be used in a query operation against a map service, thus it must be available in the map
            ' server objects server context.  SaveObject serializes the ArcObjects polygon to a string. 
            ' LoadObject deserializes the string to create an object in server context. 
            Dim aoBufferInMapServer As ESRI.ArcGIS.Geometry.IPolygon = CType(mapServerContext.LoadObject(geometryServerContext.SaveObject(aoBuffer)), ESRI.ArcGIS.Geometry.IPolygon)
            '      #End Region

            '      #Region "Find SchoolDistrict sites within the buffer"

            ' Retrieve the map service's MapLayerInfos object to use in accessing information about 
            ' the service's layers
            Dim mapLayerInfos As ESRI.ArcGIS.Carto.IMapLayerInfos = mapServerInfo.MapLayerInfos

            ' Retrieve the layer ID and geometry field name of the SchoolDistrict sites layer.  This is the layer
            ' we will query to find SchoolDistrict sites within the buffer.
            Dim SchoolDistrictsLayerID As Integer = -1
            Dim geometryFieldName As String = Nothing

            Dim i As Integer = 0
            Do While i < mapLayerInfos.Count
                Dim mapLayerInfo As ESRI.ArcGIS.Carto.IMapLayerInfo = mapLayerInfos.Element(i)
                If mapLayerInfo.Name = "SchoolTaxDistrict" Then
                    SchoolDistrictsLayerID = mapLayerInfo.ID
                    Dim j As Integer = 0
                    Do While j < mapLayerInfo.Fields.FieldCount
                        Dim field As ESRI.ArcGIS.Geodatabase.IField = mapLayerInfo.Fields.Field(j)
                        If field.Type = ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeGeometry Then
                            geometryFieldName = field.Name
                            Exit Do
                        End If
                        j += 1
                    Loop
                    Exit Do
                End If
                i += 1
            Loop
            ' Instantiate and initialize a spatial filter with the buffer geometry and SchoolDistrict sites
            ' layer geometry field name
            Dim aoSpatialFilter As ESRI.ArcGIS.Geodatabase.ISpatialFilter = TryCast(mapServerContext.CreateObject("esriGeodatabase.SpatialFilter"), ESRI.ArcGIS.Geodatabase.ISpatialFilter)
            aoSpatialFilter.Geometry = aoBufferInMapServer
            aoSpatialFilter.SpatialRel = ESRI.ArcGIS.Geodatabase.esriSpatialRelEnum.esriSpatialRelIntersects
            aoSpatialFilter.GeometryField = geometryFieldName

            ' Execute the query
            Dim aoRecordSet As ESRI.ArcGIS.Geodatabase.IRecordSet = mapServer.QueryFeatureData(mapServer.DefaultMapName, SchoolDistrictsLayerID, aoSpatialFilter)

            '      #End Region

            '      #Region "Package function output based on SchoolDistrict site data"

            ' Retrieve the School Description type fields             
            Dim schoolDscrpIndex As Integer = -1

            Dim currentIndex As Integer = 0
            i = 0
            Do While i < aoRecordSet.Fields.FieldCount
                Dim field As ESRI.ArcGIS.Geodatabase.IField = aoRecordSet.Fields.Field(i)
                If field.Name.ToUpper() = "SCHLDSCRP" Then
                    schoolDscrpIndex = currentIndex
                    Exit Do
                End If
                currentIndex += 1
                i += 1
            Loop

            Dim SchoolDistrictsList As New System.Collections.ArrayList()
            Dim SchoolDistrict As SchoolDistrict = Nothing

            ' Get a cursor to loop through the rows corresponding to SchoolDistrict site results
            Dim SchoolDistrictCursor As ESRI.ArcGIS.Geodatabase.ICursor = aoRecordSet.Cursor(False)
            Dim SchoolDistrictRow As ESRI.ArcGIS.Geodatabase.IRow = SchoolDistrictCursor.NextRow()

            ' For each SchoolDistrict site record, instantiate a new SchoolDistrict object and add it to the SchoolDistrict sites
            ' list object
            Do While SchoolDistrictRow IsNot Nothing
                SchoolDistrict = New SchoolDistrict(CStr(SchoolDistrictRow.Value(schoolDscrpIndex)))
                SchoolDistrictsList.Add(SchoolDistrict)

                SchoolDistrictRow = SchoolDistrictCursor.NextRow()
            Loop

            ' Copy the SchoolDistrict sites list to an array to be returned as the function result
            Dim SchoolDistrictsArray(SchoolDistrictsList.Count - 1) As SchoolDistrict
            SchoolDistrictsList.CopyTo(SchoolDistrictsArray)

            '      #End Region

            Return SchoolDistrictsArray
        Catch exception As System.Exception
            System.Diagnostics.Debug.WriteLine("Exception: " & exception.Message)
        Finally
            ' Make sure server contexts are released 
            If mapServerContext IsNot Nothing Then
                mapServerContext.ReleaseContext()
            End If

            If geocodeServerContext IsNot Nothing Then
                geocodeServerContext.ReleaseContext()
            End If

            If geometryServerContext IsNot Nothing Then
                geometryServerContext.ReleaseContext()
            End If
        End Try

        Return Nothing
    End Function

    <System.Web.Services.WebMethod(Description:="Locates SchoolDistrict within the specified distance of the input address." & "Output is returned in an array.  To see an example, input '1575 Apple ln', '10000.'" & "Note that this method implements its functionality using the ArcGIS Server SOAP API.")> _
 Public Function FindSchoolDistrictLocationsSoap(ByVal FullAddress As String, ByVal Distance As String) As SchoolDistrict()
        ' Check to make sure all inputs are specified
        If FullAddress Is Nothing OrElse String.IsNullOrEmpty(Distance.ToString) OrElse CDbl(Distance) = 0.0 Then
            Return Nothing
        End If

        ' Declare server context variables
        Dim mapServerContext As ESRI.ArcGIS.Server.IServerContext = Nothing
        Dim geocodeServerContext As ESRI.ArcGIS.Server.IServerContext = Nothing
        Dim geometryServerContext As ESRI.ArcGIS.Server.IServerContext = Nothing

        Try
            ' Open a connection to ArcGIS Server
            Dim adfIdentity As New ESRI.ArcGIS.ADF.Identity("username", "password", "domainOrmachine")
            Dim agsServerConnection As New ESRI.ArcGIS.ADF.Connection.AGS.AGSServerConnection("localhost", adfIdentity)
            agsServerConnection.Connect()

            ' Get a reference to the server object manager to use in creating server objects
            Dim serverObjectManager As ESRI.ArcGIS.Server.IServerObjectManager = agsServerConnection.ServerObjectManager

            '      #Region "Geocode the input address"

            ' Create an ArcGIS Server SOAP property set to hold the input to the geocode oparation
            Dim agsSoapInputPropertySet As New ESRI.ArcGIS.ADF.ArcGISServer.PropertySet()
            agsSoapInputPropertySet.PropertyArray = New ESRI.ArcGIS.ADF.ArcGISServer.PropertySetProperty(0) {}

            ' Specify the street property
            Dim agsSoapInputProperty As New ESRI.ArcGIS.ADF.ArcGISServer.PropertySetProperty()
            agsSoapInputProperty.Key = "Single Line Input"
            agsSoapInputProperty.Value = FullAddress
            agsSoapInputPropertySet.PropertyArray(0) = agsSoapInputProperty


            ' Create server context for the RoadCenterline_Locator geocoding service.  We will use this to geocode
            ' the passed-in address.
            geocodeServerContext = serverObjectManager.CreateServerContext("RoadCenterline_Locator", "GeocodeServer")

            ' Get a reference to the geocoding service
            Dim geocodeServerDcomProxy As New ESRI.ArcGIS.ADF.ArcGISServer.GeocodeServerDcomProxy(geocodeServerContext, True)

            ' Execute the geocoding operation
            Dim agsSoapResultsPropertySet As ESRI.ArcGIS.ADF.ArcGISServer.PropertySet = geocodeServerDcomProxy.GeocodeAddress(agsSoapInputPropertySet, Nothing)

            ' Retrieve the geocoded point from the results array
            Dim agsSoapLocationPoint As ESRI.ArcGIS.ADF.ArcGISServer.PointN = Nothing
            For i As Integer = 0 To agsSoapResultsPropertySet.PropertyArray.Length - 1
                If agsSoapResultsPropertySet.PropertyArray(i).Key = "Shape" Then
                    agsSoapLocationPoint = TryCast(agsSoapResultsPropertySet.PropertyArray(i).Value, ESRI.ArcGIS.ADF.ArcGISServer.PointN)
                End If
            Next i

            '      #End Region

            '      #Region "Buffer the geocoded point"

            ' Create server context for the BloomfieldTownship map service.  We will use this to access
            ' information about and query the map service
            mapServerContext = serverObjectManager.CreateServerContext("BloomfieldTownship", "MapServer")

            ' Get references to the map service and the service's server info
            Dim mapServerDcomProxy As New ESRI.ArcGIS.ADF.ArcGISServer.MapServerDcomProxy(mapServerContext, True)
            Dim mapServerInfo As ESRI.ArcGIS.ADF.ArcGISServer.MapServerInfo = mapServerDcomProxy.GetServerInfo(mapServerDcomProxy.GetDefaultMapName())

            ' Convert the service's units into the type required for the buffer operation
            Dim bufferDistanceUnits As ESRI.ArcGIS.ADF.ArcGISServer.LinearUnit = Utility.ConvertUnitType(mapServerInfo.Units)

            ' Create server context for and get a reference to the geometry service.  We will use this 
            ' for buffer and project operations.
            geometryServerContext = serverObjectManager.CreateServerContext("Geometry", "GeometryServer")
            Dim geometryServerDcomProxy As New ESRI.ArcGIS.ADF.ArcGISServer.GeometryServerDcomProxy(geometryServerContext, True)

            ' Create a spatial reference in which to execute the buffer operation.  This spatial
            ' reference's projection is optimized to minimize distortion in the vicinity of the
            ' operation.
            Dim agsSoapSpatialReference As ESRI.ArcGIS.ADF.ArcGISServer.SpatialReference = Utility.CreateOperationSpatialReference(agsSoapLocationPoint, geometryServerDcomProxy)

            ' Package the geocoded point and buffer distance in arrays for passing to the buffer
            ' operation
            Dim agsSoapInputGeometryArray(0) As ESRI.ArcGIS.ADF.ArcGISServer.Geometry
            agsSoapInputGeometryArray(0) = agsSoapLocationPoint
            Dim distancesArray(0) As Double
            distancesArray(0) = CDbl(Distance)

            ' Output spatial reference for the buffer operation
            Dim outputSpatialReference As ESRI.ArcGIS.ADF.ArcGISServer.SpatialReference = agsSoapLocationPoint.SpatialReference

            ' Execute the buffer operation
            Dim agsSoapBufferGeometryArray() As ESRI.ArcGIS.ADF.ArcGISServer.Geometry = geometryServerDcomProxy.Buffer(agsSoapLocationPoint.SpatialReference, agsSoapSpatialReference, outputSpatialReference, distancesArray, bufferDistanceUnits, False, agsSoapInputGeometryArray)

            '      #End Region

            '      #Region "Find SchoolDistrict sites within the buffer"

            ' Retrieve the layer ID and geometry field name of the SchoolDistrict sites layer.  This is the layer
            ' we will query to find SchoolDistrict sites within the buffer.
            Dim mapLayerInfoArray() As ESRI.ArcGIS.ADF.ArcGISServer.MapLayerInfo = mapServerInfo.MapLayerInfos

            Dim SchoolDistrictsLayerID As Integer = -1
            Dim geometryFieldName As String = Nothing
            For Each mapLayerInfo As ESRI.ArcGIS.ADF.ArcGISServer.MapLayerInfo In mapLayerInfoArray
                If mapLayerInfo.Name = "SchoolTaxDistrict" Then
                    SchoolDistrictsLayerID = mapLayerInfo.LayerID

                    For Each field As ESRI.ArcGIS.ADF.ArcGISServer.Field In mapLayerInfo.Fields.FieldArray
                        If field.Type = ESRI.ArcGIS.ADF.ArcGISServer.esriFieldType.esriFieldTypeGeometry Then
                            geometryFieldName = field.Name
                            Exit For
                        End If
                    Next field
                    Exit For
                End If
            Next mapLayerInfo

            ' Create and initialize a spatial filter with the buffer geometry and SchoolDistrict sites geometry
            ' field name
            Dim agsSoapSpatialFilter As New ESRI.ArcGIS.ADF.ArcGISServer.SpatialFilter()
            agsSoapSpatialFilter.FilterGeometry = agsSoapBufferGeometryArray(0)
            agsSoapSpatialFilter.SpatialRel = ESRI.ArcGIS.ADF.ArcGISServer.esriSpatialRelEnum.esriSpatialRelIntersects
            agsSoapSpatialFilter.GeometryFieldName = geometryFieldName

            ' Execute the query operation
            Dim agsSoapRecordSet As ESRI.ArcGIS.ADF.ArcGISServer.RecordSet = mapServerDcomProxy.QueryFeatureData(mapServerDcomProxy.GetDefaultMapName(), SchoolDistrictsLayerID, agsSoapSpatialFilter)

            '      #End Region

            '      #Region "Package function output based on SchoolDistrict site data"

            ' Get the indexes of School Description Field            
            Dim schoolDscrpIndex As Integer = -1


            Dim currentIndex As Integer = 0
            For Each agsSoapField As ESRI.ArcGIS.ADF.ArcGISServer.Field In agsSoapRecordSet.Fields.FieldArray
                If agsSoapField.Name.ToUpper() = "SCHLDSCRP" Then
                    schoolDscrpIndex = currentIndex
                    Exit For
                End If
                currentIndex += 1
            Next agsSoapField

            ' For each SchoolDistrict record, instantiate a new SchoolDistrict object and add it to the SchoolDistrict sites
            ' list object
            Dim SchoolDistrictsList As New System.Collections.ArrayList()
            Dim SchoolDistrict As SchoolDistrict = Nothing

            For Each SchoolDistrictRecord As ESRI.ArcGIS.ADF.ArcGISServer.Record In agsSoapRecordSet.Records
                SchoolDistrict = New SchoolDistrict(CStr(SchoolDistrictRecord.Values(schoolDscrpIndex)))
                SchoolDistrictsList.Add(SchoolDistrict)
            Next SchoolDistrictRecord

            ' Copy the SchoolDistrict sites list to an array to be returned as the function result
            Dim SchoolDistrictsArray(SchoolDistrictsList.Count - 1) As SchoolDistrict
            SchoolDistrictsList.CopyTo(SchoolDistrictsArray)

            '      #End Region

            ' Release server contexts
            mapServerContext.ReleaseContext()
            geocodeServerContext.ReleaseContext()
            geometryServerContext.ReleaseContext()

            Return SchoolDistrictsArray
        Catch exception As System.Exception
            System.Diagnostics.Debug.WriteLine("Exception: " & exception.Message)
        Finally
            ' Make sure server contexts are released 
            If mapServerContext IsNot Nothing Then
                mapServerContext.ReleaseContext()
            End If

            If geocodeServerContext IsNot Nothing Then
                geocodeServerContext.ReleaseContext()
            End If

            If geometryServerContext IsNot Nothing Then
                geometryServerContext.ReleaseContext()
            End If
        End Try

        Return Nothing
    End Function

End Class