Server spatial query server object extension
SpatialQuerySOE.Manager_CSharp\Configurator.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.Collections.Generic;
using System.Text;

namespace SpatialQuerySOE.Manager
{
    /// <summary>
    /// SpatialQuerySOE property configuration page for Manager.  Defines the appearance and behavior of the page.
    /// </summary>
    public class Configurator : ESRI.ArcGIS.ServerManager.IServerObjectExtensionConfigurator
    {
        #region Member variables
        
        // Controls to enable configuration of the SOE's layer and field
        private System.Web.UI.WebControls.DropDownList m_layersDropDown = new System.Web.UI.WebControls.DropDownList();
        private System.Web.UI.WebControls.DropDownList m_fieldsDropDown = new System.Web.UI.WebControls.DropDownList();

        // The SOE's current layer
        private string m_layer;

        // The SOE's current field
        private string m_field;

        // JSON string storing the names of the current service's layers and their fields
        private string m_jsonServiceLayersAndFields = "{}";
        
        #endregion

        #region IServerObjectExtensionConfigurator Members

        #region Properties - HtmlElementIds, SupportingJavaScript

        /// <summary>
        /// IDs of the controls that define SOE properties
        /// </summary>
        public List<string> HtmlElementIds
        {
            get { return new List<string>(new string[] { "layersDropDown", "fieldsDropDown" }); }
        }

