ArcGIS Add Dynamic Data
ArcGIS_AddDynamicData_CSharp\Default.aspx.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.
// 

// Illustrates how to add a new layer dynamically to a pooled ArcGIS Server map service and display the map image 
// using ArcObjects and ASP.NET only - no Web ADF controls
public partial class _Default : System.Web.UI.Page
{
    #region Instance Variable Declarations

    System.Data.DataTable _layerDataTable;

    #endregion

    #region ASP.NET Page Life Cycle Event Handlers

    protected void Page_Init(object sender, System.EventArgs e)
    {
        try
        {
            // Read the contents of the layers.config file, which is assumed to contained the names and paths of the
            // shapefiles that can be dynamically added to the map.  Store this data in a data table member variable.
            if (!Page.IsPostBack)
            {
                // Create an empty data table to hold the shapefile names and paths
                _layerDataTable = new System.Data.DataTable("layerTable");
                System.Data.DataColumn layerNameDataColumn = new System.Data.DataColumn("layerName");
                System.Data.DataColumn layerPathDataColumn = new System.Data.DataColumn("layerPath");
                _layerDataTable.Columns.Add(layerNameDataColumn);
                _layerDataTable.Columns.Add(layerPathDataColumn);

                // Get the root path of the web application and append the name of the file containing the
                // shapefile list
                string rootPath = Server.MapPath("~");
                string layerCatalogPath = string.Format("{0}/layers.catalog", rootPath);

                // Get a reader to access the layer catalog
                System.IO.StreamReader layerCatalogReader = new System.IO.StreamReader(layerCatalogPath);

                // Initialize the delimiter that separates shapefile names and paths in the layer catalog
                string layerDelimiterString = "=";
                char[] layerDelimiter = layerDelimiterString.ToCharArray();

                // Iterate through the lines of the layer catalog, adding each pair of shapefile names and paths
                // to the data table
                string[] layerSpecs = null;
                string currentLine = null;
                while (layerCatalogReader.Peek() != -1)
                {
                    currentLine = layerCatalogReader.ReadLine();

                    // If the current line does not contain the delimiter, assume the end of the file has been reached
                    if (!currentLine.Contains("="))
                        break;

                    // Split the current line into the shapefile name and path and add this data to the data table
                    layerSpecs = currentLine.Split(layerDelimiter);
                    System.Data.DataRow dataRow = _layerDataTable.NewRow();
                    dataRow[0] = layerSpecs[0];
                    dataRow[1] = layerSpecs[1];
                    _layerDataTable.Rows.Add(dataRow);
                }
                layerCatalogReader.Close();
            }
        }
        catch (System.Exception exception)
        {
            // Since the page has not yet rendered, we write the javascript to show an alert containing error info
            // directly to the page response
            string jsErrorAlert = string.Format("<script>{0}</script>", Utility.GetJavaScriptErrorString(exception));
            Response.Write(jsErrorAlert);
        }
    }

    protected void Page_PreRender(object sender, System.EventArgs e)
    {
        try
        {
            // Bind DropDownList to data table containing layer names
            DropDownList1.DataSource = _layerDataTable;
            DropDownList1.DataTextField = "layerName";
            DropDownList1.DataValueField = "layerPath";
            DropDownList1.DataBind();

            if (!Page.IsPostBack)
            {
                if (Session.IsNewSession)
                {
                    // On initial page prerender, add session variables to track whether a layer was added and its id 
                    Session["dynamicLayerAdded"] = false;
                    Session["addedLayerID"] = null;

                    // Get the default map description from the server
                    ESRI.ArcGIS.Server.IServerContext serverContext = this.GetServerContext();
                    ESRI.ArcGIS.Carto.IMapServer mapServer = serverContext.ServerObject as ESRI.ArcGIS.Carto.IMapServer;
                    ESRI.ArcGIS.Carto.IMapServerInfo mapServerInfo = mapServer.GetServerInfo(mapServer.DefaultMapName);
                    ESRI.ArcGIS.Carto.IMapDescription aoMapDescription = mapServerInfo.DefaultMapDescription;

                    // Create a new map image and display in the page
                    CreateMapImage(serverContext, aoMapDescription);

                    serverContext.ReleaseContext();
                }
                else
                {
                    // If this is not the initial page prerender, then the map image must be recreated with the 
                    // dynamically added layer, if one has been added.  So we create the server context, get the
                    // map description that's holding layer visibility information from session, add the dynamic 
                    // layer to the server state, create the map image based on server state, then remove the layer
                    // from server state so it does not remain part of the map service
                    ESRI.ArcGIS.Server.IServerContext serverContext = GetServerContext();
                    ESRI.ArcGIS.Carto.IMapServer mapServer = serverContext.ServerObject as ESRI.ArcGIS.Carto.IMapServer;
                    ESRI.ArcGIS.Carto.IMapServerInfo mapServerInfo = mapServer.GetServerInfo(mapServer.DefaultMapName);
                    ESRI.ArcGIS.Carto.IMapDescription aoMapDescription = mapServerInfo.DefaultMapDescription;

                    if ((bool)Session["dynamicLayerAdded"])
                        AddSelectedLayer(serverContext);

                    CreateMapImage(serverContext, aoMapDescription);

                    RemoveDynamicLayer(serverContext);
                    serverContext.ReleaseContext();
                }
            }
        }
        catch (System.Exception exception)
        {
            // Since the page has not yet rendered, we write the javascript to show an alert containing error info
            // directly to the page response
            string jsErrorAlert = string.Format("<script>{0}</script>", Utility.GetJavaScriptErrorString(exception));
            Response.Write(jsErrorAlert);
        }
    }

