How to create an SOE client


Summary The topic discusses how to create a client application to consume and utilize a server object extension (SOE).

In this topic


Creating the client Web application

Now that you have developed the SOE and deployed it with an ArcGIS Server map service, you can build a Web application to use it. In this section of the implementation, you will create a Web application using the Web Application Developer Framework's (ADF's) components. The Web ADF and ASP.NET provide the basic framework for mapping, capturing user events, and displaying results. You will create a custom tool to interact with the SOE.

Registering COM types in the SpatialQuerySOE.Interfaces assembly

The SpatialQuerySOE.Interfaces.dll must be registered on any client machine that consumes the SOE. For more information, see How to register the SOE. The assembly contains Component Object Model (COM) interface types that will be used by the Web application to work with the custom SOE's COM objects remotely. The SpatialQuerySOE.Interfaces.dll was built in How to develop the SOE.
Do the following steps to register COM types:
  1. Start a Visual Studio command prompt and navigate to the location of SpatialQuerySOE.Interfaces.dll.
  2. Type the following command:
    • regasm SpatialQuerySOE.Interfaces.dll /tlb:SpatialQuerySOE.Interfaces.tlb

    The regasm tool reads the metadata within an assembly and adds the necessary entries to the registry. Since the assembly only contains interface types, a type library must be generated using the /tlb option. The location of the tlb is stored in the registry.

Creating the Web application project

  1. Start Visual Studio.
  2. Click the File menu, click New, then click Web Site. The New Web Site dialog box appears.
  3. Under the Templates pane, click ASP.NET Web Site.
  4. Type the following for the Web application name and uniform resource locator (URL):
    • http://localhost/ArcGIS_Spatial_Query_SOE_CSharp/SpatialQuerySOE_WebSite_CSharp.

Adding and configuring Web ADF and ASP.NET controls

Do the following steps to add and configure each control:
  1. Add the MapResourceManager, Map, Toolbar, Toc, Label, Textbox, Checkbox, and div controls in the locations specified on the following screen shot:


  2. Configure the MapResourceManager control:
    1. Set the ResourceItems property on the MapResourceManager control. In design view, click Edit Resources on the smart tag menu for the control or on the MapResourceManager property page, click the ellipsis button next to the ResourceItems property to show the MapResourceInfo Collection Editor dialog box. See the following screen shot that shows the smart tag menu:


    2. To add a new MapResourceItem, click Add on the MapResourceItem Collection Editor dialog box. Change the name to Vegetation Layers.
    3. Set the MapResourceItem's definition property by clicking the ellipsis button on the property page to show the Map Resource Definition Editor dialog box. Select the ArcGIS Server Local data source type and specify the name of the server object manager (SOM) machine on which the Yellowstone map service is running with the custom SOE enabled. See the following screen shots:


    4. When the data source is defined, click the ellipsis button next to the Resource property to open the ArcGIS Resource Definition Editor dialog box, which provides a list of available map service and data frames. Select the Yellowstone map service and the default data frame. See the following screen shots:


    5. The Identity property on the Map Resource Definition Editor dialog box is unavailable and cannot be set. At design time, the identity of the user running Visual Studio is used to connect to an ArcGIS Server local data source. At run time, that identity is established by the Web application. Only one identity can be used to define access to all ArcGIS Server local data sources in a single Web application. You can define this identity by right-clicking the Web project in the Solution Explorer and selecting the Add ArcGIS Identity option. 

      Add the identity credentials that will be used to access the ArcGIS Server local resources at run time. This information is added to the web.config file within a standard ASP.NET identity tag. If the Encrypt identity in web.config check box is selected, the identity tag is encrypted; otherwise, the user name and password is stored as clear text. See the following screen shots:


  3. Configure the Map control by setting the MapResourceManager property. Select the Map control in design view or in the Properties window, then click the drop-down list for the MapResourceManager property. Select the MapResourceManager name that was previously configured (by default, MapResourceManager1).
  4. Configure the Toolbar control by setting its BuddyControl and ToolbarItems properties. See the following screen shots:


    1. Specify the map the toolbar works with through the Toolbar control's BuddyControls property. See the following screen shot:


    2. Set the BuddyControlType property to Map and click the ellipsis button in the BuddyControls property value to show the BuddyControls Collection Editor dialog box. On the dialog box, add an item and associate it with the Map control (Map1).
    3. To add an item to the toolbar, click the Toolbar control. In the Properties window, click the ellipsis button next to the ToolbarItems property. A form with a list of available toolbar items and toolbar elements appear.
    4. On the ToolbarItems area, individually select and add the Zoom In, Zoom Out, and Pan tools.
  5. Configure the Toc control by setting the BuddyControl property. Select the Toc control in design view or in the Properties window, then click the drop-down list for the BuddyControl property. Select the name of the Map control previously configured (by default, Map1).
  6. Configure the Label, Textbox, and Checkbox control. Confirm the ID for each control is Label1, Textbox1, and Checkbox1, respectively. Add the appropriate text for the Label and Checkbox control as shown in Step 1. Set the default value in Textbox1 to 10000. 
  7. Configure the div and GridView controls. Select the Hypertext Markup Language (HTML) div control and set its ID value to summaryStatsDiv (either on the property page or in the HTML source code). Drag and drop the GridView control into the div. Resize the GridView control to a height and width of 200 by 250.  

