AccessViolationException in ArcGIS.Core.Internal.IUtilityNetworkTracerIOP.UtilityNetworkTracer_Trace

603
5
05-03-2022 07:23 AM
JimGrinwald
New Contributor II

Working on a standalone ArcGIS Core Host application that is going to do downstream tracing from Transformers to Service Points on the utility network.  Admittedly, it's my first, and I am following pro snippet and concept documentation, and looking at the trace utility in ArcGIS Pro for a single transformer to see if I can at least get trace results in my standalone application.

Unfortunately, as soon as I hit the Trace(traceargument) call, I get  a System.AccessViolationException.  Any ideas would be greatly appreciated.

0 Kudos
5 Replies
Aashis
by Esri Contributor
Esri Contributor

Hi @JimGrinwald, it is hard to tell without knowing how you are constructing the trace argument object and what dataset type you are using. Could you please elaborate and provide your code snippet, if possible? 

0 Kudos
JimGrinwald
New Contributor II

Hi @Aashis. Below is a snippit of the code contained within a method inside my tracing class, where the List<Feature> associatedFeatures is passed in.  Also a private method in the class to set up TraceConfiguration.

foreach (Feature associated in associatedFeatures)
{
   using (TraceManager traceManager = _utilityNetwork.GetTraceManager())
   {
      List<Element> startingPointList = new List<Element>();
      var element = _utilityNetwork.CreateElement((Row)associated);
      element.Terminal = element.AssetType.GetTerminalConfiguration()
         .Terminals.FirstOrDefault(x => x.IsUpstreamTerminal == false);
      startingPointList.Add(element);
      TraceArgument traceArgument = new TraceArgument(startingPointList);

      _traceConfiguration = _traceConfiguration ?? BuildTraceConfiguration();
      traceArgument.Configuration = _traceConfiguration;

      var downstreamTracer = traceManager.GetTracer<DownstreamTracer>();
      var traceResult = downstreamTracer.Trace(traceArgument);
      Log.Info($"Feature OID {feature.ObjectId} produced " + 
               $"{traceResult.Count} results.");
	}
}

private TraceConfiguration BuildTraceConfiguration()
{
   var domainNetwork = _utilityNetwork.GetDefinition()
      .GetDomainNetwork(NetworkDomain.Electric.Description());
   var tier = domainNetwork.Tiers
      .FirstOrDefault(x => x.TopologyType == TierTopologyType.Radial);
   var traceConfiguration =  new TraceConfiguration
   {
      AllowIndeterminateFlow = true,
      DomainNetwork = domainNetwork,
      SourceTier = tier,
      IncludeStructures = true,
      IncludeContent = true,
   };
   return traceConfiguration;
}

 The trace class is instantiated passing in the FeatureClass from which the associatedFeatures are queried.  Said FeatureClass is used to retrieve UtilityNetwork _utilityNetwork as a private field for the class.

 

Again, this is admittedly my first run at coding network tracing inside a standalone ArcGIS Core Host application, so there my be some things I am not doing correctly.

0 Kudos
Aashis
by Esri Contributor
Esri Contributor

@JimGrinwald, I apologize for the delay. There are a couple of thoughts on the above snippet, but it is hard to pinpoint without looking at the data model.

1. The process of getting a trace manager and building a trace argument/configuration doesn't need to be in a loop (it should work fine but inefficient)

2. If associated is an edge feature, I'm not sure what line 7 is going to do

3. you probably should use var traceConfiguration =  Tier.TraceConfiguration rather than creating a new trace configuration (2.9 and older)

4. I also recommend adding using statements to dispose objects properly ( should not be causing the crash though)