    #endregion

    #region ASP.NET Web Control Event Handlers

    // Fires when the Add Layer button is clicked
    protected void AddLayer_Click(object sender, System.EventArgs e)
    {
        try
        {
            // Set the session variable indicating that a layer has been added during the current session
            Session["dynamicLayerAdded"] = true;

            // Add the currently selected layer to the map service
            ESRI.ArcGIS.Server.IServerContext serverContext = GetServerContext();
            AddSelectedLayer(serverContext);

            // Create a map image.  The image will contain the dynamic layer because that layer has been added
            // to the map service, meaning the default map description will include this layer.
            ESRI.ArcGIS.Carto.IMapServer mapServer = (ESRI.ArcGIS.Carto.IMapServer)serverContext.ServerObject;
            ESRI.ArcGIS.Carto.IMapServerInfo mapServerInfo = mapServer.GetServerInfo(mapServer.DefaultMapName);
            ESRI.ArcGIS.Carto.IMapDescription aoMapDescription = mapServerInfo.DefaultMapDescription;
            CreateMapImage(serverContext, aoMapDescription);

            // Since we do not want to make a persistent change to the map service, we remove the layer once we
            // have created an image containing it
            RemoveDynamicLayer(serverContext);

            serverContext.ReleaseContext();
        }
        catch (System.Exception exception)
        {
            // Since the page is in a full page postback, we write the javascript to show an alert containing error info
            // directly to the page response
            string jsErrorAlert = string.Format("<script>{0}</script>", Utility.GetJavaScriptErrorString(exception));
            Response.Write(jsErrorAlert);
        }
    }

    // Fires when the Change Extent button is clicked
    protected void ChangeExtent_Click(object sender, System.EventArgs e)
    {
        try
        {
            // If a dynamic layer has been added during the current session, it needs to be re-added, since we
            // are not persistently adding the layer to the service
            ESRI.ArcGIS.Server.IServerContext serverContext = this.GetServerContext();

            if ((bool)Session["dynamicLayerAdded"])
                AddSelectedLayer(serverContext);

            // Get the map service's description and extent
            ESRI.ArcGIS.Carto.IMapServer mapServer = (ESRI.ArcGIS.Carto.IMapServer)serverContext.ServerObject;
            ESRI.ArcGIS.Carto.IMapServerInfo mapServerInfo = mapServer.GetServerInfo(mapServer.DefaultMapName);
            ESRI.ArcGIS.Carto.IMapDescription mapDescription = mapServerInfo.DefaultMapDescription;

            ESRI.ArcGIS.Carto.IMapArea mapArea = mapDescription.MapArea;
            ESRI.ArcGIS.Carto.IMapExtent mapExtent = mapArea as ESRI.ArcGIS.Carto.IMapExtent;

            // Create a new envelope and update the service extent with it
            ESRI.ArcGIS.Geometry.IEnvelope aoEnvelope =
                (ESRI.ArcGIS.Geometry.IEnvelope)serverContext.CreateObject("esriGeometry.Envelope");
            aoEnvelope.PutCoords(-120, 30, -50, 50);
            mapExtent.Extent = aoEnvelope;

            // Create a map image  
            CreateMapImage(serverContext, mapDescription);

            // Since we do not want to make a persistent change to the map service, we remove the layer once we
            // have created the map image containing it
            RemoveDynamicLayer(serverContext);

            serverContext.ReleaseContext();
        }
        catch (System.Exception exception)
        {
            // Since the page has not yet rendered, we write the javascript to show an alert containing error info
            // directly to the page response
            string jsErrorAlert = string.Format("<script>{0}</script>", Utility.GetJavaScriptErrorString(exception));
            Response.Write(jsErrorAlert);
        }
    }

