Network Analyst routing
ArcGIS_Routing_CSharp\Directions.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.
// 



using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Xml;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Location;
using ESRI.ArcGIS.Server;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.NetworkAnalyst;
using ESRI.ArcGIS.Server.Web.NetworkAnalyst;
using System.Collections.Specialized;
using ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer;

namespace RouteFinder
{
  /// <summary>
  /// Summary description for Directions.
  /// </summary>
  public partial class Directions : System.Web.UI.Page, RouteFinder.IBaseRouteFinderPage
  {
        ServerObjectStateModifier serverObjectStateModifier = null;

        public void Page_PreInit(object sender, EventArgs e)
        {
            serverObjectStateModifier = new ServerObjectStateModifier();
        }

        protected void Page_Init(object sender, EventArgs e)
        {
            Map1.Load += new EventHandler(Map1_Load);

        }

        void Map1_Load(object sender, EventArgs e)
        {
            if (Page.IsPostBack)
            {
                if (!MapResourceManager1.Initialized)
                    MapResourceManager1.Initialize();
            }                
        }

    protected void Page_PreRender(object sender, System.EventArgs e)
    {
      if (!Page.IsPostBack)
      {
        #region Get XY and Address parameters

        string fromAddress = Convert.ToString(Session["FromAddress"]);
        string toAddress = Convert.ToString(Session["ToAddress"]);
        double fromX = Convert.ToDouble(Page.Request.Params["FromX"]);
        double fromY = Convert.ToDouble(Page.Request.Params["FromY"]);
        double toX = Convert.ToDouble(Page.Request.Params["ToX"]);
        double toY = Convert.ToDouble(Page.Request.Params["ToY"]);
        #endregion

        #region Get Route between Addresses

        if (fromX == 0.0 && toX == 0.0)
          return;

        NetworkAnalystRouteResult result = SolveRoute(fromX, fromY, toX, toY, fromAddress, toAddress);
        DisplayDirections(result, fromAddress, toAddress);
        #endregion
      }
    }