Here is a sample trace snippet based on the community UN data:

 

      // Guid of a known medium voltagee Transformer to begin a trace
      Guid startingPointGuid = Guid.Parse("{5D6574D1-340A-43A8-8BEE-7A87914CE477}");

      // Opens a file geodatabase that can be downloaded from community sample data
      using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"C:\Data\UtilityNetwork\NapervilleElectricSDKData.gdb"))))
      {
        IReadOnlyList<UtilityNetworkDefinition> utilityNetworkDefinitions = geodatabase.GetDefinitions<UtilityNetworkDefinition>();
        
        string unName = string.Empty;
        
        if(utilityNetworkDefinitions.Count < 0 )
        {
          return;
        }

        // Get utility network from the dataset
        foreach (var definition in utilityNetworkDefinitions)
        {
          unName = definition.GetName();

          Console.WriteLine(definition.GetName() + "=>" + definition.DatasetType);
          definition.Dispose();
        }

        // Open utility network
        using (UtilityNetwork utilityNetwork = geodatabase.OpenDataset<UtilityNetwork>(unName))
        using (UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition())
        {
          using (NetworkSource networkSource = utilityNetworkDefinition.GetNetworkSource("ElectricDevice"))
          using (AssetGroup assetGroup = networkSource.GetAssetGroup("Medium Voltage Transformer"))
          using(AssetType assetType = assetGroup.GetAssetType("Overhead Single Phase"))
          {
            Terminal terminal = null;
            if (assetType.IsTerminalConfigurationSupported())
            {
              TerminalConfiguration terminalConfiguration = assetType.GetTerminalConfiguration();
              IReadOnlyList<Terminal> terminals = terminalConfiguration.Terminals;
              terminal = terminals.First(t => !t.IsUpstreamTerminal);
            }

            DomainNetwork domainNetwork = utilityNetworkDefinition.GetDomainNetwork("Electric");
            Tier sourceTier = domainNetwork.GetTier("Electric Distribution");
            // TraceConfiguration traceConfiguration  = sourceTier.GetTraceConfiguration(); // For 3.0 pre release
             TraceConfiguration traceConfiguration  = sourceTier.TraceConfiguration; // For 2.9

            // Create an element to begin a trace
            Element startingPointElement = utilityNetwork.CreateElement(assetType, startingPointGuid, terminal);

            List<Element> startingPoints = new List<Element>();
            startingPoints.Add(startingPointElement);

            List<Element> barriers = new List<Element>();

            using (TraceManager traceManager = utilityNetwork.GetTraceManager())
            {
              TraceArgument traceArgument = new TraceArgument(startingPoints);
              traceArgument.Configuration = traceConfiguration;

              // Trace downstream
              Tracer tracer = traceManager.GetTracer<DownstreamTracer>();
              IReadOnlyList<Result> traceResults = tracer.Trace(traceArgument);
              // Prints the results of trace in console
              foreach (Result result in traceResults)
              {
                if (result is ElementResult)
                {
                  ElementResult elementResult = result as ElementResult;
                  IReadOnlyList<Element> elements = elementResult.Elements;
                  
                  Console.WriteLine("Trace Elements");
                  foreach (Element element in elements)
                  {
                    Console.WriteLine($"{element.ObjectID}-{element.AssetType}");
                  }
                }
                else if (result is FunctionOutputResult)
                {
                  FunctionOutputResult functionResult = result as FunctionOutputResult;
                  IReadOnlyList<FunctionOutput> functionOutputs = functionResult.FunctionOutputs;
                  
                  foreach (var functionOut in functionOutputs)
                  {
                    Console.WriteLine($"{functionOut.Value}-{functionOut.Function}");
                  }
                }
                else if (result is AggregatedGeometryResult)
                {
                  AggregatedGeometryResult aggResults = result as AggregatedGeometryResult;
                  Polyline aggregatedLine = aggResults.Line as Polyline;
                  Multipoint aggregatedPoint = aggResults.Point as Multipoint;
                  Polygon aggregatedPolygon = aggResults.Polygon as Polygon;
                }
              }
            }
          }
        }
      }

 

 

0 Kudos
JimGrinwald
New Contributor II

Hi @Aashis , thank you for getting back to me.  Interesting that you brought up the community example.  I took said example, and refactored the tracing logic out to a separate class and assembly for a proof of concept, such that the trace button click could instantiate that class in a QueuedTask.Run and pass simple information in, and get the same results out.  I verified that the Pro Add-In still worked, then created a separate Core host project to make the same instatntiation, and pass the same simple information in and get the same results out, and everything worked.

 

Then I used the same pattern to create a new trace class based on the tracing logic I needed for a simple downstream trace, except

  • using an SDE connection instead of a local file GDB, and
  • to get my starting point not from the UN_Temp_Starting_Points table, but from a named feature class and object Id, retrieving the information needed from said feature and feature class to create the starting point element.

Having done that, I tested the new tracer from a Pro AddIn button, and the Trace() call worked.  Then I tested the new tracer from the CoreHost console application, and I ran into the same exception that this post originated with.  I can tell you that  Resharper does allow me to drill down to the exact point (ArcGIS.Core.Internal.IUtilityNetworkTracerIOP.UtilityNetworkTracer_Trace) where the System.AccessViolationException exception gets thrown.  I get the impression that there is a COM Interop issue going on with this particular configuration. when trying to run as a standalone CoreHost console application, vs as a Pro AddIn.

0 Kudos
Aashis
by Esri Contributor
Esri Contributor

What version of Pro and database are you using, @JimGrinwald ?

0 Kudos