Adding JavaScript to capture user input and show tool progress

Initialize the custom SOE via a custom tool. The Web application user interface (UI) contains a text box and check box to store information that the custom tool uses to calculate buffer distance and updates a GridView with the custom tool output. In this section, add JavaScript to the Web application to capture text box and check box values, and add code that shows a progress indicator while the custom tool is executing.
Do the following steps to add JavaScript to the Web application:
  1. Add JavaScript to the Default.aspx page to declare page variables and execute initialization logic. The initialization logic, which is hooked to the Microsoft Asynchronous JavaScript and XML (AJAX) init event, wires event handlers for the map's onServerRequest and the toolbar's onToolSelected events, then verifies a ScriptManager is in the application. Add the following code example inside the closing tag of the page's form element:
[JavaScript]
 < script language = "javascript" type = "text/javascript" > 
// Tracks whether the vegetation summary tool is selected.
var vegToolSelected = false;

// Tracks whether a scriptManager is on the page.
var hasScriptManager = false;

// Add the initialize function to the page's AJAX initialization routine.
Sys.Application.add_init(initialize);

// Called during AJAX initialization.
function initialize(){
    // Get a reference to the client-side Web ADF map object.     
    var map = $find('Map1');
    // Add an event that fires when the map sends a request to the server.
    map.add_onServerRequest(mapServerRequest);

    // Get a reference to the client-side Web ADF toolbar object.
    var toolbar = $find('Toolbar1');
    // Add an event handler that fires when a tool on the toolbar is selected.
    toolbar.add_onToolSelected(toolbarToolSelected);

    // Verify a ScriptManager is on the page by determining if its client-tier 
    //  representation exists.
    if (Sys && Sys.WebForms && Sys.WebForms.PageRequestManager){
        // There is a ScriptManager on the page.  
        hasScriptManager = true;
    }

}

 <  / script >
  1. Inside the script element, define the event handler for the toolbar's onToolSelected event. The handler verifies if the custom tool was selected and updates the appropriate page variable accordingly. See the following code example:
[JavaScript]
// Fires when a tool on Toolbar1 is selected.
function toolbarToolSelected(toolbarObject, activeToolInfo){
    // Verify the clicked tool is one of your custom tools and set the tracking 
    //  Boolean accordingly.
    if (activeToolInfo.tool.name == "VegetationSummary")
        vegToolSelected = true;
    else
        vegToolSelected = false;
}
  1. Define the handler for the onMapServerRequest event. This event fires when the map issues a request, including when a user clicks the map with the custom tool activated. The handler verifies the custom tool is activated and if so, shows the progress indicator.

    If callbacks, rather than partial postbacks, are used for asynchronous functionality (that is, a ScriptManager is not on the page), add the input text box and check box values to the request via the addCustomArguments helper method that you will define in Step 4. Include the controls' values in the request so they can be retrieved in the custom tool implementation. If partial postbacks are used, the values of all ASP.NET server controls are automatically included in the request. See the following code example:
