Common Geocoding
Common_Geocoding_CSharp\Default.aspx.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.
// 


public partial class Default : System.Web.UI.Page
{
    #region ASP.NET Page Event Handlers

  
    protected void Page_PreRender(object sender, System.EventArgs e)
    {
        if (!IsPostBack)
        {
            ESRI.ArcGIS.ADF.Web.Geometry.Envelope bloomingField = new ESRI.ArcGIS.ADF.Web.Geometry.Envelope(-83.3337801950437, 42.5314716926848, -83.2476061838133, 42.6123242012297);
            Map1.Extent = bloomingField;
        }
        try
        {
            string customScriptKey = "customDataItemScript";
            // Check whether a script block with the name stored in customScriptKey has already
            // been registered on the client, and whether the page is in an asynchronous postback.
            // If neither of these is true, create and register the script block.  Note that replacing
            // ScriptManager1.IsInAsyncPostBack with Page.IsPostback will work initially, but if a
            // full page postback occurs, the script may be lost.
            if (!this.Page.ClientScript.IsClientScriptBlockRegistered(GetType(), customScriptKey) &&
            !ScriptManager1.IsInAsyncPostBack)
            {
                // Construct the JavaScript block that will be responsible for processing data items.
                // 
                // onLoadFunction specifies AsyncResponseHandler as a handler for the pageLoading AJAX
                // client-side event.  This event fires during asynchronous postbacks after the response 
                // has been received from the server, but before any content on the page is updated.  
                // 
                // AsyncResponseHandler retrieves the data items registered server-side during the 
                // asynchronous postback by accessing the dataItems property on the second argument 
                // passed to the handler.  It then gets the particular data item corresponding to the 
                // page by passing the page's client ID to the dataItems array as an array index.  This 
                // data item, assumed to be formatted as a Web ADF callback result, is then passed to 
                // ESRI.ADF.System.processCallbackResult - the client-side Web ADF function responsible 
                // for parsing callback results and updating Web ADF controls accordingly.
                //
                // Below the function declarations, onLoadFunction is added as a handler for the AJAX 
                // client-side event init, which is raised once when the page is first rendered. This 
                // is therefore the appropriate place for onLoadFunction to be called, since the 
                // asynchronous pageLoading handler in this case can remain unchanged for the life
                // of the application.
                //
                // The functions are enclosed in an extra pair of curly braces to allow the subsequent
                // call to String.Format.  String.Format is designed to replace the contents of curly
                // braces with the parameters passed to the function call.  These extra braces "escape" 
                // the braces that must enclose a JavaScript function's logic, essentially telling 
                // String.Format to not replace the contents of these particular braces.
                string scriptBlock = @"
                
                function onLoadFunction(){{
                  Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(AsyncResponseHandler);
                }}

                function AsyncResponseHandler(sender, args) {{
                  var dataItems = args.get_dataItems();
                  if (dataItems['{0}'] != null)
                    ESRI.ADF.System.processCallbackResult(dataItems['{0}']);
                }}

                Sys.Application.add_init(onLoadFunction);";

                // Insert the client ID of the page into the script block.  
                scriptBlock = string.Format(scriptBlock, Page.ClientID);

                // Register the script on the client.  This will make the script block available client-side
                // and execute statements that are not function or object declarations, in this case adding
                // onLoadFunction as a handler for the init event.
                this.Page.ClientScript.RegisterStartupScript(GetType(), customScriptKey, scriptBlock, true);
            }
        }
        catch (System.Exception exception)
        {
            string jsErrorAlert = string.Format("<script>{0}</script>", GetJavaScriptErrorString(exception));
            Response.Write(jsErrorAlert);
        }
    }

    #endregion

    #region ASP.NET Web Control Event Handlers
   
