ArcGIS Geocode Search service
ArcGIS_Geocode_Search_CSharp\App_Code\SchoolDistrictLocatorService.cs
// 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.
// 

[System.Web.Services.WebService(Namespace = "http://localhost/ArcGIS_SchoolDistrictGeocode_WebService/")]
[System.Web.Services.WebServiceBinding(ConformsTo = System.Web.Services.WsiProfiles.BasicProfile1_1)]
public class SchoolDistrictLocatorService : System.Web.Services.WebService {

    public SchoolDistrictLocatorService(){}

    [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 SchoolDistrict[] FindSchoolDistrictLocationsArcObjects(string FullAddress, string Distance)
    {
        // Make sure all inputs were specified
        if (FullAddress == null || string.IsNullOrEmpty(Distance.ToString()) || System.Convert.ToDouble(Distance) == 0.0)
        {
            return null;
        }

        // Declare server context variables
        ESRI.ArcGIS.Server.IServerContext mapServerContext = null;
        ESRI.ArcGIS.Server.IServerContext geocodeServerContext = null;
        ESRI.ArcGIS.Server.IServerContext geometryServerContext = null;

        try
        {
            // Connect to ArcGIS Server
            ESRI.ArcGIS.ADF.Identity adfIdentity = new ESRI.ArcGIS.ADF.Identity("username", "password", "domainOrmachine");
            ESRI.ArcGIS.ADF.Connection.AGS.AGSServerConnection agsServerConnection =
                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
            ESRI.ArcGIS.Server.IServerObjectManager serverObjectManager = 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");
            ESRI.ArcGIS.Location.IGeocodeServer geocodeServer = geocodeServerContext.ServerObject as
                ESRI.ArcGIS.Location.IGeocodeServer;

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

            // Execute the geocoding operation
            ESRI.ArcGIS.esriSystem.IPropertySet aoResultsPropertySet =
                geocodeServer.GeocodeAddress(aoInputPropertySet, null);

            // Retrieve the geocoded point from the operation results
            ESRI.ArcGIS.Geometry.IPoint aoLocationPoint = aoResultsPropertySet.GetProperty("Shape") as
                ESRI.ArcGIS.Geometry.IPoint;

            #endregion

            #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. 
            ESRI.ArcGIS.Geometry.IPoint aoLocationPointInGeometryServer = (ESRI.ArcGIS.Geometry.IPoint)
                geometryServerContext.LoadObject(geocodeServerContext.SaveObject(aoLocationPoint));
            
            ESRI.ArcGIS.Geometry.IGeometryServer geometryServer = geometryServerContext.ServerObject as
                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.
            ESRI.ArcGIS.Geometry.ISpatialReference aoBufferSpatialReference =
                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.
            ESRI.ArcGIS.Geometry.ISpatialReference outputSpatialReference = 
                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");
            ESRI.ArcGIS.Carto.IMapServer2 mapServer = mapServerContext.ServerObject as
                ESRI.ArcGIS.Carto.IMapServer2;

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

            // Create a spatial reference environemnt for use by the ConvertUnitType method
            ESRI.ArcGIS.Geometry.SpatialReferenceEnvironment spatialReferenceEnvironment =
                geometryServerContext.CreateObject("esriGeometry.SpatialReferenceEnvironment") as
                ESRI.ArcGIS.Geometry.SpatialReferenceEnvironment;

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

            // Package the geocoded point and buffer distance in arrays to pass to the buffer 
            // operation
            ESRI.ArcGIS.Geometry.IGeometryArray aoInputGeometryArray =
                geometryServerContext.CreateObject("esriGeometry.GeometryArray") as
                ESRI.ArcGIS.Geometry.IGeometryArray;
            aoInputGeometryArray.Add(aoLocationPointInGeometryServer);

            ESRI.ArcGIS.esriSystem.IDoubleArray distancesArray =
                geometryServerContext.CreateObject("esriSystem.DoubleArray") as
                ESRI.ArcGIS.esriSystem.IDoubleArray;
            distancesArray.Add(System.Convert.ToDouble(Distance));

            // Execute the buffer operation
            ESRI.ArcGIS.Geometry.IGeometryArray aoBufferGeometryArray = geometryServer.Buffer(
                aoLocationPointInGeometryServer.SpatialReference, aoBufferSpatialReference,
                outputSpatialReference, distancesArray, bufferUnit, false,
                aoInputGeometryArray);

            // Retrieve the buffer geometry from the operation results
            ESRI.ArcGIS.Geometry.IPolygon aoBuffer = aoBufferGeometryArray.get_Element(0) as
                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. 
            ESRI.ArcGIS.Geometry.IPolygon aoBufferInMapServer = (ESRI.ArcGIS.Geometry.IPolygon)
                mapServerContext.LoadObject(geometryServerContext.SaveObject(aoBuffer));

            #endregion

            #region Find SchoolDistrict sites within the buffer

            // Retrieve the map service's MapLayerInfos object to use in accessing information about 
            // the service's layers
            ESRI.ArcGIS.Carto.IMapLayerInfos mapLayerInfos =
                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.
            int SchoolDistrictsLayerID = -1;
            string geometryFieldName = null;

            for (int i = 0; i < mapLayerInfos.Count; i++)
            {
                ESRI.ArcGIS.Carto.IMapLayerInfo mapLayerInfo = mapLayerInfos.get_Element(i);
                if (mapLayerInfo.Name == "SchoolTaxDistrict")
                {
                    SchoolDistrictsLayerID = mapLayerInfo.ID;

                    for (int j = 0; j < mapLayerInfo.Fields.FieldCount; j++)
                    {
                        ESRI.ArcGIS.Geodatabase.IField field = mapLayerInfo.Fields.get_Field(j);
                        if (field.Type == ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeGeometry)
                        {
                            geometryFieldName = field.Name;
                            break;
                        }
                    }
                    break;
                }
            }

            // Instantiate and initialize a spatial filter with the buffer geometry and SchoolDistrict sites
            // layer geometry field name
            ESRI.ArcGIS.Geodatabase.ISpatialFilter aoSpatialFilter =
                mapServerContext.CreateObject("esriGeodatabase.SpatialFilter") as
                ESRI.ArcGIS.Geodatabase.ISpatialFilter;
            aoSpatialFilter.Geometry = aoBufferInMapServer;
            aoSpatialFilter.SpatialRel =
                ESRI.ArcGIS.Geodatabase.esriSpatialRelEnum.esriSpatialRelIntersects;
            aoSpatialFilter.GeometryField = geometryFieldName;

            // Execute the query
            ESRI.ArcGIS.Geodatabase.IRecordSet aoRecordSet = mapServer.QueryFeatureData(
                mapServer.DefaultMapName, SchoolDistrictsLayerID, aoSpatialFilter);

            #endregion

            #region Package function output based on SchoolDistrict site data

            // Retrieve the School Description type fields             
            int schoolDscrpIndex = -1;            

            int currentIndex = 0;
            for (int i = 0; i < aoRecordSet.Fields.FieldCount; i++)
            {
                ESRI.ArcGIS.Geodatabase.IField field = aoRecordSet.Fields.get_Field(i);
                if (field.Name.ToUpper() == "SCHLDSCRP")
                {
                    schoolDscrpIndex = currentIndex;
                    break;
                }
                currentIndex++;
            }

            System.Collections.ArrayList SchoolDistrictsList = new System.Collections.ArrayList();
            SchoolDistrict SchoolDistrict = null;            

            // Get a cursor to loop through the rows corresponding to SchoolDistrict site results
            ESRI.ArcGIS.Geodatabase.ICursor SchoolDistrictCursor = aoRecordSet.get_Cursor(false);
            ESRI.ArcGIS.Geodatabase.IRow SchoolDistrictRow = SchoolDistrictCursor.NextRow();

            // For each SchoolDistrict site record, instantiate a new SchoolDistrict object and add it to the SchoolDistrict sites
            // list object
            while (SchoolDistrictRow != null)
            {                
                SchoolDistrict = new SchoolDistrict((string)SchoolDistrictRow.get_Value(schoolDscrpIndex));
                SchoolDistrictsList.Add(SchoolDistrict);

                SchoolDistrictRow = SchoolDistrictCursor.NextRow();
            }

            // Copy the SchoolDistrict sites list to an array to be returned as the function result
            SchoolDistrict[] SchoolDistrictsArray = new SchoolDistrict[SchoolDistrictsList.Count];
            SchoolDistrictsList.CopyTo(SchoolDistrictsArray);

            #endregion

            return SchoolDistrictsArray;
        }
        catch (System.Exception exception)
        {
            System.Diagnostics.Debug.WriteLine("Exception: " + exception.Message);
        }
        finally
        {
            // Make sure server contexts are released 
            if (mapServerContext != null)
                mapServerContext.ReleaseContext();

            if (geocodeServerContext != null)
                geocodeServerContext.ReleaseContext();

            if (geometryServerContext != null)
                geometryServerContext.ReleaseContext();
        }

        return null;
    }

    [System.Web.Services.WebMethod(Description = "Locates SchoolDistrict sites 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 SchoolDistrict[] FindSchoolDistrictLocationsSoap(string FullAddress, double Distance)
    {
        // Check to make sure all inputs are specified
        if (FullAddress == null || string.IsNullOrEmpty(Distance.ToString()) || System.Convert.ToDouble(Distance) == 0.0)
        {
            return null;
        }

        // Declare server context variables
        ESRI.ArcGIS.Server.IServerContext mapServerContext = null;
        ESRI.ArcGIS.Server.IServerContext geocodeServerContext = null;
        ESRI.ArcGIS.Server.IServerContext geometryServerContext = null;

        try
        {
            // Open a connection to ArcGIS Server
            ESRI.ArcGIS.ADF.Identity adfIdentity = new ESRI.ArcGIS.ADF.Identity("username", "password", "domainOrmachine");
            ESRI.ArcGIS.ADF.Connection.AGS.AGSServerConnection agsServerConnection =
                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
            ESRI.ArcGIS.Server.IServerObjectManager serverObjectManager = agsServerConnection.ServerObjectManager;

            #region Geocode the input address

            // Create an ArcGIS Server SOAP property set to hold the input to the geocode oparation
            ESRI.ArcGIS.ADF.ArcGISServer.PropertySet agsSoapInputPropertySet =
                new ESRI.ArcGIS.ADF.ArcGISServer.PropertySet();
            agsSoapInputPropertySet.PropertyArray = new ESRI.ArcGIS.ADF.ArcGISServer.PropertySetProperty[1];

            // Specify the street property
            ESRI.ArcGIS.ADF.ArcGISServer.PropertySetProperty agsSoapInputProperty =
                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
            ESRI.ArcGIS.ADF.ArcGISServer.GeocodeServerDcomProxy geocodeServerDcomProxy =
               new ESRI.ArcGIS.ADF.ArcGISServer.GeocodeServerDcomProxy(geocodeServerContext, true);

            // Execute the geocoding operation
            ESRI.ArcGIS.ADF.ArcGISServer.PropertySet agsSoapResultsPropertySet =
                geocodeServerDcomProxy.GeocodeAddress(agsSoapInputPropertySet, null);

            // Retrieve the geocoded point from the results array
            ESRI.ArcGIS.ADF.ArcGISServer.PointN agsSoapLocationPoint = null;
            for (int i = 0; i < agsSoapResultsPropertySet.PropertyArray.Length; i++)
            {
                if (agsSoapResultsPropertySet.PropertyArray[i].Key == "Shape")
                    agsSoapLocationPoint = agsSoapResultsPropertySet.PropertyArray[i].Value as
                        ESRI.ArcGIS.ADF.ArcGISServer.PointN;
            }

            #endregion

            #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
            ESRI.ArcGIS.ADF.ArcGISServer.MapServerDcomProxy mapServerDcomProxy =
                new ESRI.ArcGIS.ADF.ArcGISServer.MapServerDcomProxy(mapServerContext, true);
            ESRI.ArcGIS.ADF.ArcGISServer.MapServerInfo mapServerInfo =
                mapServerDcomProxy.GetServerInfo(mapServerDcomProxy.GetDefaultMapName());

            // Convert the service's units into the type required for the buffer operation
            ESRI.ArcGIS.ADF.ArcGISServer.LinearUnit bufferDistanceUnits =
                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");
            ESRI.ArcGIS.ADF.ArcGISServer.GeometryServerDcomProxy geometryServerDcomProxy =
                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.
            ESRI.ArcGIS.ADF.ArcGISServer.SpatialReference agsSoapSpatialReference =
                Utility.CreateOperationSpatialReference(agsSoapLocationPoint, geometryServerDcomProxy);

            // Package the geocoded point and buffer distance in arrays for passing to the buffer
            // operation
            ESRI.ArcGIS.ADF.ArcGISServer.Geometry[] agsSoapInputGeometryArray =
                new ESRI.ArcGIS.ADF.ArcGISServer.Geometry[1];
            agsSoapInputGeometryArray[0] = agsSoapLocationPoint;
            double[] distancesArray = new double[1];
            distancesArray[0] = Distance;

            // Output spatial reference for the buffer operation
            ESRI.ArcGIS.ADF.ArcGISServer.SpatialReference outputSpatialReference = agsSoapLocationPoint.SpatialReference;

            // Execute the buffer operation
            ESRI.ArcGIS.ADF.ArcGISServer.Geometry[] agsSoapBufferGeometryArray =
                geometryServerDcomProxy.Buffer(agsSoapLocationPoint.SpatialReference,
                agsSoapSpatialReference, outputSpatialReference, distancesArray, bufferDistanceUnits,
                false, agsSoapInputGeometryArray);

            #endregion

            #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.
            ESRI.ArcGIS.ADF.ArcGISServer.MapLayerInfo[] mapLayerInfoArray =
                mapServerInfo.MapLayerInfos;

            int SchoolDistrictsLayerID = -1;
            string geometryFieldName = null;
            foreach (ESRI.ArcGIS.ADF.ArcGISServer.MapLayerInfo mapLayerInfo in mapLayerInfoArray)
            {
                if (mapLayerInfo.Name == "SchoolTaxDistrict")
                {
                    SchoolDistrictsLayerID = mapLayerInfo.LayerID;

                    foreach (ESRI.ArcGIS.ADF.ArcGISServer.Field field in mapLayerInfo.Fields.FieldArray)
                    {
                        if (field.Type == ESRI.ArcGIS.ADF.ArcGISServer.esriFieldType.esriFieldTypeGeometry)
                        {
                            geometryFieldName = field.Name;
                            break;
                        }
                    }
                    break;
                }
            }

            // Create and initialize a spatial filter with the buffer geometry and SchoolDistrict sites geometry
            // field name
            ESRI.ArcGIS.ADF.ArcGISServer.SpatialFilter agsSoapSpatialFilter =
                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
            ESRI.ArcGIS.ADF.ArcGISServer.RecordSet agsSoapRecordSet = mapServerDcomProxy.QueryFeatureData(
                mapServerDcomProxy.GetDefaultMapName(), SchoolDistrictsLayerID, agsSoapSpatialFilter);

            #endregion

            #region Package function output based on SchoolDistrict site data

            // Get the indexes of School Description Field            
            int schoolDscrpIndex = -1;
            

            int currentIndex = 0;
            foreach (ESRI.ArcGIS.ADF.ArcGISServer.Field agsSoapField in agsSoapRecordSet.Fields.FieldArray)
            {
                if (agsSoapField.Name.ToUpper() == "SCHLDSCRP")
                {
                    schoolDscrpIndex = currentIndex;
                    break;
                }
                currentIndex++;
            }

            // For each SchoolDistrict record, instantiate a new SchoolDistrict object and add it to the SchoolDistrict sites
            // list object
            System.Collections.ArrayList SchoolDistrictsList = new System.Collections.ArrayList();
            SchoolDistrict SchoolDistrict = null;
            
            foreach (ESRI.ArcGIS.ADF.ArcGISServer.Record SchoolDistrictRecord in agsSoapRecordSet.Records)
            {
                SchoolDistrict = new SchoolDistrict((string)SchoolDistrictRecord.Values[schoolDscrpIndex]);
                SchoolDistrictsList.Add(SchoolDistrict);
            }

            // Copy the SchoolDistrict sites list to an array to be returned as the function result
            SchoolDistrict[] SchoolDistrictsArray = new SchoolDistrict[SchoolDistrictsList.Count];
            SchoolDistrictsList.CopyTo(SchoolDistrictsArray);

            #endregion

            // Release server contexts
            mapServerContext.ReleaseContext();
            geocodeServerContext.ReleaseContext();
            geometryServerContext.ReleaseContext();

            return SchoolDistrictsArray;
        }
        catch (System.Exception exception)
        {
            System.Diagnostics.Debug.WriteLine("Exception: " + exception.Message);
        }
        finally
        {
            // Make sure server contexts are released 
            if (mapServerContext != null)
                mapServerContext.ReleaseContext();

            if (geocodeServerContext != null)
                geocodeServerContext.ReleaseContext();

            if (geometryServerContext != null)
                geometryServerContext.ReleaseContext();
        }

        return null;
    }

}