How to setup, solve, and save a network analysis problem


Summary
There are many ways to modify a network analysis problem to fit a specific application. This topic shows the simplest way to create a problem instance, solve it, and save it to disk using solvers, contexts, and layers.

To automate your workflow, use the ArcGIS Network Analyst extension geoprocessing tools. For this topic, use the Make Route Layer, Add Locations, and Solve tools.

Setting up, solving, and saving a network analysis layer

The following documents a standard workflow:
  1. Set up your network dataset. This code works for a File Geodatabase. You will need to set up your network dataset slightly differently for other types of datasets.  To open other types of network datasets, see How to open a network dataset:
[C#]
var workspaceFactory = Activator.CreateInstance(Type.GetTypeFromProgID(
    "esriDataSourcesGDB.FileGDBWorkspaceFactory"))as IWorkspaceFactory;
var featureWorkspace = workspaceFactory.OpenFromFile(pathToWorkspace, 0)as
    IFeatureWorkspace;
var fdExtensionContainer = featureWorkspace.OpenFeatureDataset(featureDatasetName)as
    IFeatureDatasetExtensionContainer;
var datasetContainer = fdExtensionContainer.FindExtension
    (esriDatasetType.esriDTNetworkDataset)as IDatasetContainer2;
var networkDataset = datasetContainer.get_DatasetByName
    (esriDatasetType.esriDTNetworkDataset, networkDatasetName)as INetworkDataset;
var deNetworkDataset = ((IDatasetComponent)networkDataset).DataElement as
    IDENetworkDataset;
[VB.NET]
Dim workspaceFactory = TryCast(Activator.CreateInstance(Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory")), IWorkspaceFactory)
Dim featureWorkspace = TryCast(workspaceFactory.OpenFromFile(pathToWorkspace, 0), IFeatureWorkspace)
Dim fdExtensionContainer = TryCast(featureWorkspace.OpenFeatureDataset(featureDatasetName), IFeatureDatasetExtensionContainer)
Dim datasetContainer = TryCast(fdExtensionContainer.FindExtension(esriDatasetType.esriDTNetworkDataset), IDatasetContainer2)
Dim networkDataset = TryCast(datasetContainer.get_DatasetByName(esriDatasetType.esriDTNetworkDataset, networkDatasetName), INetworkDataset)
Dim deNetworkDataset = TryCast(DirectCast(networkDataset, IDatasetComponent).DataElement, IDENetworkDataset)
2. Create and prepare your solver.  There are many more settings for solvers than are listed here.  In your own code, this is the place you would tweak the solver to your specification.
[C#]
var routeSolver = new NARouteSolverClass()as INASolver;
INASolverSettings naSolverSettings = routeSolver as INASolverSettings;
naSolverSettings.ImpedanceAttributeName = impedanceAttributeName;
[VB.NET]
Dim routeSolver = TryCast(New NARouteSolverClass(), INASolver)
Dim naSolverSettings As INASolverSettings = TryCast(routeSolver, INASolverSettings)
naSolverSettings.ImpedanceAttributeName = impedanceAttributeName
3. Set up your context by creating it, then binding it to a network dataset.
[C#]
var context = routeSolver.CreateContext(deNetworkDataset, "Name Your Context Here")
    as INAContext;
var contextEdit = context as INAContextEdit;
IGPMessages gpMessages = new GPMessagesClass();
contextEdit.Bind(networkDataset, gpMessages);
[VB.NET]
Dim context = TryCast(routeSolver.CreateContext(deNetworkDataset, "Name Your Context Here"), INAContext)
Dim contextEdit = TryCast(context, INAContextEdit)
Dim gpMessages As IGPMessages = New GPMessagesClass()
contextEdit.Bind(networkDataset, gpMessages)
4. Load your input data.  In this case, we are loading stops using the input feature class and a NAClassLoader. This code assumes that your input stops are from the same workspace.  To find more about how to load input, including single input loading, batch loading, and polygon and polyline loading, see How to load data into a network analysis problem.
[C#]
var inputStopsFClass = featureWorkspace.OpenFeatureClass(inputStopsFeatureClassName);
var cursor = inputStopsFClass.Search(null, false)as ICursor;
var classLoader = new NAClassLoaderClass()as INAClassLoader;
classLoader.NAClass = context.NAClasses.get_ItemByName("Stops")as INAClass;
classLoader.Locator = context.Locator;

// Prevent locations from being placed on restricted elements
ESRI.ArcGIS.NetworkAnalyst.INALocator3 naLocator3 = classLoader.Locator as
    ESRI.ArcGIS.NetworkAnalyst.INALocator3;
naLocator3.ExcludeRestrictedElements = true;
naLocator3.CacheRestrictedElements(context);

int rowsInCursor = 0;
int rowsLocated = 0;
classLoader.Load(cursor, null, ref rowsInCursor, ref rowsLocated);
[VB.NET]
Dim inputStopsFClass = featureWorkspace.OpenFeatureClass(inputStopsFeatureClassName)
Dim cursor = TryCast(inputStopsFClass.Search(Nothing, False), ICursor)
Dim classLoader = TryCast(New NAClassLoaderClass(), INAClassLoader)
classLoader.NAClass = TryCast(context.NAClasses.get_ItemByName("Stops"), INAClass)
classLoader.Locator = context.Locator
' Prevent locations from being placed on restricted elements
Dim naLocator3 As ESRI.ArcGIS.NetworkAnalyst.INALocator3 = TryCast(classLoader.Locator, ESRI.ArcGIS.NetworkAnalyst.INALocator3)
naLocator3.ExcludeRestrictedElements = True
naLocator3.CacheRestrictedElements(context)
Dim rowsInCursor As Integer = 0
Dim rowsLocated As Integer = 0
classLoader.Load(cursor, Nothing, rowsInCursor, rowsLocated)
5. Solve the route. If you are getting an exception during the solve, put a Try-Catch around the Solve call and look at the GPMessages for specific information as to the cause of the failure.  You can also check the GPMessages after a successful solve to see if there are any warning or informational messages.
[C#]
bool partialSolution = routeSolver.Solve(context, gpMessages, null);
[VB.NET]
Dim partialSolution As Boolean = routeSolver.Solve(context, gpMessages, Nothing)
6. If you want to work with the results of the solve, obtain the FeatureClass containing the route results.  Iterate over the route class features' attribute values to examine the results.
[C#]
var routesClass = context.NAClasses.get_ItemByName("Routes")as IFeatureClass;
[VB.NET]
Dim routesClass = TryCast(context.NAClasses.get_ItemByName("Routes"), IFeatureClass)
7. Save your solved route as a layer file.  Be sure that your output file ends with the extension .lyr.
[C#]
try
{
    INALayer3 naLayer = routeSolver.CreateLayer(context)as INALayer3;
    ILayerFile layerfile = new LayerFileClass();
    layerfile.New(outputFile);
    layerfile.ReplaceContents(naLayer as ILayer);
    layerfile.Save();
    layerfile.Close();
}

catch (Exception e)
{
    // Check here if there was an error when saving your layer file.
}
[VB.NET]
Try
Dim naLayer As INALayer3 = TryCast(routeSolver.CreateLayer(context), INALayer3)
Dim layerfile As ILayerFile = New LayerFileClass()
layerfile.[New](outputFile)
layerfile.ReplaceContents(TryCast(naLayer, ILayer))
layerfile.Save()
layerfile.Close()
Catch e As Exception
' Check here if there was an error when saving your layer file.
End Try
The following method is composed of the previous code fragments:
[C#]
public void SimpleRouteSetupSolveAndSaveWorkflow(string pathToWorkspace, string
    featureDatasetName, string networkDatasetName, string inputStopsFeatureClassName,
    string impedanceAttributeName, string outputFile)
{
    // Set up your network dataset.
    // This works for a FileGDB. You will need to set up your network dataset slightly differently for other types of datasets.
    // There is a document about how to open network datasets. Find that for how to open other types.
    var workspaceFactory = Activator.CreateInstance(Type.GetTypeFromProgID(
        "esriDataSourcesGDB.FileGDBWorkspaceFactory"))as IWorkspaceFactory;
    var featureWorkspace = workspaceFactory.OpenFromFile(pathToWorkspace, 0)as
        IFeatureWorkspace;
    var fdExtensionContainer = featureWorkspace.OpenFeatureDataset
        (featureDatasetName)as IFeatureDatasetExtensionContainer;
    var datasetContainer = fdExtensionContainer.FindExtension
        (esriDatasetType.esriDTNetworkDataset)as IDatasetContainer2;
    var networkDataset = datasetContainer.get_DatasetByName
        (esriDatasetType.esriDTNetworkDataset, networkDatasetName)as INetworkDataset;
    var deNetworkDataset = ((IDatasetComponent)networkDataset).DataElement as
        IDENetworkDataset;

    // Set up your solver.
    var routeSolver = new NARouteSolverClass()as INASolver;
    INASolverSettings naSolverSettings = routeSolver as INASolverSettings;
    naSolverSettings.ImpedanceAttributeName = impedanceAttributeName;

    // Set up your context by creating it, then binding it to a network dataset.
    var context = routeSolver.CreateContext(deNetworkDataset, 
        "Name Your Context Here")as INAContext;
    var contextEdit = context as INAContextEdit;
    IGPMessages gpMessages = new GPMessagesClass();
    contextEdit.Bind(networkDataset, gpMessages);

    // Load new stops using the input feature class and a NAClassLoader.
    // This assumes that your input stops are from the same workspace.
    // There is also a document showing how to accomplish different kinds of loading in the SDK.
    // Check that document for information on single input and batch loading, load settings, and polygon and polyline loading.
    var inputStopsFClass = featureWorkspace.OpenFeatureClass
        (inputStopsFeatureClassName);
    var cursor = inputStopsFClass.Search(null, false)as ICursor;
    var classLoader = new NAClassLoaderClass()as INAClassLoader;
    classLoader.NAClass = context.NAClasses.get_ItemByName("Stops")as INAClass;
    classLoader.Locator = context.Locator;
    int rowsInCursor = 0;
    int rowsLocated = 0;
    classLoader.Load(cursor, null, ref rowsInCursor, ref rowsLocated);

    // Solve the route using current settings.
    // If you are getting an exception, put a Try-Catch around the Solve call and look at the 
    // GPMessages for specific information as to the cause of the failure.
    // You can also check the GPMessages after a successful solve to see if there are any warning or informational messages.
    bool partialSolution = routeSolver.Solve(context, gpMessages, null);

    // Get the FeatureClass containing the route results.
    // Iterate over the route class features' attribute values to examine the results.
    var routesClass = context.NAClasses.get_ItemByName("Routes")as IFeatureClass;

    // Save your solved route as a layer file.
    // Be sure that your output file ends with the extension .lyr.
    try
    {
        INALayer3 naLayer = routeSolver.CreateLayer(context)as INALayer3;
        ILayerFile layerfile = new LayerFileClass();
        layerfile.New(outputFile);
        layerfile.ReplaceContents(naLayer as ILayer);
        layerfile.Save();
        layerfile.Close();
    }
    catch (Exception e)
    {
        // Check here if there was an error when saving your layer file.
    }
}
[VB.NET]
Public Sub SimpleRouteSetupSolveAndSaveWorkflow(ByVal pathToWorkspace As String, ByVal featureDatasetName As String, ByVal networkDatasetName As String, ByVal inputStopsFeatureClassName As String, ByVal impedanceAttributeName As String, ByVal outputFile As String)
    ' Set up your network dataset.
    ' This works for a FileGDB. You will need to set up your network dataset slightly differently for other types of datasets.
    ' There is a document about how to open network datasets. Find that for how to open other types.
    Dim workspaceFactory = TryCast(Activator.CreateInstance(Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory")), IWorkspaceFactory)
    Dim featureWorkspace = TryCast(workspaceFactory.OpenFromFile(pathToWorkspace, 0), IFeatureWorkspace)
    Dim fdExtensionContainer = TryCast(featureWorkspace.OpenFeatureDataset(featureDatasetName), IFeatureDatasetExtensionContainer)
    Dim datasetContainer = TryCast(fdExtensionContainer.FindExtension(esriDatasetType.esriDTNetworkDataset), IDatasetContainer2)
    Dim networkDataset = TryCast(datasetContainer.get_DatasetByName(esriDatasetType.esriDTNetworkDataset, networkDatasetName), INetworkDataset)
    Dim deNetworkDataset = TryCast(DirectCast(networkDataset, IDatasetComponent).DataElement, IDENetworkDataset)
    
    ' Set up your solver.
    Dim routeSolver = TryCast(New NARouteSolverClass(), INASolver)
    Dim naSolverSettings As INASolverSettings = TryCast(routeSolver, INASolverSettings)
    naSolverSettings.ImpedanceAttributeName = impedanceAttributeName
    
    ' Set up your context by creating it, then binding it to a network dataset.
    Dim context = TryCast(routeSolver.CreateContext(deNetworkDataset, "Name Your Context Here"), INAContext)
    Dim contextEdit = TryCast(context, INAContextEdit)
    Dim gpMessages As IGPMessages = New GPMessagesClass()
    contextEdit.Bind(networkDataset, gpMessages)
    
    ' Load new stops using the input feature class and a NAClassLoader.
    ' This assumes that your input stops are from the same workspace.
    ' There is also a document showing how to accomplish different kinds of loading in the SDK.
    ' Check that document for information on single input and batch loading, load settings, and polygon and polyline loading.
    Dim inputStopsFClass = featureWorkspace.OpenFeatureClass(inputStopsFeatureClassName)
    Dim cursor = TryCast(inputStopsFClass.Search(Nothing, False), ICursor)
    Dim classLoader = TryCast(New NAClassLoaderClass(), INAClassLoader)
    classLoader.NAClass = TryCast(context.NAClasses.get_ItemByName("Stops"), INAClass)
    classLoader.Locator = context.Locator
    Dim rowsInCursor As Integer = 0
    Dim rowsLocated As Integer = 0
    classLoader.Load(cursor, Nothing, rowsInCursor, rowsLocated)
    
    ' Solve the route using current settings.
    ' If you are getting an exception, put a Try-Catch around the Solve call and look at the
    ' GPMessages for specific information as to the cause of the failure.
    ' You can also check the GPMessages after a successful solve to see if there are any warning or informational messages.
    Dim partialSolution As Boolean = routeSolver.Solve(context, gpMessages, Nothing)
    
    ' Get the FeatureClass containing the route results.
    ' Iterate over the route class features' attribute values to examine the results.
    Dim routesClass = TryCast(context.NAClasses.get_ItemByName("Routes"), IFeatureClass)
    
    ' Save your solved route as a layer file.
    ' Be sure that your output file ends with the extension .lyr.
    Try
    Dim naLayer As INALayer3 = TryCast(routeSolver.CreateLayer(context), INALayer3)
    Dim layerfile As ILayerFile = New LayerFileClass()
    layerfile.[New](outputFile)
    layerfile.ReplaceContents(TryCast(naLayer, ILayer))
    layerfile.Save()
    layerfile.Close()
    Catch e As Exception
    ' Check here if there was an error when saving your layer file.
    End Try
End Sub


See Also:

Sample: Vehicle routing problem solver
Sample: Origin-destination cost matrix solver
Sample: Location-allocation solver
Sample: Service area solver
Sample: Route layer
Sample: Closest facility solver
How to open a network dataset
How to load data into a network analysis problem
What is ArcGIS Network Analyst extension?
About the ArcGIS Network Analyst extension Tutorial
Essential ArcGIS Network Analyst extension vocabulary
NetworkAnalyst
ArcGIS Network Analyst extension Object Model Diagram




To use the code in this topic, reference the following assemblies in your Visual Studio project. In the code files, you will need using (C#) or Imports (VB .NET) directives for the corresponding namespaces (given in parenthesis below if different from the assembly name):
Development licensing Deployment licensing
Engine Developer Kit Engine: Network Analyst
ArcGIS for Desktop Advanced ArcGIS for Desktop Advanced: Network Analyst
ArcGIS for Desktop Standard ArcGIS for Desktop Standard: Network Analyst
ArcGIS for Desktop Basic ArcGIS for Desktop Basic: Network Analyst