    // Geocodes the input address, adds spatial results to the map, and adds text/tabular results to the page.
    // Called when the user clicks the Geocode button.
    protected void btnGeocode_Click(object sender, System.EventArgs e)
  {
        try
        {
        // Get the resource item for the first item in the GeocodeResourceManager and make sure it's initialized
            ESRI.ArcGIS.ADF.Web.UI.WebControls.GeocodeResourceItem geocodeResourceItem = 
                GeocodeResourceManager1.ResourceItems.Find("Geocode Resource");    
            if (!geocodeResourceItem.Resource.Initialized)      
                geocodeResourceItem.InitializeResource();

            // Create a Web ADF Common API geocode functionality
        ESRI.ArcGIS.ADF.Web.DataSources.IGeocodeFunctionality commonGeocodeFunctionality =
                (ESRI.ArcGIS.ADF.Web.DataSources.IGeocodeFunctionality)
                (geocodeResourceItem.Resource.CreateFunctionality(typeof(
                ESRI.ArcGIS.ADF.Web.DataSources.IGeocodeFunctionality), null));
            
            System.Collections.Generic.List<ESRI.ArcGIS.ADF.Web.Geocode.Field> addressFieldList = 
                commonGeocodeFunctionality.GetAddressFields();

        System.Collections.Generic.List<ESRI.ArcGIS.ADF.Web.Geocode.AddressValue> addressValueList = 
                new System.Collections.Generic.List<ESRI.ArcGIS.ADF.Web.Geocode.AddressValue>();

            // Retrieve the input street from txtAddress and store in an AddressValue object
        ESRI.ArcGIS.ADF.Web.Geocode.AddressValue streetAddressValue = 
                new ESRI.ArcGIS.ADF.Web.Geocode.AddressValue("STREET", txtAddress.Text);
            
            // Retrieve the input zip from txtZipCode and store in an AddressValue object
            ESRI.ArcGIS.ADF.Web.Geocode.AddressValue zoneAddressValue = 
                new ESRI.ArcGIS.ADF.Web.Geocode.AddressValue("Zip", txtZipCode.Text);

            // Add the input street and zip to the list of address values
        addressValueList.Add(streetAddressValue);
        addressValueList.Add(zoneAddressValue);

        // Get graphics layer from Map and clear it of all graphic elements
        ESRI.ArcGIS.ADF.Web.Display.Graphics.ElementGraphicsLayer elementGraphicsLayer = 
                GetGraphicsLayer("Graphics Resource", "Geocode Results");
        elementGraphicsLayer.Clear();

            // Declare a Web ADF Point object to store the result geometry
        ESRI.ArcGIS.ADF.Web.Geometry.Point adfPoint = null;

            // Hide the controls that may display textual/tabular results to false.  If one is used to
            // display results, it will be set to visible when necessary.
        lblResults.Visible = false;
        grdMatchInfo.Visible = false;

        // Check whether all the match candidates are being returned or not
        if (chkAllCandidates.Checked)
        {
          // Get all available match candidates

                // Get the minimum match score from the minimum score drop-down
          commonGeocodeFunctionality.MinCandidateScore = int.Parse(ddlMinScore.SelectedValue);

                // Execute the geocode operation.  Here we call FindAddressCandidates because we wish
                // to find all the match candidates that meet or exceed the minimum score
          System.Data.DataTable matchDataTable = 
                    commonGeocodeFunctionality.FindAddressCandidates(addressValueList, true, true);

                // Find the index of the shape column from the results data table
                int shapeColumnIndex = -1;
                for (int j = 0; j < matchDataTable.Columns.Count; j++)
                {
                    if (matchDataTable.Columns[j].DataType == typeof(ESRI.ArcGIS.ADF.Web.Geometry.Geometry))
                    {
                        shapeColumnIndex = j;
                        break;
                    }
                }

                // Check that results were found
                if (matchDataTable.Rows.Count > 0)
                {
                    // Bind the results to the GridView control
                    grdMatchInfo.DataSource = matchDataTable;
                    grdMatchInfo.DataBind();
                    grdMatchInfo.Visible = true;

                    // Get the geometry column from the results table
                    System.Data.DataColumn shapeColumn = matchDataTable.Columns[shapeColumnIndex];

                    // Add a point on the map for each candidate
                    foreach (System.Data.DataRow dataRow in matchDataTable.Rows)
                    {
                        object adfPointAsObject = dataRow[shapeColumnIndex];
                        if (adfPointAsObject is ESRI.ArcGIS.ADF.Web.Geometry.Point)
                        {
                            adfPoint = (ESRI.ArcGIS.ADF.Web.Geometry.Point)adfPointAsObject;
                            AddPointToMap(adfPoint, elementGraphicsLayer);
                        }
                    }

                    // Update the match count label
                    lblMatchCount.Text = string.Format("Number of Matches: {0}", matchDataTable.Rows.Count);
                }
        }
        else
        {
          // Just get the one best-matching address

                // Get the minimum match score from the minimum score drop-down
                commonGeocodeFunctionality.MinMatchScore = int.Parse(ddlMinScore.SelectedValue);
          
                // Execute the geocode operation.  In this case, we call GeocodeAddress, which returns
                // only the best match as a Web ADF Point
                adfPoint = commonGeocodeFunctionality.GeocodeAddress(addressValueList);

          // If a match was found, put it on the map
                if ((adfPoint != null) && (!adfPoint.X.Equals(double.NaN)))
                {
                    AddPointToMap(adfPoint, elementGraphicsLayer);

                    // Update the results and match count label controls.  Use string.Format with N as the 
                    // format provider to specify that the coordinates be presented in general numeric format.
                    lblResults.Text = string.Format("Address found at {0:N}, {1:N}",
                        adfPoint.X.ToString(), adfPoint.Y.ToString());
                    lblResults.Visible = true;
                    lblMatchCount.Text = "Number of Matches: 1";
                }
        }

            // Check whether the match point is null or is populated with coordinates of NaN
        if ((adfPoint != null) && (!adfPoint.X.Equals(double.NaN)))
        {
          Map1.RefreshResource("Graphics Resource");
                ScriptManager1.RegisterDataItem(Page, Map1.CallbackResults.ToString(), false);
        }
        else
        {
                // No results were found, so inform the user by setting the Label control
                // accordingly
                lblResults.Text = "No matches found";
          lblResults.Visible = true;
        }
        }
        catch (System.Exception exception)
        {
            ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult errorCallbackResult =
                GetErrorCallback(exception);
            Map1.CallbackResults.Add(errorCallbackResult);
            ScriptManager1.RegisterDataItem(Page, Map1.CallbackResults.ToString(), false);
        }
  }