    #endregion

    #region Instance Methods

    // Retrieves the server context of the map service specified by the serverName and mapServiceName variables
    private ESRI.ArcGIS.Server.IServerContext GetServerContext()
    {
        string serverName = "localhost";
        string mapServiceName = "USA";
        ESRI.ArcGIS.Server.IServerObjectManager serverObjectManager;

        // Check whether the session variable storing the ServerObjectManager is null and initialize it if so.  
        // This code only executes once because we only want to create one connection per session.
        if (Session["SOM"] == null)
        {
            // Using ADF connection library
            ESRI.ArcGIS.ADF.Connection.AGS.AGSServerConnection agsServerConnection =
                new ESRI.ArcGIS.ADF.Connection.AGS.AGSServerConnection();
            agsServerConnection.Host = serverName;
            agsServerConnection.Connect();

            serverObjectManager = agsServerConnection.ServerObjectManager;
            Session["SOM"] = serverObjectManager;
        }
        else
        {
            serverObjectManager = Session["SOM"] as ESRI.ArcGIS.Server.IServerObjectManager;
        }

        // Create a map server context with the specified map service name
        ESRI.ArcGIS.Server.IServerContext serverContext = 
            serverObjectManager.CreateServerContext(mapServiceName, "MapServer");

        return serverContext;
    }
    
    // Adds the currently selected layer to the map service
    private void AddSelectedLayer(ESRI.ArcGIS.Server.IServerContext serverContext)
    {
        // Use ArcObjects to get the ArcObjects map underlying the map service
        ESRI.ArcGIS.Carto.IMapServer mapServer = (ESRI.ArcGIS.Carto.IMapServer)serverContext.ServerObject;
        ESRI.ArcGIS.Carto.IMapServerObjects2 mapServerObjects = (ESRI.ArcGIS.Carto.IMapServerObjects2)mapServer;
        string mapName = mapServer.DefaultMapName;
        ESRI.ArcGIS.Carto.IMap aoMap = mapServerObjects.get_Map(mapName);

        // Retrieve the currently selected item and parse its value into the shapefile directory path and file name
        System.Web.UI.WebControls.ListItem listItem = DropDownList1.SelectedItem;
        int lastSlashIndex = listItem.Value.LastIndexOf("/");
        string filePath = listItem.Value.Substring(0, lastSlashIndex);
        string fileName = listItem.Value.Substring(lastSlashIndex + 1);

        // Get a reference to the shapefile directory as an ArcObjects FeatureWorkspace
        ESRI.ArcGIS.Geodatabase.IWorkspaceFactory workspaceFactory =
            (ESRI.ArcGIS.Geodatabase.IWorkspaceFactory)serverContext.CreateObject("esriDataSourcesFile.ShapefileWorkspaceFactory");
        ESRI.ArcGIS.Geodatabase.IWorkspace workspace = workspaceFactory.OpenFromFile(filePath, 0);
        ESRI.ArcGIS.Geodatabase.IFeatureWorkspace featureWorkspace = (ESRI.ArcGIS.Geodatabase.IFeatureWorkspace)workspace;

        // Get a reference to the shapefile as a GeoFeatureLayer
        ESRI.ArcGIS.Carto.IFeatureLayer aoFeatureLayer = (ESRI.ArcGIS.Carto.IFeatureLayer)serverContext.CreateObject("esriCarto.FeatureLayer");
        // Or use the guid for esriCarto.FeatureLayer
        //IFeatureLayer layer = (IFeatureLayer)in_mapcontext.CreateObject("{E663A651-8AAD-11D0-BEC7-00805F7C4268}");
        aoFeatureLayer.FeatureClass = featureWorkspace.OpenFeatureClass(fileName);
        aoFeatureLayer.Name = listItem.Text;
        ESRI.ArcGIS.Carto.IGeoFeatureLayer geoFeatureLayer = (ESRI.ArcGIS.Carto.IGeoFeatureLayer)aoFeatureLayer;

        // Create an ArcObjects color object with the color set to blue for use by the layer's renderer
        ESRI.ArcGIS.Display.IRgbColor rgbColor = (ESRI.ArcGIS.Display.IRgbColor)serverContext.CreateObject("esriDisplay.RgbColor");
        rgbColor.Red = 0;
        rgbColor.Green = 0;
        rgbColor.Blue = 210;

        // Set the symbol of the GeoFeatureLayer's renderer to use the color initialized above
        ESRI.ArcGIS.Carto.ISimpleRenderer aoSimpleRenderer = (ESRI.ArcGIS.Carto.ISimpleRenderer)geoFeatureLayer.Renderer;
        ESRI.ArcGIS.Geometry.esriGeometryType geometryType = aoFeatureLayer.FeatureClass.ShapeType;
        if (geometryType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint)
        {
            ESRI.ArcGIS.Display.ISimpleMarkerSymbol simpleMarkerSymbol = 
                (ESRI.ArcGIS.Display.ISimpleMarkerSymbol)aoSimpleRenderer.Symbol;
            simpleMarkerSymbol.Color = (ESRI.ArcGIS.Display.IColor)rgbColor;
        }
        else if (geometryType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline)
        {
            ESRI.ArcGIS.Display.ISimpleLineSymbol simpleLineSymbol = (ESRI.ArcGIS.Display.ISimpleLineSymbol)aoSimpleRenderer.Symbol;
            simpleLineSymbol.Color = (ESRI.ArcGIS.Display.IColor)rgbColor;
        }
        else if (geometryType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon)
        {
            ESRI.ArcGIS.Display.ISimpleFillSymbol simpleFillSymbol = (ESRI.ArcGIS.Display.ISimpleFillSymbol)aoSimpleRenderer.Symbol;
            simpleFillSymbol.Color = (ESRI.ArcGIS.Display.IColor)rgbColor;
        }
        else
        {
            throw new System.Exception("No renderer or symbol selected.  Shape type undetermined.");
        }

        // Add the layer to the map service's map
        aoMap.AddLayer(aoFeatureLayer);
        mapServerObjects.RefreshServerObjects();

        // Store the map service ID of the layer in session
        Session["addedLayerID"] = mapServerObjects.get_LayerID(mapName, aoFeatureLayer);
    }