[JavaScript]
// Fires when the map sends a request to the server.
function mapServerRequest(mapObject, inputArgument){
    //Verify the vegetation summary tool is selected and a ScriptManager is on the page. 
    //If the tool is selected, but there is no ScriptManager, the values of the distance
    //text box and show summary results check box must be explicitly added to the page 
    //request arguments. Also, show the busy indicator.
    if (vegToolSelected){
        if (!hasScriptManager)
            inputArgument.argument = addCustomArguments(inputArgument.argument);
        var busyIndicator = $get('busyIndicator');
        busyIndicator.style.display = '';
    }
}
  1. Define the addCustomArguments method to retrieve the values of the input text box and check box, then add them to the passed in request. See the following code example:
[JavaScript]
function addCustomArguments(args){
    // Get the search distance and value of the show summary results check box.
    var searchDistance = $get('SearchDistanceTextBox').value;
    var showSummaryResults = $get('ShowResultsCheckBox').checked;

    // Add the control values to the passed in arguments with the control IDs as keys.
    args += String.format('&SearchDistanceTextBox={0}&ShowResultsCheckBox={1}',
        searchDistance, showSummaryResults);
    return args;
}

Adding a custom tool to work with the SOE

Do the following steps to add a custom tool:
  1. In the Solution Explorer, right-click the Web project and select Add New Item. The Add New Item dialog box appears. Under the Templates pane, select the Class item template. Verify the language is Visual C#, then type VegTool.cs in the Name text box. Click Yes when prompted, to create an App_Code folder and place the new class file inside. The VegTool.cs file opens for you to start adding content. This file contains the executable code associated with the custom tool.
  2. The SOE exposes the SpatialQuerySOE.IExtension and SpatialQuerySOE.IResults interfaces. As a client, the Web application needs a reference to the type definition for both interfaces to remotely utilize the COM objects they represent. The COM interface types are provided in SpatialQuerySOE.Interfaces.dll. In the Solution Explorer, right-click the Web project and select Add Reference. The Add Reference dialog box appears. Browse to the location of the SpatialQuerySOE.Interfaces.dll and add it to the project.
  3. Additional components are also required to work with ArcGIS Server and the Web ADF. In the Solution Explorer, right-click the Web project and select Add ArcGIS Reference. The Add ArcGIS Reference dialog box appears. Select the following components, click Add, then click Finish:
    • ESRI.ArcGIS.ADF.ArcGISServer
    • ESRI.ArcGIS.ADF.Connection
    • ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer
    • ESRI.ArcGIS.Carto
    • ESRI.ArcGIS.Display
    • ESRI.ArcGIS.Geodatabase
    • ESRI.ArcGIS.Geometry
    • ESRI.ArcGIS.Server
  4. Remove the VegTool constructor and implement IMapServerToolAction on the VegTool class. Begin the code for the class with the following code example:
[C#]
public class VegTool: ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerToolAction
{
    public void ServerAction(ESRI.ArcGIS.ADF.Web.UI.WebControls.ToolEventArgs
        toolEventArgs)
    {
[VB.NET]
Public Class VegTool
    Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerToolAction
  1. Get user input from the client by retrieving a reference to the buddied Map control and a reference to the page containing the Map. The value in the SearchDistanceTextBox is the buffer distance and ShowResultsCheckBox determines if a table with data is returned to the Web browser, and if the tool initiates a callback. If the tool initiates a partial postback (that is, a ScriptManager is on the page), the argument and value pairs for the input controls are included directly in the Hypertext Transfer Protocol (HTTP) request. Otherwise, the tool initiates a callback and the __CALLBACKPARAM argument in the HTTP request contains the argument and value pairs. See the following code example:
       
[C#]
// Get the Map control that was clicked.
ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap = toolEventArgs.Control as
    ESRI.ArcGIS.ADF.Web.UI.WebControls.Map;

// Get the page containing the Map control.
System.Web.UI.Page page = adfMap.Page;
// Get the request parameters.
System.Collections.Specialized.NameValueCollection requestParameters = null;
if (System.Web.UI.ScriptManager.GetCurrent(page) == null)
    requestParameters =
        ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection(page.Request.Params["__CALLBACKPARAM"]);
else
    requestParameters = page.Request.Params;
// Get the search distance.
double searchDistance;
if (!System.Double.TryParse(requestParameters["SearchDistanceTextBox"], out
    searchDistance))
    searchDistance = 10000;
// Get the value of the Show Results check box.
bool showSummaryStats;
if (!bool.TryParse(requestParameters["ShowResultsCheckBox"], out showSummaryStats))
    showSummaryStats = false;
[VB.NET]
' Get the map control that was clicked.
Dim adfMap As ESRI.ArcGIS.ADF.Web.UI.WebControls.Map = TryCast(args.Control, ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)
' Get the page containing the map control.
Dim page As System.Web.UI.Page = adfMap.Page
' Get the request parameters.
Dim requestParameters As System.Collections.Specialized.NameValueCollection = Nothing
If System.Web.UI.ScriptManager.GetCurrent(page) Is Nothing Then
    requestParameters = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection(page.Request.Params("__CALLBACKPARAM"))
Else
    requestParameters = page.Request.Params
End If
' Get the search distance.
Dim searchDistance As Double
If (Not System.Double.TryParse(requestParameters("SearchDistanceTextBox"), searchDistance)) Then
    searchDistance = 10000
End If
' Get the value of the Show Results check box.
Dim showSummaryStats As Boolean
If (Not Boolean.TryParse(requestParameters("ShowResultsCheckBox"), showSummaryStats)) Then
    showSummaryStats = False
End If
  1. The ArcGIS Server implementation of the Web ADF Common application programming interface (API) is used to get the map resource for an ArcGIS Server local data source (MapResourceLocal). Local data sources provide access to the ArcObjects API for a server object; therefore, you have access to server context and the stateless interface (IMapServer) for map services. Clicking in the Web browser provides the center point for a buffer to select and aggregate features. Server context is used to create an ArcObjects Point to use with the custom SOE. Buffer distance is set with the value provided by the user in SearchDistanceTextBox. See the following code example:
[C#]
// Get MapFunctionality and MapResource for the Vegetation layers' resource item.
ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality agsMapFunctionality =
    adfMap.GetFunctionality("Vegetation Layers")as
    ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality;
ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal agsMapResourceLocal = 
    (ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal)
    agsMapFunctionality.MapResource;
// Get the server context.
ESRI.ArcGIS.Server.IServerContext serverContext =
    agsMapResourceLocal.ServerContextInfo.ServerContext;
// Get the click point as an ArcObjects point.
ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs mapPointEventArgs =
    toolEventArgs as ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs;
ESRI.ArcGIS.Geometry.IPoint clickPoint = (ESRI.ArcGIS.Geometry.IPoint)
    serverContext.CreateObject("esriGeometry.Point");
clickPoint.X = mapPointEventArgs.MapPoint.X;
clickPoint.Y = mapPointEventArgs.MapPoint.Y;
[VB.NET]
' Get MapFunctionality and MapResource for the Vegetation Layers resource item.
Dim agsMapFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality = TryCast(adfMap.GetFunctionality("Vegetation Layers"), ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality)
Dim agsMapResourceLocal As ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal = CType(agsMapFunctionality.MapResource, ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal)
' Get the server context.
Dim serverContext As ESRI.ArcGIS.Server.IServerContext = agsMapResourceLocal.ServerContextInfo.ServerContext
' Get the click point as an ArcObjects point.
Dim mapPointEventArgs As ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs = TryCast(args, ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs)
Dim clickPoint As ESRI.ArcGIS.Geometry.IPoint = CType(serverContext.CreateObject("esriGeometry.Point"), ESRI.ArcGIS.Geometry.IPoint)
clickPoint.X = mapPointEventArgs.MapPoint.X
clickPoint.Y = mapPointEventArgs.MapPoint.Y
  1. Every server object type implements the ArcObjects IServerObjectExtensionManager interface to support the discovery of SOEs. If an SOE is enabled on the server object, use the FindExtensionByTypeName method to return a reference to the SOE with its registered name. In this case, the custom SOE class (SpatialQuerySOE.Extension) implements the SpatialQuerySOE.IExtension interface, which exposes a single method, QueryPoint. The method requires the following parameters to store distance:
    • ArcObjects Point
    • Double value
    The method uses the point and distance to construct a buffer. When the SOE was enabled (in ArcCatalog or ArcGIS Server Manager), a feature layer and field was selected. The buffer selects features in the feature layer and the results will be summarized using the field. In this case, the feature layer contains polygons defining vegetation regions and the field is the proper name of the vegetation type classification. The QueryPoint method returns a reference to a SpatialQuerySOE.Results object via the SpatialQuerySOE.IResults interface. The following steps in this section cover working with the properties of this results object.

    See the following code example:
[C#]
// Get the Spatial Query SOE.
ESRI.ArcGIS.Carto.IMapServer mapServer = agsMapResourceLocal.MapServer;
ESRI.ArcGIS.Server.IServerObjectExtensionManager serverObjectExtensionManager =
    mapServer as ESRI.ArcGIS.Server.IServerObjectExtensionManager;
ESRI.ArcGIS.Server.IServerObjectExtension serverObjectExtension =
    serverObjectExtensionManager.FindExtensionByTypeName("SpatialQuerySOE");
SpatialQuerySOE.Interfaces.IExtension spatialQuerySOE = serverObjectExtension as
    SpatialQuerySOE.Interfaces.IExtension;

// Execute the SOE's logic.
SpatialQuerySOE.Interfaces.IResults spatialQueryResults = spatialQuerySOE.QueryPoint
    (clickPoint, searchDistance);
[VB.NET]
' Get the Spatial Query SOE.
Dim mapServer As ESRI.ArcGIS.Carto.IMapServer = agsMapResourceLocal.MapServer
Dim serverObjectExtensionManager As ESRI.ArcGIS.Server.IServerObjectExtensionManager = TryCast(mapServer, ESRI.ArcGIS.Server.IServerObjectExtensionManager)
Dim serverObjectExtension As ESRI.ArcGIS.Server.IServerObjectExtension = serverObjectExtensionManager.FindExtensionByTypeName("SpatialQuerySOE_VBNet")
Dim spatialQuerySOE As SpatialQuerySOE.Interfaces_VBNet.IExtension = TryCast(serverObjectExtension, SpatialQuerySOE.Interfaces_VBNet.IExtension)
' Execute the SOE's logic.
Dim spatialQueryResults As SpatialQuerySOE.Interfaces_VBNet.IResults = spatialQuerySOE.QueryPoint(clickPoint, searchDistance)
  1. The SpatialQuerySOE.IResults.ResultsGraphics property references a set of graphic elements via the IGraphicElements interface. To render these graphics in the map requested by the Web ADF and generated by ArcGIS Server, the graphic elements need to be converted from a COM object to a value object. Value objects are used by the ArcGIS Server Simple Object Access Protocol (SOAP) API to store values. The Web ADF uses the ArcGIS Server SOAP API to work with ArcGIS Server data sources, both Internet and Local. When the Web ADF requests a map image from an ArcGIS Server map service, it uses the MapFunctionality's MapDescription value object. By default, changes to the MapDescription are maintained for the duration of the user session. 

    In this section of code, the properties of the graphics representing the summarized features are explicitly defined. The color of the solid outline is dark red. Since you are working with the ArcGIS Server SOAP API, value objects are used to set and store these properties. The symbol for each element in the graphic element array is set, then the graphic element array is associated with the MapDescription via the CustomGraphics property. The next time a map is requested from this map resource, the custom graphics render on the map. See the following code example:
[C#]
// Get the results graphics.
ESRI.ArcGIS.ADF.ArcGISServer.GraphicElement[] resultsGraphics =
    ESRI.ArcGIS.ADF.ArcGISServer.Converter.ComObjectToValueObject
    (spatialQueryResults.ResultsGraphics, serverContext, typeof
    (ESRI.ArcGIS.ADF.ArcGISServer.GraphicElement[]))as
    ESRI.ArcGIS.ADF.ArcGISServer.GraphicElement[];
// Create a symbol for the graphics' outlines.
ESRI.ArcGIS.ADF.ArcGISServer.RgbColor rgbColor = new
    ESRI.ArcGIS.ADF.ArcGISServer.RgbColor();
rgbColor.Red = 155;
rgbColor.Green = 0;
rgbColor.Blue = 0;
rgbColor.AlphaValue = 255;

ESRI.ArcGIS.ADF.ArcGISServer.SimpleLineSymbol simpleLineSymbol = new
    ESRI.ArcGIS.ADF.ArcGISServer.SimpleLineSymbol();
simpleLineSymbol.Style =
    ESRI.ArcGIS.ADF.ArcGISServer.esriSimpleLineStyle.esriSLSSolid;
simpleLineSymbol.Color = rgbColor;
simpleLineSymbol.Width = 0.2;
// Apply the symbol to the graphics.
foreach (ESRI.ArcGIS.ADF.ArcGISServer.PolygonElement polygonElement in
    resultsGraphics)
{
    ESRI.ArcGIS.ADF.ArcGISServer.SimpleFillSymbol simpleFillSymbol =
        polygonElement.Symbol as ESRI.ArcGIS.ADF.ArcGISServer.SimpleFillSymbol;
    simpleFillSymbol.Outline = simpleLineSymbol;
}

// Add the graphics to the map.
agsMapFunctionality.MapDescription.CustomGraphics = resultsGraphics;
[VB.NET]
' Get the results graphics.
Dim resultsGraphics() As ESRI.ArcGIS.ADF.ArcGISServer.GraphicElement = TryCast(ESRI.ArcGIS.ADF.ArcGISServer.Converter.ComObjectToValueObject(spatialQueryResults.ResultsGraphics, serverContext, GetType(ESRI.ArcGIS.ADF.ArcGISServer.GraphicElement())), ESRI.ArcGIS.ADF.ArcGISServer.GraphicElement())
' Create a symbol for the graphics' outlines.
Dim rgbColor As New ESRI.ArcGIS.ADF.ArcGISServer.RgbColor()
rgbColor.Red = 155
rgbColor.Green = 0
rgbColor.Blue = 0
rgbColor.AlphaValue = 255
Dim simpleLineSymbol As New ESRI.ArcGIS.ADF.ArcGISServer.SimpleLineSymbol()
simpleLineSymbol.Style = ESRI.ArcGIS.ADF.ArcGISServer.esriSimpleLineStyle.esriSLSSolid
simpleLineSymbol.Color = rgbColor
simpleLineSymbol.Width = 0.2
' Apply the symbol to the graphics.
For Each polygonElement As ESRI.ArcGIS.ADF.ArcGISServer.PolygonElement In resultsGraphics
    Dim simpleFillSymbol As ESRI.ArcGIS.ADF.ArcGISServer.SimpleFillSymbol = TryCast(polygonElement.Symbol, ESRI.ArcGIS.ADF.ArcGISServer.SimpleFillSymbol)
    simpleFillSymbol.Outline = simpleLineSymbol
Next polygonElement
' Add the graphics to the map.
agsMapFunctionality.MapDescription.CustomGraphics = resultsGraphics
  1. The Web page contains a div element that contains a GridView control that is used to show summarized statistics returned from the SOE. If the GridView is shown, IRecordSet is returned from the SpatialQuerySOE.IResults.SummaryStatistics property. IRecordSet is converted into a ArcGIS Server SOAP API RecordSet that can be converted into an ADO.NET DataTable using the Converter method, ToDataTable. The GridView is rendered as HTML, which is returned to the Web browser and inserted into the div, summaryStatsDiv. Since the Map generates the request when it is clicked with the custom tool, the Map also receives the response (that is, callback results). Create a custom CallbackResult to contain the raw HTML GridView content and append it to the Map's callback results collection. See the following code example:
[C#]
// Get the grid view to show summary stats.
System.Web.UI.WebControls.GridView summaryStatsGridView = adfMap.Page.FindControl(
    "GridView1")as System.Web.UI.WebControls.GridView;

// Update the summary stats grid view if the stats are shown.
if (showSummaryStats)
{
    // Get the summary statistics as a value object record set.
    ESRI.ArcGIS.ADF.ArcGISServer.RecordSet summaryStatsRecordSet =
        ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.Converter.ComObjectToValueObject(spatialQueryResults.SummaryStatistics, serverContext, typeof(ESRI.ArcGIS.ADF.ArcGISServer.RecordSet))as ESRI.ArcGIS.ADF.ArcGISServer.RecordSet;
    // Convert the record set to a DataTable.
    System.Data.DataTable summaryStatsDataTable =
        ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.Converter.ToDataTable
        (summaryStatsRecordSet);
    if (summaryStatsDataTable.Rows.Count > 0)
    {
        // Bind the summary stats to the grid view.
        summaryStatsGridView.DataSource = summaryStatsDataTable;
        summaryStatsGridView.DataBind();
        // Get the grid view's HTML.
        System.IO.StringWriter stringWriter = new System.IO.StringWriter();
        System.Web.UI.HtmlTextWriter htmlTextWriter = new
            System.Web.UI.HtmlTextWriter(stringWriter);
        summaryStatsGridView.RenderControl(htmlTextWriter);
        htmlTextWriter.Flush();
        string gridViewHtml = stringWriter.ToString();
        // Create a callback result that updates the summary stats grid view.
        ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult
            updateStatsTableCallbackResult =
            ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateSetInnerContent(
            "summaryStatsDiv", gridViewHtml);
        adfMap.CallbackResults.Add(updateStatsTableCallbackResult);
    }
    else
    {
        showSummaryStats = false;
    }
}
[VB.NET]
' Get the grid view for displaying summary stats.
Dim summaryStatsGridView As System.Web.UI.WebControls.GridView = TryCast(adfMap.Page.FindControl("GridView1"), System.Web.UI.WebControls.GridView)
' Update the summary stats grid view if the stats are to be shown.
If showSummaryStats Then
    ' Get the summary statistics as a value object record set.
    Dim summaryStatsRecordSet As ESRI.ArcGIS.ADF.ArcGISServer.RecordSet = TryCast(ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.Converter.ComObjectToValueObject(spatialQueryResults.SummaryStatistics, serverContext, GetType(ESRI.ArcGIS.ADF.ArcGISServer.RecordSet)), ESRI.ArcGIS.ADF.ArcGISServer.RecordSet)
    ' Convert the record set to a DataTable.
    Dim summaryStatsDataTable As System.Data.DataTable = ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.Converter.ToDataTable(summaryStatsRecordSet)
    If summaryStatsDataTable.Rows.Count > 0 Then
        ' Bind the summary stats to the grid view.
        summaryStatsGridView.DataSource = summaryStatsDataTable
        summaryStatsGridView.DataBind()
        ' Get the grid view's HTML.
        Dim stringWriter As New System.IO.StringWriter()
        Dim htmlTextWriter As New System.Web.UI.HtmlTextWriter(stringWriter)
        summaryStatsGridView.RenderControl(htmlTextWriter)
        htmlTextWriter.Flush()
        Dim gridViewHtml As String = stringWriter.ToString()
        ' Create a callback result that updates the summary stats grid view.
        Dim updateStatsTableCallbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateSetInnerContent("summaryStatsDiv", gridViewHtml)
        adfMap.CallbackResults.Add(updateStatsTableCallbackResult)
    Else
        showSummaryStats = False
    End If
End If
  1. If the DataTable is not empty, the content of the summaryStatsDiv element needs to be made visible. The following custom CallbackResult includes JavaScript to set the visibility of the div and GridView content in the Web browser. The progress indicator also needs to be hidden; therefore, the JavaScript for that is also included in the following code example:
     
[C#]
// Create a callback result that updates the visibility of the summary stats div and busy 
// indicator via JavaScript.
string statsDivVisibility = showSummaryStats ? "" : "none";
string setElementVisibilityScript = @"var summaryStatsDiv = $get('summaryStatsDiv');
summaryStatsDiv.style.display = '{0}';
var busyIndicator = $get('busyIndicator');
busyIndicator.style.display = 'none';

    ";setElementVisibilityScript = string.Format(setElementVisibilityScript, statsDivVisibility);
ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult
    setStatsDivVisibilityCallbackResult =
    ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript
    (setElementVisibilityScript);
adfMap.CallbackResults.Add(setStatsDivVisibilityCallbackResult);
[VB.NET]
' Create a callback result that will update the visibility of the summary stats div and busy
' indicator via JavaScript.
Dim statsDivVisibility As String = If(showSummaryStats, "", "none")
Dim setElementVisibilityScript As String = "" & ControlChars.CrLf & " var summaryStatsDiv = $get('summaryStatsDiv');" & ControlChars.CrLf & " summaryStatsDiv.style.display = '{0}';" & ControlChars.CrLf & ControlChars.CrLf & " var busyIndicator = $get('busyIndicator');" & ControlChars.CrLf & " busyIndicator.style.display = 'none';"
setElementVisibilityScript = String.Format(setElementVisibilityScript, statsDivVisibility)
Dim setStatsDivVisibilityCallbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(setElementVisibilityScript)
adfMap.CallbackResults.Add(setStatsDivVisibilityCallbackResult)
  1. The final step in the custom tool is to refresh the ArcGIS Server resource that contains the custom graphics previously added. See the following code example:
[C#]
adfMap.RefreshResource(agsMapResourceLocal.Name);
[VB.NET]
adfMap.RefreshResource(agsMapResourceLocal.Name)
  1. Now that the implementation code for the custom tool is finished, add a tool item to the Toolbar control to trigger the action that executes the custom tool. Select the Toolbar control in design view or in the Properties window, then click the ellipsis for the ToolbarItems property. On the ToolbarCollectionEditorForm dialog box, add a new Tool item. In the Toolbar Items section, select the Tool item, then click Add. The new Tool appears under the Current Toolbar Contents section.
  2. Select the new Tool item and click Show Properties. The Properties area for the new Tool appears. See the following screen shot:



    Set the properties shown in the following table:
Property
Value
Description
Text
Vegetation Summary Proximity Search tool
Label for the tool on the toolbar.
ClientAction
Point
Client event passed to the server.
Name
VegetationSummary
Object name of the tool, if used in the code.
ServerActionAssembly
App_Code
Class libraries associated with a Web site are compiled into an assembly named App_Code.
ServerActionClass
VegTool
Name of the custom class that implements IMapServerToolAction and is executed when this tool is used on the map.

Using the Web application at run time

Do the following steps to use the Web application:
  1. Open a Web browser and navigate to the Web application's URL (for example, http://localhost/ArcGIS_Spatial_Query_SOE_CSharp/SpatialQuerySOE_WebSite_CSharp) or open the Web application solution in Visual Studio.
  2. Type a distance in meters to search vegetation regions in the Vegetation layer. The default is 10000.
  3. To show the summary statistics for the selected regions, select the Show Summary Results in a Table check box.
  4. On the toolbar, click the Vegetation Summary Proximity Search tool.
  5. Click the map.
  6. When the application is finished processing, a circular region on the map highlights along the boundary of the features in the Vegetation layer. The summary statistics are rendered in a table below the Toc. See the following screen shot:



See Also:

Sample: ArcGIS Spatial query server object extension
Walkthrough: Creating a server object extension
How to develop the SOE
How to create SOE property pages
How to register the SOE
Sample: Server spatial query COM utility
Developing with ArcGIS Server