    // Clears spatial geocode results from the map and textual/tabular geocode results from the page.
    // Called when the user clicks the Clear button
    protected void btnClearResults_Click(object sender, System.EventArgs e)
    {
        try
        {
            // Get the graphics layer where spatial geocode results are stored from the Map
            ESRI.ArcGIS.ADF.Web.Display.Graphics.ElementGraphicsLayer elementGraphicsLayer =
                GetGraphicsLayer("Graphics Resource", "Geocode Results");
            // Remove all graphics from the layer
            elementGraphicsLayer.Clear();

            // Hide textual/tabular results elements
            grdMatchInfo.Visible = false;
            lblResults.Visible = false;

            // Update the number of matches label
            lblMatchCount.Text = "Number of Matches:";

            // Refresh the graphics resource
            Map1.RefreshResource("Graphics Resource");

            // Register the Map's callback results as a data item.  This sends the results back
            // to the client, where they can be accessed by handlers of the pageLoading, pageLoaded, or
            // endRequest events on the PageRequestManager object.  More specifically, the callback
            // results will be inserted into the dataItems array, which is passed to the client as a 
            // property of the second argument passed to any of the three aforementioned event 
            // handlers.  The response can be retrieved from the array by specifying the client ID of 
            // the control passed into the RegisterDataItem call (in this case Page) as the array
            // index.  In this case, a pageLoading handler was declared in the script block 
            // registered in the Page's PreRender event, and this handler retrieves the dataItem and 
            // passes it to ESRI.ADF.System.processCallbackResult.
            ScriptManager1.RegisterDataItem(Page, Map1.CallbackResults.ToString(), false);
        }
        catch (System.Exception exception)
        {
            ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult errorCallbackResult =
                GetErrorCallback(exception);
            Map1.CallbackResults.Add(errorCallbackResult);
            ScriptManager1.RegisterDataItem(Page, Map1.CallbackResults.ToString(), false);
        }
    }

    #endregion

    #region Instance Methods

