ArcGIS_AddDynamicData_CSharp\App_Code\ServerObjectStateModifier.cs
// Copyright 2011 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. // public class ServerObjectStateModifier { // Custom enumeration for specifying the behavior of ApplySimpleRenderers public enum RendererAction { ApplyNew, ApplyOriginal, ApplyLast } // Adds the passed in shapefile to the passed-in resource and assigns it the passed-in name public void AddLayer(ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal mapResourceLocal, string layerName) { // Get the map underlying the passed-in resource ESRI.ArcGIS.Carto.IMapServerObjects mapServerObjects = (ESRI.ArcGIS.Carto.IMapServerObjects)mapResourceLocal.MapServer; ESRI.ArcGIS.Carto.IMap aoMap = mapServerObjects.get_Map(mapResourceLocal.DataFrame); // Check whether the map already contains a layer with the passed-in name bool layerAdded = false; for (int i = 0; i < aoMap.LayerCount; i++) { if (aoMap.get_Layer(i).Name == layerName) { layerAdded = true; break; } } // Only execute the logic to add the layer if a layer of the same name has not already been added if (!layerAdded) { // Create a reference to the us_lakes shapefile as an ArcObjects feature layer ESRI.ArcGIS.Server.IServerContext serverContext = mapResourceLocal.ServerContextInfo.ServerContext; ESRI.ArcGIS.Geodatabase.IWorkspaceFactory workspaceFactory = (ESRI.ArcGIS.Geodatabase.IWorkspaceFactory)serverContext.CreateObject("esriDataSourcesFile.ShapefileWorkspaceFactory"); ESRI.ArcGIS.Geodatabase.IFeatureWorkspace featureWorkspace = workspaceFactory.OpenFromFile( @"C:\Program files\ArcGIS\DeveloperKit10.0\Samples\data\USAMajorHighways\", 0) as ESRI.ArcGIS.Geodatabase.IFeatureWorkspace; ESRI.ArcGIS.Carto.IFeatureLayer aoFeatureLayer = (ESRI.ArcGIS.Carto.IFeatureLayer) serverContext.CreateObject("esriCarto.FeatureLayer"); aoFeatureLayer.FeatureClass = featureWorkspace.OpenFeatureClass(layerName); aoFeatureLayer.Name = layerName; // Apply a renderer to the feature layer ESRI.ArcGIS.Carto.IGeoFeatureLayer aoGeoFeatureLayer = aoFeatureLayer as ESRI.ArcGIS.Carto.IGeoFeatureLayer; ApplySimpleRenderer(aoGeoFeatureLayer, serverContext, 0, 0, 210); // Set the dynamic layer's visibility based on the session variable. Default to visible if the session variable // does not yet exist. if ((System.Web.HttpContext.Current.Session["dynamicLayerVisible"] != null)) aoFeatureLayer.Visible = (bool)System.Web.HttpContext.Current.Session["dynamicLayerVisible"]; else aoFeatureLayer.Visible = true; // Add the layer to the map and move it below any other layers aoMap.AddLayer(aoFeatureLayer); aoMap.MoveLayer(aoFeatureLayer, aoMap.LayerCount - 1); // Before pushing the changes to the server, create a dictionary containing the current visibility of the map layers. // We do this because updating the objects on the server (via RefreshServerObjects) also updates the map description // referenced by the map resource with the service's updated default description, which includes default layer // visibility. System.Collections.Generic.Dictionary<string, bool> visibleLayers = new System.Collections.Generic.Dictionary<string, bool>(); foreach (ESRI.ArcGIS.ADF.ArcGISServer.LayerDescription layerDescription in mapResourceLocal.MapDescription.LayerDescriptions) { visibleLayers.Add(layerDescription.LayerID.ToString(), layerDescription.Visible); } // Register changes to server object - dynamic layer added. mapResourceLocal.RefreshServerObjects(); // Reset the visibility of the layers in the resource's map description to what it was before updating the map service. foreach (System.Collections.Generic.KeyValuePair<string, bool> layerVisiblePair in visibleLayers) { ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality.UpdateVisibleLayer( mapResourceLocal.MapDescription, layerVisiblePair.Key, layerVisiblePair.Value); } } } // Adds the passed-in GeoFeatureLayer to the passed-in local map resource and sets its position to that specified by the // passed-in argument public void AddLayer(ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal mapResourceLocal, ESRI.ArcGIS.Carto.IGeoFeatureLayer geoFeatureLayer, int layerIndex) { // Get the map underlying the passed-in resource ESRI.ArcGIS.Carto.IMapServerObjects mapServerObjects = (ESRI.ArcGIS.Carto.IMapServerObjects)mapResourceLocal.MapServer; ESRI.ArcGIS.Carto.IMap aoMap = mapServerObjects.get_Map(mapResourceLocal.DataFrame); // Get the server context of the passed-in map service ESRI.ArcGIS.Server.IServerContext serverContext = mapResourceLocal.ServerContextInfo.ServerContext; // Add the passed-in layer to the map and move it to the passed-in index aoMap.AddLayer(geoFeatureLayer); aoMap.MoveLayer(geoFeatureLayer, layerIndex); // Before pushing the changes to the server, create a dictionary containing the current visibility of the map layers. // We do this because updating the objects on the server (via RefreshServerObjects) also updates the map description // referenced by the map resource with the service's updated default description, which includes default layer // visibility. So when RefreshServerObjects is called, the visibility of the map layers will be reset to default System.Collections.Generic.Dictionary<string, bool> visibleLayers = new System.Collections.Generic.Dictionary<string, bool>(); foreach (ESRI.ArcGIS.ADF.ArcGISServer.LayerDescription layerDescription in mapResourceLocal.MapDescription.LayerDescriptions) { visibleLayers.Add(layerDescription.LayerID.ToString(), layerDescription.Visible); } // Register changes to server object, adding the passed-in layer at the map service level. mapResourceLocal.RefreshServerObjects(); // Reset the visibility of the layers in the resource's map description to what it was before updating the map service. foreach (System.Collections.Generic.KeyValuePair<string, bool> layerVisiblePair in visibleLayers) { ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality.UpdateVisibleLayer( mapResourceLocal.MapDescription, layerVisiblePair.Key, layerVisiblePair.Value); } } // Removes the layer with the passed-in name from the passed-in resource public System.Collections.Generic.Dictionary<int, ESRI.ArcGIS.Carto.ILayer> RemoveLayer( ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal mapResourceLocal, string layerName) { // Get the map underlying the passed-in map resource ESRI.ArcGIS.Carto.IMapServerObjects mapServerObjects = (ESRI.ArcGIS.Carto.IMapServerObjects)mapResourceLocal.MapServer; ESRI.ArcGIS.Carto.IMap aoMap = mapServerObjects.get_Map(mapResourceLocal.DataFrame); // Get a reference to the layer with the passed-in name from the map ESRI.ArcGIS.Carto.IEnumLayer enumLayer = aoMap.get_Layers(null, true); ESRI.ArcGIS.Carto.ILayer currentLayer = null; System.Collections.Generic.Dictionary<int, ESRI.ArcGIS.Carto.ILayer> removedLayerDictionary = new System.Collections.Generic.Dictionary<int, ESRI.ArcGIS.Carto.ILayer>(); int layerIndex = 0; while ((currentLayer = enumLayer.Next()) != null) { if (currentLayer.Name == layerName) { removedLayerDictionary.Add(layerIndex, currentLayer); break; } layerIndex++; } // Make sure the layer was found before executing logic to remove it if (currentLayer != null) { // Delete the layer from the map aoMap.DeleteLayer(currentLayer); // Before committing the change to the map service, create a dictionary containing the current visibility of the map layers. // We do this because updating the objects on the server (via RefreshServerObjects) also updates the map description // referenced by the map resource with the service's updated default description, which includes default layer visibility. System.Collections.Generic.Dictionary<string, bool> visibleLayers = new System.Collections.Generic.Dictionary<string, bool>(); foreach (ESRI.ArcGIS.ADF.ArcGISServer.LayerDescription layerDescription in mapResourceLocal.MapDescription.LayerDescriptions) { visibleLayers.Add(layerDescription.LayerID.ToString(), layerDescription.Visible); } // Register the layer removal with the server object mapResourceLocal.RefreshServerObjects(); // Reset the visibility of the remaining layers back to what it was before the update foreach (System.Collections.Generic.KeyValuePair<string, bool> layerVisiblePair in visibleLayers) { ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality.UpdateVisibleLayer( mapResourceLocal.MapDescription, layerVisiblePair.Key, layerVisiblePair.Value); } } return removedLayerDictionary; } // Moves the layer with the passed-in name to the passed-in index within the passed-in resource public int MoveLayer(ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal mapResourceLocal, string layerName, int layerIndex) { // Get the map underlying the passed-in map resource ESRI.ArcGIS.Carto.IMapServerObjects mapServerObjects = (ESRI.ArcGIS.Carto.IMapServerObjects)mapResourceLocal.MapServer; ESRI.ArcGIS.Carto.IMap aoMap = mapServerObjects.get_Map(mapResourceLocal.DataFrame); if ((layerIndex < 0) || (layerIndex > aoMap.LayerCount - 1)) return -1; // Get a reference to the layer with the passed-in name from the map ESRI.ArcGIS.Carto.IEnumLayer enumLayer = aoMap.get_Layers(null, true); ESRI.ArcGIS.Carto.ILayer currentLayer = null; while ((currentLayer = enumLayer.Next()) != null) { if (currentLayer.Name == layerName) break; } // Make sure the layer was found before executing logic to move it if (currentLayer != null) { // Move the layer to the passed-in layer index aoMap.MoveLayer(currentLayer, layerIndex); // Before committing the change to the map service, create a dictionary containing the current visibility of the map layers. // We do this because updating the objects on the server (via RefreshServerObjects) also updates the map description // referenced by the map resource with the service's updated default description, which includes default layer visibility. System.Collections.Generic.Dictionary<string, bool> visibleLayers = new System.Collections.Generic.Dictionary<string, bool>(); foreach (ESRI.ArcGIS.ADF.ArcGISServer.LayerDescription layerDescription in mapResourceLocal.MapDescription.LayerDescriptions) { visibleLayers.Add(layerDescription.LayerID.ToString(), layerDescription.Visible); } // Register the layer repositioning with the server object mapResourceLocal.RefreshServerObjects(); // Reset the visibility of the remaining layers back to what it was before the update foreach (System.Collections.Generic.KeyValuePair<string, bool> layerVisiblePair in visibleLayers) { ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality.UpdateVisibleLayer( mapResourceLocal.MapDescription, layerVisiblePair.Key, layerVisiblePair.Value); } } return layerIndex; } // Changes the renderers for all layers belonging to the passed-in local map resource. If rendererAction is ApplyNew, // the renderers are set to simple renderers with randomly generated colors. If ApplyOriginal, the renderers are set // to what they were when the page first loaded. If ApplyLast, then the renderers are set to the last new renderer // applied. public void ApplySimpleRenderers(ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal mapResourceLocal, RendererAction rendererAction) { // Get a reference to the ArcObjects map and layers via server context ESRI.ArcGIS.Server.IServerContext aoServerContext = mapResourceLocal.ServerContextInfo.ServerContext; ESRI.ArcGIS.Carto.IMapServerObjects aoMapServerObjects = (ESRI.ArcGIS.Carto.IMapServerObjects)mapResourceLocal.MapServer; ESRI.ArcGIS.Carto.IMap aoMap = aoMapServerObjects.get_Map(mapResourceLocal.DataFrame); ESRI.ArcGIS.Carto.IEnumLayer enumLayer = aoMap.get_Layers(null, true); // For each layer, we will store a dictionary containing its initial renderers (i.e. on initial load) in session. // Check whether the session variable for the current layer has already been created. If so, retrieve it. If not, // create a new dictionary. This dictionary will be used to reset renderers to their initial load state. System.Collections.Generic.Dictionary<int, ESRI.ArcGIS.Carto.IFeatureRenderer> originalRendererDictionary = null; string originalRendererKey = string.Format("{0}_originalRendererDictionary", mapResourceLocal.Name); if (System.Web.HttpContext.Current.Session[originalRendererKey] == null) originalRendererDictionary = new System.Collections.Generic.Dictionary<int, ESRI.ArcGIS.Carto.IFeatureRenderer>(); else originalRendererDictionary = (System.Collections.Generic.Dictionary<int, ESRI.ArcGIS.Carto.IFeatureRenderer>) System.Web.HttpContext.Current.Session[originalRendererKey]; // For each layer, we will also store a dictionary containing its current renderers. This will be used to re-apply // the current renderer on each page request. System.Collections.Generic.Dictionary<int, ESRI.ArcGIS.Carto.IFeatureRenderer> currentRendererDictionary = null; string currentRendererKey = string.Format("{0}_currentRendererDictionary", mapResourceLocal.Name); if (System.Web.HttpContext.Current.Session[currentRendererKey] == null) currentRendererDictionary = new System.Collections.Generic.Dictionary<int, ESRI.ArcGIS.Carto.IFeatureRenderer>(); else currentRendererDictionary = (System.Collections.Generic.Dictionary<int, ESRI.ArcGIS.Carto.IFeatureRenderer>) System.Web.HttpContext.Current.Session[currentRendererKey]; // Loop through each layer in the current map, either applying a new random simple renderer, reverting to the random simple // renderer that was last applied, or reverting the renderer to its initial load state. int layerIndex = 0; ESRI.ArcGIS.Carto.IGeoFeatureLayer aoGeoFeatureLayer = null; while ((aoGeoFeatureLayer = (ESRI.ArcGIS.Carto.IGeoFeatureLayer)enumLayer.Next()) != null) { switch (rendererAction) { case RendererAction.ApplyNew: // If the current layer's renderer is not in the dictionary of initial renderers, then this is the // first time this code has been executed during the session. The layer's current renderer is // therefore the initial load state renderer, so we add it to the original renderer dictionary. if (!originalRendererDictionary.ContainsKey(layerIndex)) { originalRendererDictionary.Add(layerIndex, aoGeoFeatureLayer.Renderer); System.Web.HttpContext.Current.Session[originalRendererKey] = originalRendererDictionary; } // Apply a randomly colored simple renderer to the current layer ApplySimpleRenderer(aoGeoFeatureLayer, aoServerContext, -1, -1, -1); // If the current renderer dictionary contains the current layer's renderer, remove it so it can // be replaced with the new renderer. if (currentRendererDictionary.ContainsKey(layerIndex)) currentRendererDictionary.Remove(layerIndex); // Update the current renderer dictionary with the current renderer currentRendererDictionary.Add(layerIndex, aoGeoFeatureLayer.Renderer); System.Web.HttpContext.Current.Session[currentRendererKey] = currentRendererDictionary; break; case RendererAction.ApplyLast: // Set the layer's renderer to the last random simple renderer applied aoGeoFeatureLayer.Renderer = (ESRI.ArcGIS.Carto.IFeatureRenderer)currentRendererDictionary[layerIndex]; break; case RendererAction.ApplyOriginal: // Set the layer's renderer to the one it had when the session started if (originalRendererDictionary.ContainsKey(layerIndex)) aoGeoFeatureLayer.Renderer = (ESRI.ArcGIS.Carto.IFeatureRenderer)originalRendererDictionary[layerIndex]; break; } layerIndex++; } // Get the current resource's map description before the map and layers are updated on the server. We do this // because when the server objects are updated, the layer visibility reverts to that specified by the map // document underlying the map service, and the map description contains information about current layer // visibility ESRI.ArcGIS.ADF.ArcGISServer.MapDescription adfMapDescription = mapResourceLocal.MapDescription; // Register the layer changes with the server. This applies the new renderer. mapResourceLocal.RefreshServerObjects(); // Set the resource's map description to that retrieved before server objects were updated, so layer visibility // is the same as before the update. mapResourceLocal.MapDescription = adfMapDescription; } // Generates a simple renderer and applies it to the passed-in layer. For any passed-in color value that is not within the // valid range (0-255), a random value within the valid range is applied. So, for example, a randomly colored renderer can // be generated by passing in RGB parameters of -1, -1, and -1. private void ApplySimpleRenderer(ESRI.ArcGIS.Carto.IGeoFeatureLayer aoGeoFeatureLayer, ESRI.ArcGIS.Server.IServerContext aoServerContext, int red, int green, int blue) { // Generate an ArcObjects color for the renderer. Use the specified RGB value if valid, otherwise use a random integer within // the valid range. ESRI.ArcGIS.Display.IRgbColor aoRgbColor = (ESRI.ArcGIS.Display.IRgbColor)aoServerContext.CreateObject("esriDisplay.RgbColor"); System.Random randomizer = new System.Random(); if ((red < 0) || (red > 255)) aoRgbColor.Red = randomizer.Next(0, 256); else aoRgbColor.Red = red; if ((green < 0) || (green > 255)) aoRgbColor.Green = randomizer.Next(0, 256); else aoRgbColor.Green = green; if ((blue < 0) || (blue > 255)) aoRgbColor.Blue = randomizer.Next(0, 256); else aoRgbColor.Blue = blue; // Instantiate an ArcObjects simple renderer to use in specifying the layer's renderer ESRI.ArcGIS.Carto.ISimpleRenderer aoSimpleRenderer = (ESRI.ArcGIS.Carto.ISimpleRenderer) aoServerContext.CreateObject("esriCarto.SimpleRenderer"); // Check the layer's geometry type and create a symbol for the renderer accordingly ESRI.ArcGIS.Geometry.esriGeometryType geometryType = aoGeoFeatureLayer.FeatureClass.ShapeType; switch (aoGeoFeatureLayer.FeatureClass.ShapeType) { case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint: ESRI.ArcGIS.Display.ISimpleMarkerSymbol aoSimpleMarkerSymbol = (ESRI.ArcGIS.Display.ISimpleMarkerSymbol)aoServerContext.CreateObject("esriDisplay.SimpleMarkerSymbol"); aoSimpleMarkerSymbol.Color = (ESRI.ArcGIS.Display.IColor)aoRgbColor; aoSimpleRenderer.Symbol = (ESRI.ArcGIS.Display.ISymbol)aoSimpleMarkerSymbol; break; case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline: ESRI.ArcGIS.Display.ISimpleLineSymbol aoSimpleLineSymbol = (ESRI.ArcGIS.Display.ISimpleLineSymbol)aoServerContext.CreateObject("esriDisplay.SimpleLineSymbol"); aoSimpleLineSymbol.Color = (ESRI.ArcGIS.Display.IColor)aoRgbColor; aoSimpleRenderer.Symbol = (ESRI.ArcGIS.Display.ISymbol)aoSimpleLineSymbol; break; case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon: ESRI.ArcGIS.Display.ISimpleFillSymbol aoSimpleFillSymbol = (ESRI.ArcGIS.Display.ISimpleFillSymbol)aoServerContext.CreateObject("esriDisplay.SimpleFillSymbol"); aoSimpleFillSymbol.Color = (ESRI.ArcGIS.Display.IColor)aoRgbColor; aoSimpleRenderer.Symbol = (ESRI.ArcGIS.Display.ISymbol)aoSimpleFillSymbol; break; default: throw new System.Exception("No renderer or symbol selected. Shape type undetermined."); } // Assign the new renderer to the passed-in layer aoGeoFeatureLayer.Renderer = (ESRI.ArcGIS.Carto.IFeatureRenderer)aoSimpleRenderer; } }