Get all child nodes of an Enterprise Architect package node

1

What I need

Step 1

I need to do an export of all information, whatever the node type, under a main root node (= package).

Step 2

Using that export information I need to do a mapping to a JSON contract provided by a third party.

Step 3

The third party can then use my JSON to import the information from EA into their system.

What I have

Step 1 is completed, I have a file based data dump on my target location like this:

enter image description here

Basically that's a static html website which corresponds to the EA structure by displaying the information in a tree-view, similar to how you see it in EA.

What I can do

Is go through the EARoot folder and read all information provided in the html files that are in there.

In my case EARoot contains three subfolders:

  • EA1
  • EA2
  • EA3

Where the EA1 subfolders contains

  • EA1
  • EA2
  • EA1.html
  • EA2.html
  • EA3.html

The html files contain the information I need, it's doable to interpret the data in a meaningful fashion.

The catch

Is that there's no immediate link to the files and the actual node structure in EA. I can make an assumption based on the available data, that will work -most- of the time, but it needs to be reliable and work -all- the time.

I can find a correct UUID in each html file, so that would be a way to link to the structure, but to find this structure, I need to be able to get the UUIDS of all children of a node and go through the tree recursively.

I tried the following:

public Package GetRootPackage()
{
    using (var repo = EnterpriseArchitect.Repository.Open(_connectionString))
    {
        return repo.GetPackage(this.RootPackageName);
    }
}

EnterpriseArchitect.Repository is a wrapper on top of EA.Repository to have it be IDisposable for better connection management.

Using the GetRootPackage method defined above, I can connect and load the node I want:

var root = MyBuilder.ConnectTo(myConnectionString)
    .RootPackage(rootNodeName)
    .GetRootPackage();

I'd think that I'd then be able to fetch it's children like so:

var children = root.Packages;

But then I get this nasty error:

System.Runtime.InteropServices.COMException HResult=0x80010105
Message=The server threw an exception. (Exception from HRESULT: 0x80010105 (RPC_E_SERVERFAULT)) Source=my.console
StackTrace: at EA.IDualPackage.get_Elements() at my.console.Program.Main(String[] args) in C:\Repos\my.console\Program.cs:line 29

I checked eventviewer for more information and found (only) this:

Faulting application name: EA.exe, version: 14.1.0.1427, time stamp: 0x5b9718a5
Faulting module name: EA.exe, version: 14.1.0.1427, time stamp: 0x5b9718a5
Exception code: 0xc0000005
Fault offset: 0x0049ffc4
Faulting process id: 0x2eac
Faulting application start time: 0x01d56eb6d931a965
Faulting application path: C:\Program Files (x86)\Sparx Systems\EA\EA.exe
Faulting module path: C:\Program Files (x86)\Sparx Systems\EA\EA.exe
Report Id: 223f8c89-c84a-45c6-9100-82af8e94643a
Faulting package full name: 
Faulting package-relative application ID: 

The question

What I find regarding this HResult=0x80010105seems to be Excel related, so I'm not sure if that's meaningful.

I'm running from a console, because I understood that interop.EA should be considered to be not-threadsafe.

What can I do to avoid this issue and get the child packages?

c#
console-application
com-interop
enterprise-architect
asked on Stack Overflow Sep 19, 2019 by Spikee • edited Sep 19, 2019 by Spikee

1 Answer

1

It's the IDisposable wrapper on top of EA.Repository that's causing the issue. If I call the repo directly (using try catch finally instead of IDisposable) I am able to get the child nodes.

So much for defensive programming ...


Instead of the wrapper I had:

public class Repository : IDisposable
{
    private EA.Repository _repo;

    protected Repository(string connectionString)
    {
        _repo = new EA.Repository();
        _repo.OpenFile(connectionString);
    }

    ...

    public void Dispose()
    {
        _repo.CloseFile();
        _repo = null;
    }
}

I'm now using the EA repo directly to get (root) package information:

public Package GetRootPackage()
{
    var repo = new EA.Repository();

    try
    {    
        repo.OpenFile(_connectionString);

        var pkg = (EA.Package)repo.Models.GetByName(this.RootPackageName);

        if (pkg is null)
            throw new ApplicationException($"Package \"{this.RootPackageName}\" not found.");

        return pkg;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
        throw;
    }
    finally
    {
        Console.WriteLine("Closing repository...");
        repo.CloseFile();
    }
}

Through this I can do:

var root = MyBuilder.ConnectTo(myConnectionString)
    .RootPackage(rootNodeName)
    .GetRootPackage();

foreach (var item in root.Packages)
{
    var child = (IDualPackage)item;    
    var guid = child.PackageGUID;
}

And the guid var contains the correct PackageGUID.

answered on Stack Overflow Oct 1, 2019 by Spikee • edited Oct 1, 2019 by Spikee

User contributions licensed under CC BY-SA 3.0