    // Adds the passed-in point to the passed-in graphics layer
  private void AddPointToMap(ESRI.ArcGIS.ADF.Web.Geometry.Point adfPoint, 
        ESRI.ArcGIS.ADF.Web.Display.Graphics.ElementGraphicsLayer elementGraphicsLayer)
  {
        try
        {
            // Create a default symbol for the point
            ESRI.ArcGIS.ADF.Web.Display.Symbol.SimpleMarkerSymbol defaultAdfSimpleMarkerSymbol =
                new ESRI.ArcGIS.ADF.Web.Display.Symbol.SimpleMarkerSymbol();
            defaultAdfSimpleMarkerSymbol.Color = System.Drawing.Color.GreenYellow;
            defaultAdfSimpleMarkerSymbol.Width = 20;
            defaultAdfSimpleMarkerSymbol.Type = ESRI.ArcGIS.ADF.Web.Display.Symbol.MarkerSymbolType.Star;

            // Create a selected symbol for the point
            ESRI.ArcGIS.ADF.Web.Display.Symbol.SimpleMarkerSymbol selectedAdfSimpleMarkerSymbol =
                new ESRI.ArcGIS.ADF.Web.Display.Symbol.SimpleMarkerSymbol();
            selectedAdfSimpleMarkerSymbol.Color = System.Drawing.Color.Yellow;
            selectedAdfSimpleMarkerSymbol.Width = 20;
            selectedAdfSimpleMarkerSymbol.Type = ESRI.ArcGIS.ADF.Web.Display.Symbol.MarkerSymbolType.Star;

            // Create a graphic based on the passed-in point, the default symbol, and the selected symbol
            ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicElement graphicElement =
                new ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicElement(adfPoint,
                defaultAdfSimpleMarkerSymbol, selectedAdfSimpleMarkerSymbol);

            // Add the graphic to the passed-in graphics layer
            elementGraphicsLayer.Add(graphicElement);
        }
        catch (System.Exception exception)
        {
            ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult errorCallbackResult =
                GetErrorCallback(exception);
            Map1.CallbackResults.Add(errorCallbackResult);
        }
  }

    // Retrieves the graphics layer of the passed-in name from the graphics resource of the passed-in name.
    // If the graphics layer does not exist, it is created.
  private ESRI.ArcGIS.ADF.Web.Display.Graphics.ElementGraphicsLayer GetGraphicsLayer(
        string graphicsResourceName, string graphicsLayerName)
    {
        try
        {
            // Retrieve the graphics resource of the passed-in name
            ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapResource graphicsMapResource =
                (ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapResource)
                (MapResourceManager1.GetResource(graphicsResourceName));

            // Attempt to retrieve the graphics layer having the passed-in name from the resource
            ESRI.ArcGIS.ADF.Web.Display.Graphics.ElementGraphicsLayer elementGraphicsLayer = null;
            if (graphicsMapResource.Graphics.Tables.Contains(graphicsLayerName))
                elementGraphicsLayer = graphicsMapResource.Graphics.Tables[graphicsLayerName] as
                    ESRI.ArcGIS.ADF.Web.Display.Graphics.ElementGraphicsLayer;

            // If no graphics layer with the passed-in name was found, create one
            if (elementGraphicsLayer == null)
            {
                elementGraphicsLayer = new ESRI.ArcGIS.ADF.Web.Display.Graphics.ElementGraphicsLayer();
                elementGraphicsLayer.TableName = graphicsLayerName;
                graphicsMapResource.Graphics.Tables.Add(elementGraphicsLayer);
                // Refresh the Toc so the layer is displayed in it
                Toc1.Refresh();
            }

            return elementGraphicsLayer;
        }
        catch (System.Exception exception)
        {
            ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult errorCallbackResult =
                GetErrorCallback(exception);
            Map1.CallbackResults.Add(errorCallbackResult);
            return null;
        }
    }

    // Constructs a callback result that will display an error message based on the passed-in
    // exception
    private ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult GetErrorCallback(
        System.Exception exception)
    {
        // Create a callback result to display an error message
        string jsAlertErrorMessage = GetJavaScriptErrorString(exception);
        ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult alertCallbackResult =
            ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsAlertErrorMessage);
        return alertCallbackResult;
    }

    // Constructs JavaScript necessary to display an error message based on the passed-in exception.
    private string GetJavaScriptErrorString(System.Exception exception)
    {
        // Get the website's configuration file
        System.Configuration.Configuration webConfig =
        System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(
            System.Web.HttpContext.Current.Request.ApplicationPath);

        // Get the "compilation" section of the config file
        System.Web.Configuration.CompilationSection compilationSection =
            webConfig.GetSection("system.web/compilation") as
            System.Web.Configuration.CompilationSection;

        // If the config file's compilation section specifies debug mode, include 
        // stack trace information in the error message.  Otherwise, just return 
        // the exception message.
        string errorMessage = null;
        if ((compilationSection != null) && (compilationSection.Debug))
        {
            string stackTrace = exception.StackTrace.Replace("\\", "\\\\");
            errorMessage = exception.Message + "\\n\\n" + stackTrace.Trim();
        }
        else
            errorMessage = exception.Message;

        // Create a callback result to display an error message
        string jsAlertException = "alert('" + errorMessage + "')";
        return jsAlertException;
    }
    #endregion
}