    // Creates a JPEG image based on the passed-in server context and map description and sets the MapImage web 
    // control to display it
    private void CreateMapImage(ESRI.ArcGIS.Server.IServerContext serverContext, ESRI.ArcGIS.Carto.IMapDescription aoMapDescription)
    {
        ESRI.ArcGIS.Carto.IImageType imageType;
        ESRI.ArcGIS.Carto.IImageDescription imageDescription;
        ESRI.ArcGIS.Carto.IImageDisplay imageDisplay;

        imageType = serverContext.CreateObject("esriCarto.ImageType") as ESRI.ArcGIS.Carto.IImageType;
        imageDescription = serverContext.CreateObject("esriCarto.ImageDescription") as ESRI.ArcGIS.Carto.ImageDescription;
        imageDisplay = serverContext.CreateObject("esriCarto.ImageDisplay") as ESRI.ArcGIS.Carto.ImageDisplay;

        // Set properties to have the image output a JPEG and refer to it via URL
        imageType.Format = ESRI.ArcGIS.Carto.esriImageFormat.esriImageJPG;
        imageType.ReturnType = ESRI.ArcGIS.Carto.esriImageReturnType.esriImageReturnURL;

        // Initialize image height and width based on the dimensions of the MapImage Image control
        imageDisplay.Height = (int)MapImage.Height.Value;
        imageDisplay.Width = (int)MapImage.Width.Value;
        imageDisplay.DeviceResolution = 96;

        imageDescription.Display = imageDisplay;
        imageDescription.Type = imageType;

        ESRI.ArcGIS.Carto.IMapServer mapServer = (ESRI.ArcGIS.Carto.IMapServer)serverContext.ServerObject;

        // Create the map image and set the MapImage control to display it
        ESRI.ArcGIS.Carto.IImageResult mapImage = mapServer.ExportMapImage(aoMapDescription, imageDescription);
        MapImage.ImageUrl = mapImage.URL;
        MapImage.Visible = true;
    }

    // Removes the dynamically added layer from the map service
    private void RemoveDynamicLayer(ESRI.ArcGIS.Server.IServerContext serverContext)
    {
        // Check whether a dynamic layer has been added during the session
        bool layerAdded = (bool)Session["dynamicLayerAdded"];

        if (layerAdded)
        {
            // Retrieve the dynamic layer from the map service and delete it.  Note that we know the layer has been
            // added at index 0, so we can safely delete the layer at this index.
            ESRI.ArcGIS.Carto.IMapServer mapServer = (ESRI.ArcGIS.Carto.IMapServer)serverContext.ServerObject;
            ESRI.ArcGIS.Carto.IMapServerObjects mapServerObjects = (ESRI.ArcGIS.Carto.IMapServerObjects)mapServer;
            ESRI.ArcGIS.Carto.IMap aoMap = mapServerObjects.get_Map(mapServer.DefaultMapName);
            ESRI.ArcGIS.Carto.ILayer aoLayer = aoMap.get_Layer(0);

            aoMap.DeleteLayer(aoLayer);
            mapServerObjects.RefreshServerObjects();
        }
    }

    #endregion
}