Server spatial query server object extension
SpatialQuerySOE_CSharp\Extension.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.
// 

using System;
using System.Runtime.InteropServices;
using System.EnterpriseServices;

namespace SpatialQuerySOE
{
    /// <summary>
    /// Implementation of the Spatial Query SOE.
    /// </summary>
    [AutomationProxy(true), ClassInterface(ClassInterfaceType.None), GuidAttribute("1932805D-7266-41a2-9428-0421A5617436")]
    public class Extension : ServicedComponent, SpatialQuerySOE.Interfaces.IExtension, ESRI.ArcGIS.Server.IServerObjectExtension, 
        ESRI.ArcGIS.esriSystem.IObjectConstruct, ESRI.ArcGIS.esriSystem.ILogSupport, ESRI.ArcGIS.esriSystem.IObjectActivate
    {
        #region Member Variables

        private ESRI.ArcGIS.Server.IServerObjectHelper m_ServerObjectHelper;
        private ESRI.ArcGIS.Carto.IFeatureLayer m_featureLayer;
        private string m_layerName;
        private string m_fieldName;
        private ESRI.ArcGIS.esriSystem.ILog m_log;

        #endregion

        #region IServerObjectExtension Members

        public void Init(ESRI.ArcGIS.Server.IServerObjectHelper pSOH)
        {
            m_ServerObjectHelper = pSOH;
            m_log.AddMessage(3,8000,"SpatialQuerySOE custom message. Init called");
        }

        public void Shutdown()
        {
            m_log.AddMessage(3, 8000, "SpatialQuerySOE custom message. Shutdown called");
            m_ServerObjectHelper = null;
            m_featureLayer = null;
            m_log = null;
        }
        
        #endregion

        #region SpatialQuerySOE.Interfaces.IExtension Members

        public SpatialQuerySOE.Interfaces.IResults QueryPoint(ESRI.ArcGIS.Geometry.IPoint point, double distance)
        {
            if (m_featureLayer == null)
            {
                m_log.AddMessage(1, 8000, "SpatialQuerySOE custom error: layer not found");
                return null;
            }

            ESRI.ArcGIS.Geodatabase.IFeatureClass featureClass = m_featureLayer.FeatureClass;

            // buffer the point
            ESRI.ArcGIS.Geometry.ITopologicalOperator topologicalOperator = (ESRI.ArcGIS.Geometry.ITopologicalOperator)point;
            ESRI.ArcGIS.Geometry.IGeometry queryGeometry = topologicalOperator.Buffer(distance);

            // query the feature class
            ESRI.ArcGIS.Geodatabase.ISpatialFilter spatialFilter = new ESRI.ArcGIS.Geodatabase.SpatialFilter();
            spatialFilter.Geometry = queryGeometry;
            spatialFilter.SpatialRel = ESRI.ArcGIS.Geodatabase.esriSpatialRelEnum.esriSpatialRelIntersects;
            spatialFilter.GeometryField = featureClass.ShapeFieldName;

            ESRI.ArcGIS.Geodatabase.IFeatureCursor resultsFeatureCursor = featureClass.Search(spatialFilter, true);

            // loop thourgh the features, clip each geometry to the buffer
            // and total areas by attribute value
            topologicalOperator = (ESRI.ArcGIS.Geometry.ITopologicalOperator)queryGeometry;
            int classFieldIndex = featureClass.FindField(m_fieldName);

            System.Collections.Specialized.ListDictionary summaryStatsDictionary = new System.Collections.Specialized.ListDictionary();

            // create the symbol and graphic elements collection for the graphics
            ESRI.ArcGIS.Display.ISimpleFillSymbol simpleFillSymbol = createFillSymbol();
            ESRI.ArcGIS.Carto.IGraphicElements resultsGraphics = new ESRI.ArcGIS.Carto.GraphicElements();

            ESRI.ArcGIS.Geodatabase.IFeature resultsFeature;
            while ((resultsFeature = resultsFeatureCursor.NextFeature()) != null)
            {
                // create the graphic
                ESRI.ArcGIS.Carto.IFillShapeElement fillShapeElement = new ESRI.ArcGIS.Carto.PolygonElement() as
                    ESRI.ArcGIS.Carto.IFillShapeElement;
                ESRI.ArcGIS.Carto.IElement element = fillShapeElement as ESRI.ArcGIS.Carto.IElement;

                // clip the geometry
                ESRI.ArcGIS.Geometry.IGeometry clippedResultsGeometry = topologicalOperator.Intersect(resultsFeature.Shape, 
                    ESRI.ArcGIS.Geometry.esriGeometryDimension.esriGeometry2Dimension);
                element.Geometry = clippedResultsGeometry;
                fillShapeElement.Symbol = simpleFillSymbol;
                ESRI.ArcGIS.Carto.IGraphicElement resultsGraphicElement = fillShapeElement as
                    ESRI.ArcGIS.Carto.IGraphicElement;
                resultsGraphics.Add(resultsGraphicElement);

                // get statistics and add to dictionary
                ESRI.ArcGIS.Geometry.IArea area = clippedResultsGeometry as ESRI.ArcGIS.Geometry.IArea;
                string resultsClass = resultsFeature.get_Value(classFieldIndex) as string;

                // If the class is already in the dictionary, add the current feature's area to the existing entry
                if (summaryStatsDictionary.Contains(resultsClass))
                    summaryStatsDictionary[resultsClass] = (double)summaryStatsDictionary[resultsClass] + area.Area;
                else
                    summaryStatsDictionary[resultsClass] = area.Area;
            }

            // create the summary statistics recordset
            ESRI.ArcGIS.Geodatabase.IRecordSet summaryStatsRecordSet = createSummaryRecordSet(summaryStatsDictionary);

            // create the results object
            SpatialQuerySOE.Interfaces.IResults results = new Results();
            results.ResultsGraphics = resultsGraphics;
            results.SummaryStatistics = summaryStatsRecordSet;

            return results;
        }

        private ESRI.ArcGIS.Geodatabase.IRecordSet createSummaryRecordSet(
            System.Collections.Specialized.ListDictionary summaryStatsDictionary)
        {
            // initialize the summary statistics record set
            ESRI.ArcGIS.Geodatabase.IRecordSet summaryStatsRecordSet = new ESRI.ArcGIS.Geodatabase.RecordSet();
            ESRI.ArcGIS.Geodatabase.IRecordSetInit recordSetInit = summaryStatsRecordSet as ESRI.ArcGIS.Geodatabase.IRecordSetInit;

            ESRI.ArcGIS.Geodatabase.IFields summaryFields = new ESRI.ArcGIS.Geodatabase.Fields();
            ESRI.ArcGIS.Geodatabase.IFieldsEdit summaryFieldsEdit = summaryFields as ESRI.ArcGIS.Geodatabase.IFieldsEdit;
            summaryFieldsEdit.FieldCount_2 = 2;

            ESRI.ArcGIS.Geodatabase.IField field = new ESRI.ArcGIS.Geodatabase.Field();
            ESRI.ArcGIS.Geodatabase.IFieldEdit fieldEdit = field as ESRI.ArcGIS.Geodatabase.IFieldEdit;
            fieldEdit.Name_2 = "Type";
            fieldEdit.Type_2 = ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeString;
            fieldEdit.Length_2 = 50;
            summaryFieldsEdit.set_Field(0, field);

            field = new ESRI.ArcGIS.Geodatabase.Field();
            fieldEdit = field as ESRI.ArcGIS.Geodatabase.IFieldEdit;

            fieldEdit.Name_2 = "Area";
            fieldEdit.Type_2 = ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeDouble;
            summaryFieldsEdit.set_Field(1, field);

            recordSetInit.CreateTable(summaryFields);

            ESRI.ArcGIS.Geodatabase.ICursor cursor = recordSetInit.Insert();
            ESRI.ArcGIS.Geodatabase.IRowBuffer rowBuffer = recordSetInit.CreateRowBuffer();

            // Copy the summary stats to the record set
            System.Collections.IDictionaryEnumerator summaryStatsEnumerator = summaryStatsDictionary.GetEnumerator();
            while (summaryStatsEnumerator.MoveNext())
            {
                rowBuffer.set_Value(0, summaryStatsEnumerator.Key);
                rowBuffer.set_Value(1, summaryStatsEnumerator.Value);
                cursor.InsertRow(rowBuffer);
            }

            return summaryStatsRecordSet;
        }

        private ESRI.ArcGIS.Display.ISimpleFillSymbol createFillSymbol()
        {
            ESRI.ArcGIS.Display.ISimpleLineSymbol simpleLineSymbol = new ESRI.ArcGIS.Display.SimpleLineSymbol();
            ESRI.ArcGIS.Display.IRgbColor rgbColor = new ESRI.ArcGIS.Display.RgbColor();
            rgbColor.Red = 0;
            rgbColor.Green = 255;
            rgbColor.Blue = 0;
            simpleLineSymbol.Color = rgbColor;
            simpleLineSymbol.Style = ESRI.ArcGIS.Display.esriSimpleLineStyle.esriSLSSolid;
            simpleLineSymbol.Width = 2;

            ESRI.ArcGIS.Display.ISimpleFillSymbol simpleFillSymbol = new ESRI.ArcGIS.Display.SimpleFillSymbol();
            simpleFillSymbol.Outline = simpleLineSymbol;
            simpleFillSymbol.Style = ESRI.ArcGIS.Display.esriSimpleFillStyle.esriSFSHollow;

            return simpleFillSymbol;
        }
        #endregion

        #region IObjectConstruct Members
        public void Construct(ESRI.ArcGIS.esriSystem.IPropertySet props)
        {
            try
            {
                m_layerName = props.GetProperty("LayerName") as string;
                m_fieldName = props.GetProperty("FieldName") as string;
            }
            catch (Exception ex)
            {
                m_log.AddMessage(1, 8000, "SpatialQuerySOE custom error. Error reading properties: " + ex.Message + " " + props.Count.ToString());
                return;
            }

            try
            {
                // Get the map underlying the map service and the IGeoFeatureLayers contained in the map
                ESRI.ArcGIS.Carto.IMapServer mapServer = (ESRI.ArcGIS.Carto.IMapServer) m_ServerObjectHelper.ServerObject;
                ESRI.ArcGIS.Carto.IMapServerObjects mapServerObjects = (ESRI.ArcGIS.Carto.IMapServerObjects) mapServer;
                ESRI.ArcGIS.Carto.IMap map = mapServerObjects.get_Map(mapServer.DefaultMapName);
                ESRI.ArcGIS.esriSystem.UID layerTypeID = new ESRI.ArcGIS.esriSystem.UIDClass();
                layerTypeID.Value = "{E156D7E5-22AF-11D3-9F99-00C04F6BC78E}";
                ESRI.ArcGIS.Carto.IEnumLayer enumLayer = map.get_Layers(layerTypeID, true);
                enumLayer.Reset();

                // Get the layer specified as the SOE layer
                while ((m_featureLayer = enumLayer.Next() as ESRI.ArcGIS.Carto.IFeatureLayer) != null)
                {
                    if (m_featureLayer.Name == m_layerName)
                        break;
                }

                if (m_featureLayer == null)
                {
                    m_log.AddMessage(1, 8000, "SpatialQuerySOE custom error: Layer " + m_layerName + " not found.");
                    return;
                }

                // Make sure the layer contains the field specified by the SOE's configuration
                if (m_featureLayer.FeatureClass.FindField(m_fieldName) == -1)
                    m_log.AddMessage(1, 8000, "SpatialQuerySOE custom error: Field " + m_fieldName + " not found in layer " + m_layerName);
                else
                    m_log.AddMessage(3, 8000, "SpatialQuerySOE successfully initialized.");

            }
            catch (Exception ex)
            {
                m_log.AddMessage(1, 8000, "SpatialQuerySOE custom error: Failed to initialize extension: " + ex.Message + "::" + ex.StackTrace.Length.ToString());
            }
        }
        #endregion

        #region ILogSupport Members
        public void InitLogging(ESRI.ArcGIS.esriSystem.ILog log)
        {
            m_log = log;
        }
        #endregion

        #region IObjectActivate Members

        void ESRI.ArcGIS.esriSystem.IObjectActivate.Activate()
        {
            m_log.AddMessage(3, 8000, "SpatialQuerySOE custom message. Activate called");
        }

        void ESRI.ArcGIS.esriSystem.IObjectActivate.Deactivate()
        {
            m_log.AddMessage(3, 8000, "SpatialQuerySOE custom message. Deactivate called");
        }

        #endregion
    }
}