    /// <summary>
    /// Solves route between two geocoded locations
    /// </summary>
    public NetworkAnalystRouteResult SolveRoute(double fromX, double fromY, double toX, double toY, string fromAddress, string toAddress)
    {      

      #region Get a reference to the Map
            if (!MapResourceManager1.Initialized)
                MapResourceManager1.Initialize();

      MapResourceLocal mapResourceLocal = (MapResourceLocal)MapResourceManager1.GetResource(0);
      IServerContext serverContext = mapResourceLocal.ServerContextInfo.ServerContext;
      IMapServerObjects mapServerObjects = (IMapServerObjects)mapResourceLocal.MapServer;
      IMap map = mapServerObjects.get_Map(mapResourceLocal.DataFrame);
      #endregion


      #region Get first Route Layer

      INALayer2 naLayer = null;
      int layerID = -1;

            UID uidINALayer = (UID) serverContext.CreateObject("esriSystem.UID");
      uidINALayer.Value = "{667B776B-5905-4450-9C94-18B214ECE8FB}";
      IEnumLayer elayers = map.get_Layers(uidINALayer, true);
      ILayer layer = elayers.Next();
      int i = 0;
      while (layer != null)
      {
                if ((layer is INALayer) && (layer.Name == "Route"))
        {
          naLayer = layer as INALayer2;
          layerID = i;
          break;
        }
        ++i;
        layer = elayers.Next();
      }

      if (layerID == -1)
        throw new Exception("No Route layers in map");

      Session["RouteLayerID"] = layerID;
      #endregion


      #region Get a copy of the original NAContext to restore at the end of the request

      // Only save the original context once
      string originalContextSerialized = Session["OriginalNAContext"] as string;
      if (originalContextSerialized == null)
      {
        INAContext originalNAContext = naLayer.CopyContext();
        originalContextSerialized = serverContext.SaveObject(originalNAContext);
        Session["OriginalNAContext"] = originalContextSerialized;
      }

      INAContext naContext = naLayer.Context;
      #endregion


      #region Add From and To Points

      //delete any old stops
      INAClass naClass = naContext.NAClasses.get_ItemByName("Stops") as INAClass;
      naClass.DeleteAllRows();

      //add from point
      IPoint point = serverContext.CreateObject("esriGeometry.Point") as IPoint;

      point.PutCoords(fromX, fromY);

      NetworkAnalystUtility.AddLocation(naContext, "Stops", point, fromAddress, 100);
      //add to point
      point.PutCoords(toX, toY);
      NetworkAnalystUtility.AddLocation(naContext, "Stops", point, toAddress, 100);

            // Message all of the network analysis agents that the analysis context has changed
            ((INAContextEdit)naContext).ContextChanged();
      #endregion


      #region Solve and Display Route

      // Solve the route and generated the resulting directions
      IGPMessages gpMessages = serverContext.CreateObject("esriGeodatabase.GPMessages") as IGPMessages;
      INASolver solver = naContext.Solver;
      solver.Solve(naContext, gpMessages, null);

      NetworkAnalystRouteResult result = NetworkAnalystUtility.GetDirections(naContext, "Routes", serverContext);

      //Draw the map centered on route
      Map1.Extent = result.RouteExtent;

      #endregion


      #region Store Extents in Session for Use in Zooming to Full Extent or to Each Step

      Session["PathExtent"] = result.RouteExtent;
      Session["DirectionExtents"] = result.StepExtents;
      #endregion


      #region Store coords for ReverseDirections

      Session["FromX"] = fromX;
      Session["FromY"] = fromY;
      Session["ToX"] = toX;
      Session["ToY"] = toY;
      Session["FromAddress"] = fromAddress;
      Session["ToAddress"] = toAddress;
      #endregion

      Session["ModifiedNAContextApplied"] = true;

      return result;
    }
    /// <summary>
    /// Populates datagrid with directions and javascript array with summary
    /// </summary>
    public void DisplayDirections(NetworkAnalystRouteResult result, string fromAdd, string toAdd)
    {
      #region Write Summary

      System.Text.StringBuilder sb = new System.Text.StringBuilder();
      sb.Append("<b>Starting from:</b> " + fromAdd + "<br>");
      sb.Append("<b>Arriving at:</b> " + toAdd + "<br>");
      sb.Append("<b>Distance: </b> " + result.Summary["Length"] + "<br>");
      sb.Append("<b>Time: </b> " + result.Summary["Time"] + "<br>");
      DirectionsSummary.InnerHtml = sb.ToString();
      Session["Summary"] = DirectionsSummary.InnerHtml;

      #endregion

      #region Populate data grid

      DataGrid1.DataSource = null;

      //Get data table and remove unnecessary columns
      DataTable dataTable = result.Directions;
      dataTable.Columns.Remove("Summary");  //this column displays the same information found in the columns that follow it
      dataTable.Columns.Remove("Type");
      #region Create Links in Table for Zooming In to Each Step
      #region Merge 1st and 2nd rows
      dataTable.Rows[1]["Directions"] = String.Format("{0}. {1}", dataTable.Rows[0]["Directions"], dataTable.Rows[1]["Directions"]);
      dataTable.Rows[dataTable.Rows.Count - 2]["Directions"] = String.Format("{0}. {1}", dataTable.Rows[dataTable.Rows.Count - 2]["Directions"], dataTable.Rows[dataTable.Rows.Count - 1]["Directions"]);
      dataTable.Rows.RemoveAt(dataTable.Rows.Count - 1);
      dataTable.Rows.RemoveAt(0);
      #endregion

      #region Create Links
      DataRow dataRow;
      for (int i = 0; i < dataTable.Rows.Count; i++)
      {
        dataRow = dataTable.Rows[i];
        string step = Convert.ToString((i + 1)); //add 1 because 1st row was merged into the second
        //Link Directions
        dataRow["Directions"] = "<a href=\"javascript:ZoomTo(" + step + ")\">" + dataRow["Directions"] + "</a>";
        //Link Step
        dataRow["Step"] = "<b><a href=\"javascript:ZoomTo(" + step + ")\">" + step + "</a></b>";
      }
      #endregion

      // bind new datatable to datagrid
      DataGrid1.DataSource = dataTable;
      DataGrid1.DataBind();
      #endregion
      // save to session for print page
      Session["Directions_DataTable"] = dataTable;

      return;

      #endregion
    }

    protected void MapResourceManager1_ResourcesDispose(object sender, EventArgs e)
    {
      if ((bool)Session["ModifiedNAContextApplied"])
      {               
               ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem mapresourceitem = MapResourceManager1.ResourceItems.Find("MapResourceItem0");
               if (mapresourceitem != null)
               {
                   serverObjectStateModifier.ApplyOriginalNAContext(mapresourceitem);
                   Session["ModifiedNAContextApplied"] = false;
               }
      }
    }

        protected void MapResourceManager1_ResourceInit(object sender, EventArgs e)
        {
            ESRI.ArcGIS.ADF.Web.UI.WebControls.ResourceInitEventArgs riea = e as ESRI.ArcGIS.ADF.Web.UI.WebControls.ResourceInitEventArgs;

            if (riea.GISResourceItem.Name == "MapResourceItem0")
                CustomResourceInit(riea.GISResourceItem);
        }

        protected void CustomResourceInit(ESRI.ArcGIS.ADF.Web.UI.WebControls.GISResourceItem resource)
        {
            object modifiedNAContextApplied = System.Web.HttpContext.Current.Session["ModifiedNAContextApplied"];
            if (modifiedNAContextApplied == null || !(bool)modifiedNAContextApplied)
            {
                serverObjectStateModifier.ApplySessionNAContext(resource);                
                System.Web.HttpContext.Current.Session["ModifiedNAContextApplied"] = true;
            }
        }


    #region Error Functions
    protected void Directions_Error(object sender, EventArgs e)
    {
      Exception exception = Server.GetLastError();
      Server.ClearError();
      callErrorPage("Page_Error", exception);
    }

    /// <summary>
    /// Displays the error page.
    /// </summary>
    private void callErrorPage(string errorMessage, Exception exception)
    {
      Session["ErrorMessage"] = errorMessage;
      Session["Error"] = exception;
      Page.Response.Redirect("ErrorPage.aspx", true);
    }
    #endregion


}
}