        /// <summary>
        /// JavaScript to execute when the property page is loaded
        /// </summary>
        public string SupportingJavaScript
        {
            get
            {
                return string.Format(@"
                    // JSON object storing the names of the current service's layers and their fields
                    var layerFieldsMapping = {0};

                    // ExtensionConfigurator is a global JavaScript object defined by Manager and available to SOE property page
                    // implementations.  Here we use it to define the client logic to execute when a new layer is selected.
                    ExtensionConfigurator.OnLayerChanged = function(layersDropDown) {{
                        // Get the currently selected layer                           
                        var layerName = layersDropDown.options[layersDropDown.selectedIndex].value;
                        // Get the fields drop down and the number of items in it
                        var fieldsDropDown = document.getElementById('fieldsDropDown');  
                        var len = fieldsDropDown.options ? fieldsDropDown.options.length : 0;

                        // Remove all the drop down's items
                        for(var i=0; i < len; i++)
                            fieldsDropDown.remove(0);

                        // Get the fields for the currently selected layer and populate the fields drop down with them
                        var fieldsArray = layerFieldsMapping[layerName];
                        if(fieldsArray)
                        {{  
                            for(i=0; i < fieldsArray.length; i++)
                                fieldsDropDown.options.add(new Option(fieldsArray[i], fieldsArray[i]));

                            fieldsDropDown.options[0].selected = true;
                        }}
                    }}", m_jsonServiceLayersAndFields);
            }
        }

        #endregion

        #region Methods - LoadConfigurator, SaveProperties

        /// <summary>
        /// Called when the property page is loaded
        /// </summary>
        /// <param name="serverContext">server context for the service</param>
        /// <param name="ServerObjectProperties">properties of the server object (i.e. service)</param>
        /// <param name="ExtensionProperties">SOE properties for the current server object</param>
        /// <param name="InfoProperties">global SOE properties</param>
        /// <param name="isEnabled">whether the SOE is enabled on the current server object</param>
        /// <param name="servicesEndPoint">end point for server's web services </param>
        /// <param name="serviceName">name of the server object</param>
        /// <returns>An HTML string that defines the property page's UI</returns>
        public string LoadConfigurator(ESRI.ArcGIS.Server.IServerContext serverContext,
                        System.Collections.Specialized.NameValueCollection ServerObjectProperties,
                        System.Collections.Specialized.NameValueCollection ExtensionProperties,
                        System.Collections.Specialized.NameValueCollection InfoProperties,
                        bool isEnabled, string servicesEndPoint, string serviceName)
        {
            // Just return a message if the SOE is not enabled on the current service
            if (!isEnabled)
                return ("<span>No Properties to configure</span>");

            // Initialize member variables holding the SOE's properties
            if (!string.IsNullOrEmpty(ExtensionProperties["LayerName"]))
                m_layer = ExtensionProperties["LayerName"];
            if (!string.IsNullOrEmpty(ExtensionProperties["FieldName"]))
                m_field = ExtensionProperties["FieldName"];


            //Container div and table          
            System.Web.UI.HtmlControls.HtmlGenericControl propertiesDiv =
                new System.Web.UI.HtmlControls.HtmlGenericControl("propertiesDiv");
            propertiesDiv.Style[System.Web.UI.HtmlTextWriterStyle.Padding] = "10px";

            System.Web.UI.HtmlControls.HtmlTable table = new System.Web.UI.HtmlControls.HtmlTable();
            table.CellPadding = table.CellSpacing = 4;
            propertiesDiv.Controls.Add(table);


            // Header row
            System.Web.UI.HtmlControls.HtmlTableRow row = new System.Web.UI.HtmlControls.HtmlTableRow();
            table.Rows.Add(row);

            System.Web.UI.HtmlControls.HtmlTableCell cell = new System.Web.UI.HtmlControls.HtmlTableCell();
            row.Cells.Add(cell);
            cell.ColSpan = 2;

            System.Web.UI.WebControls.Label lbl = new System.Web.UI.WebControls.Label();
            lbl.Text = "Choose the layer and field.";
            cell.Controls.Add(lbl);


            // Layer drop-down row
            row = new System.Web.UI.HtmlControls.HtmlTableRow();
            table.Rows.Add(row);

            cell = new System.Web.UI.HtmlControls.HtmlTableCell();
            row.Cells.Add(cell);

            lbl = new System.Web.UI.WebControls.Label();
            cell.Controls.Add(lbl);
            lbl.Text = "Layer:";

            cell = new System.Web.UI.HtmlControls.HtmlTableCell();
            row.Cells.Add(cell);
            cell.Controls.Add(m_layersDropDown);
            m_layersDropDown.ID = "layersDropDown";

            // Wire the OnLayerChanged JavaScript function (defined in SupportingJavaScript) to fire when a new layer is selected
            m_layersDropDown.Attributes["onchange"] = "ExtensionConfigurator.OnLayerChanged(this);";


            // Fields drop-down row
            row = new System.Web.UI.HtmlControls.HtmlTableRow();
            table.Rows.Add(row);

            cell = new System.Web.UI.HtmlControls.HtmlTableCell();
            row.Cells.Add(cell);

            lbl = new System.Web.UI.WebControls.Label();
            cell.Controls.Add(lbl);
            lbl.Text = "Fields:";

            cell = new System.Web.UI.HtmlControls.HtmlTableCell();
            row.Cells.Add(cell);
            cell.Controls.Add(m_fieldsDropDown);
            m_fieldsDropDown.ID = "fieldsDropDown";



            // Get the path of the underlying map document and use it to populate the properties drop-downs
            string fileName = ServerObjectProperties["FilePath"];
            populateDropDowns(serverContext, fileName);


            // Render and return the HTML for the container div
            System.IO.StringWriter stringWriter = new System.IO.StringWriter();
            System.Web.UI.HtmlTextWriter htmlWriter = new System.Web.UI.HtmlTextWriter(stringWriter);
            propertiesDiv.RenderControl(htmlWriter);
            string html = stringWriter.ToString();
            stringWriter.Close();
            return html;
        }

        /// <summary>
        /// Persists the server object extension's properties
        /// </summary>
        /// <param name="serverContext">the server context of the service</param>
        /// <param name="Request">values of the controls specified in HtmlElementIds</param>
        /// <param name="isEnabled">whether the extension is enabled on the current server object</param>
        /// <param name="ExtensionProperties">collection of server object properties to save</param>
        /// <param name="InfoProperties">collection of global extension properties to save</param>
        public void SaveProperties(ESRI.ArcGIS.Server.IServerContext serverContext,
            System.Collections.Specialized.NameValueCollection Request, bool isEnabled,
            out System.Collections.Specialized.NameValueCollection ExtensionProperties,
            out System.Collections.Specialized.NameValueCollection InfoProperties)
        {
            // Instantiate the properties collection and define the LayerName and FieldName properties
            ExtensionProperties = new System.Collections.Specialized.NameValueCollection();

            string layerName = Request["layersDropDown"];
            if (!string.IsNullOrEmpty(layerName))
                ExtensionProperties.Add("LayerName", layerName);

            string fieldName = Request["fieldsDropDown"];
            if (!string.IsNullOrEmpty(fieldName))
                ExtensionProperties.Add("FieldName", fieldName);

            InfoProperties = new System.Collections.Specialized.NameValueCollection();
        }

        #endregion

        #endregion

        // Retrieves the current service's layers and fields and populates the property page UI with them
        private void populateDropDowns(ESRI.ArcGIS.Server.IServerContext serverContext, string mapDocPath)
        {
            ESRI.ArcGIS.Carto.IMapDocument mapDoc = null;
            ESRI.ArcGIS.Carto.IMap map = null;
            try
            {
                // Get the map underlying the current service
                mapDoc = (ESRI.ArcGIS.Carto.IMapDocument)serverContext.CreateObject("esriCarto.MapDocument");
                mapDoc.Open(mapDocPath, null);
                map = mapDoc.get_Map(0);

                // Get IGeoFeatureLayers from the map
                ESRI.ArcGIS.esriSystem.UID id = (ESRI.ArcGIS.esriSystem.UID)serverContext.CreateObject("esriSystem.UID");
                id.Value = "{E156D7E5-22AF-11D3-9F99-00C04F6BC78E}";
                ESRI.ArcGIS.Carto.IEnumLayer enumLayer = map.get_Layers(id, true);

                // Loop through each layer and the fields for that layer.  For each simple polygon layer, add its name and 
                // a list containing the names of all its fields to the dictionary.
                ESRI.ArcGIS.Carto.IFeatureLayer featureLayer = (ESRI.ArcGIS.Carto.IFeatureLayer)enumLayer.Next();
                Dictionary<string, List<string>> layersAndFieldsDictionary = new Dictionary<string, List<string>>();
                bool addFields = false;
                while (featureLayer != null)
                {
                    List<string> fieldsList = new List<string>();

                    // Check whether the current layer is a simple polygon layer
                    if (featureLayer.FeatureClass.ShapeType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon
                           && featureLayer.FeatureClass.FeatureType == ESRI.ArcGIS.Geodatabase.esriFeatureType.esriFTSimple)
                    {
                        // Add the layer to the layers drop-down
                        m_layersDropDown.Items.Add(featureLayer.Name);

                        // Check whether the fields drop-down should be initialized with fields from the current loop layer
                        if (featureLayer.Name == m_layer || (m_layer == null && m_layersDropDown.Items.Count == 1))
                            addFields = true;

                        // Add each field to the fields list
                        ESRI.ArcGIS.Geodatabase.IFields fields = featureLayer.FeatureClass.Fields;
                        for (int i = 0; i < fields.FieldCount; i++)
                        {
                            ESRI.ArcGIS.Geodatabase.IField field = fields.get_Field(i);
                            fieldsList.Add(field.Name);

                            // If the current loop layer is the first, add its fields to the fields drop-down
                            if (addFields)
                                m_fieldsDropDown.Items.Add(field.Name);
                        }

                        addFields = false;

                        // Add the layer name and its fields to the dictionary
                        layersAndFieldsDictionary.Add(featureLayer.Name, fieldsList);
                    }

                    featureLayer = (ESRI.ArcGIS.Carto.IFeatureLayer)enumLayer.Next();
                }

                // Serialize the dictionary containing the layer and field names to JSON
                System.Web.Script.Serialization.JavaScriptSerializer serializer =
                    new System.Web.Script.Serialization.JavaScriptSerializer();
                m_jsonServiceLayersAndFields = serializer.Serialize(layersAndFieldsDictionary);

                // If a layer is defined for the extension, select it in the layers drop-down.
                if (m_layer != null)
                    m_layersDropDown.SelectedValue = m_layer;

                // If a field is defined for the extension, select it in the fields drop-down.
                if (m_field != null)
                    m_fieldsDropDown.SelectedValue = m_field;
            }
            catch { }
            finally
            {
                // Close the service's map document
                if (mapDoc != null)
                    mapDoc.Close();
                map = null;
            }
        }
    }
}