Book a Demo

Author Topic: Exception after iteration over attributes  (Read 6950 times)

TheTwo

  • EA User
  • **
  • Posts: 39
  • Karma: +0/-0
    • View Profile
Exception after iteration over attributes
« on: July 03, 2009, 09:41:24 pm »
Hi,

I've a problem with an self implemented rule check.

1. It is started by the EA_OnStartValidation. There I do nothing.
2. EA_OnRunElementRule is called.
3. then I take the EA.Element and call
     if (Element.Attributes.Count == 0)
                return true;


At the end EA_OnEndValidation(EA.Repository Repository, Object Args) is called from EA.
There I call
GC.Collect();
GC.WaitForPendingFinalizers();


When this method is finished, then an TargetInvocationExeption occures in my Addin.

What could be the reason?

Thanks
TheTwo

«Midnight»

  • EA Guru
  • *****
  • Posts: 5651
  • Karma: +0/-0
  • That nice Mister Grey
    • View Profile
Re: Exception after iteration over attributes
« Reply #1 on: July 03, 2009, 11:00:36 pm »
Please tell us the version of EA you are using, and whether you are referencing the API through the Interop or 'old' DLL.

Are you releasing the reference to Element after the loop completes? COM applications are notorious for not releasing resources unless they are explicitly deallocated (i.e. set to null) by some means.

And finally, have you reported this directly to Sparx using a bug report? [Not as a forum posting, but with the Report a Bug link near the bottom of any forum page.]
No, you can't have it!

TheTwo

  • EA User
  • **
  • Posts: 39
  • Karma: +0/-0
    • View Profile
Re: Exception after iteration over attributes
« Reply #2 on: July 03, 2009, 11:44:20 pm »
I am using EA 7.1 Build 833 but also tested my addin with the newest Version of 7.5. In both cases the Exeption is thrown.

To reference the API I use the Interop.EA.dll.

How can I release the resource (here the Attribute-Collection) explicitly in C#?

And I have not send a bug report to Sparx Systems, yet, because I am not sure if I do something wrong.

Thanks
TheTwo

«Midnight»

  • EA Guru
  • *****
  • Posts: 5651
  • Karma: +0/-0
  • That nice Mister Grey
    • View Profile
Re: Exception after iteration over attributes
« Reply #3 on: July 04, 2009, 02:13:20 am »
So basically you can cause EA to throw an exception - I am assuming that you can successfully catch the exception so you don't have a crash - regardless of version.

When you tried the newest version of EA did you make sure that the Interop.EA.dll file was refreshed in your project? Sometimes it helps to delete and recreate the association. [I really do not expect this to be the problem, but it never hurts to confirm. If this were an issue it could result in some lengthy debugging for nothing.]

What you need to do is explicitly release any COM objects from EA. This is sort of like calling a dispose method in .Net. Of course you have to do this indirectly as most COM objects (at least those in the EA API) do not provide such a method.

The easiest way to do this is to explicitly set the object variable to null when you are done with it. Something along the lines of:

EA.Element elem;
//
// Use the element for something...
//
elem = null;

When using .Net you should get the same effect when you declare the object variable in a loop construct like:

foreach EA.Element elem
{
  // Use the variable in the loop body...
}

I do not know how good .Net is when you simply declare the object variable in a subroutine. You might want to explicitly deallocate it before returning. Of course this will be difficult if your routine is a function that returns the object.

Note that you cannot do this via a Using clause, since the variable in this case must have an explicit dispose method (which .Net will ensure gets called).

You could create wrapper classes for EA entities. These could provide dispose methods, that in turn released the internal variables holding the COM references. This might help by freeing you from making explicit calls in your working code. You could also write Using blocks to handle object references cleanly.

David[edit]Aha! (perhaps)

I just reread your original message. Are you making the Finalizer calls from within the event code? If you you are probably in trouble. When you are calling garbage collection you definitely have an outstanding reference; something has to be running the event code. Try moving the finalization to somewhere else. This might take some playing around.

Note that the code given in the EA documentation assumes (or seems to) that you are calling this from 'outside' the add-in, releasing (in turn) the resources the add-in consumed.[/edit]
« Last Edit: July 04, 2009, 02:17:54 am by Midnight »
No, you can't have it!

smendonc

  • EA User
  • **
  • Posts: 148
  • Karma: +5/-0
  • I love YaBB 1 Gold!
    • View Profile
Re: Exception after iteration over attributes
« Reply #4 on: July 04, 2009, 02:28:17 am »
I have some ideas but not any solutions.

To explicitly release a COM object from C#:
Assuming 'EA.Element element' is the what needs to get released;
System.Runtime.InteropServices.Marshal.ReleaseComObject(element);

The above will release a single reference made to the COM object.  If the object has been called repeatedly in a loop in will have one reference for each call.  The method to call to 'bulk' release all references is
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(element);
-------------------------
I'm not sure the above will fix the issue you are having as the 'element' passed into the EA_OnRunElementRule is an IN parameter so cleanup would be the responsibility of the caller.  I think the GC.Collect() call is inadvertently cleaning up this object (or another object because it works directly at the .net runtime level) which is causing the issue.
I'm not sure how you would figure this out without Sparx help as <Midnight> notes.

Stan.

TheTwo

  • EA User
  • **
  • Posts: 39
  • Karma: +0/-0
    • View Profile
Re: Exception after iteration over attributes
« Reply #5 on: July 06, 2009, 11:05:00 pm »
Thanks for your help.

After half a day try and error, I found a solution.

I'm using the Method
System.Runtime.InteropServices.Marshal.ReleaseComObject(attributes);


The parameters EA calls are handeled by EA self. So I have not to release the parameter Element. But I have to release the EA.Collection attribs and every attribute (from this collection) I work on. So I can't use a foreach. Its possible to use foreach.

This solution is not nice but it works.
               EA.Attribute attr = null;
                for (short i = 0; i < attribs.Count; i++)
                {
                    attr = (EA.Attribute)attribs.GetAt(i);
                    
                    //check type of enumeration
                    if (!(attr.Stereotype.Equals("enum") && attr.Type.Equals("")))
                    {
                        //release com object
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(attribs);
                        return false;
                    }
                    //release com object
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(attr);
                }
                //release com object
                System.Runtime.InteropServices.Marshal.ReleaseComObject(attr);


Is there a possibility to extend the EA.Collection with an destructor or automate something like this?

I have read about the "extension methods" in C# 3.5 but I use 2.0 and VS2005.
« Last Edit: July 06, 2009, 11:19:34 pm by TheTwo »

TheTwo

  • EA User
  • **
  • Posts: 39
  • Karma: +0/-0
    • View Profile
Re: Exception after iteration over attributes
« Reply #6 on: August 31, 2009, 09:26:38 pm »
Hi,

I've tried to use my workaround in my Add-In and realized, that it is nearly impossible to release all references by hand. The code gets really ugly.

Has someone an other - maybe more usable than mine - idea to solve my problem?

Thanks
TheTwo

lubos

  • EA User
  • **
  • Posts: 101
  • Karma: +0/-0
  • I love YaBB 1G - SP1!
    • View Profile
Re: Exception after iteration over attributes
« Reply #7 on: September 22, 2009, 10:03:49 pm »
Hi,

I have just found out memory leaks in my C# plugin  that I was looking  for a long time for.
and it is probably related to your problem.

I found out that I _always_ have to call ReleaseComObject on any object I get from EA API (eg. GetPackageByID, GetElementsByQuery ...) when it is not used anymore.
Setting to null is not enough.

 I have not read about this principle in any EA documentation and demos.
I'm not very advanced in these issues, can anybody confirm or describe this ?

Thank you in advance.


smendonc

  • EA User
  • **
  • Posts: 148
  • Karma: +5/-0
  • I love YaBB 1 Gold!
    • View Profile
Re: Exception after iteration over attributes
« Reply #8 on: September 23, 2009, 04:09:44 pm »
Hi Lubos,

What you are saying is correct, this is not specific to EA, it's how the .net runtime works, my interpretation below.

Setting an object to null in any .net language like C# will not release any memory or resources that were allocated to the object by COM immediately from the OS perspective.  The .net runtime will flag the resources as free but not release them back to the OS.  Eventually the Garbage Collector will decide when to return the resource back to the OS.  The ReleaseComObject method explicitly instructs the .net runtime to immediately release the object and its resources back to the OS and update its internal data structures bypassing the Garbage Collector altogether.

Stan.

lubos

  • EA User
  • **
  • Posts: 101
  • Karma: +0/-0
  • I love YaBB 1G - SP1!
    • View Profile
Re: Exception after iteration over attributes
« Reply #9 on: September 23, 2009, 07:09:32 pm »
Yes, I intuitively understand this.
I understand that GC can free it after some while,
but it seems to me .NET GC never frees the COM references, so I have to do it always explicitly.  I have not found this explicit calls in any demos provided by sparx.
I'm still not sure whether I have to explicit free all parts of COM collections ]eg. from GetElementsByQuery), or I can free only this collection and this will safely free all its members.

I'm not sure about using "foreach" as well.

is it safer this :
Code: [Select]
EA.Collection col= elem.Packages
foreach(EA.Packages in col){...}
ReleaseComObject(col)

or can I call just:
Code: [Select]
foreach(EA.Packages in elem.Packages){...}??

thanks for any hints

Eve

  • EA Administrator
  • EA Guru
  • *****
  • Posts: 8090
  • Karma: +118/-20
    • View Profile
Re: Exception after iteration over attributes
« Reply #10 on: September 24, 2009, 09:00:30 am »
Try forcing .Net to run the garbage collector periodically.

GC.Collect();
GC.WaitForPendingFinalizers();

TheTwo

  • EA User
  • **
  • Posts: 39
  • Karma: +0/-0
    • View Profile
Re: Exception after iteration over attributes
« Reply #11 on: September 25, 2009, 01:55:01 am »
Hi,

I've tried to call the garbage collector in the event code (OnEndValidation) after nearly release every COM object by ReleaseComObject(...) I have used. This only causes the exeption to happen in the OnEndValidation()-part of the code instead of other event methods like EA_OnRunConnectorRule(...).

Is it possible that EA runs concurrent operations on the repository, while the validation is executed. May this cause these exceptions?

Thanks
TheTwo  

TheTwo

  • EA User
  • **
  • Posts: 39
  • Karma: +0/-0
    • View Profile
Re: Exception after iteration over attributes
« Reply #12 on: September 27, 2009, 10:50:37 pm »
Thanks to all,

today I've found the solution to my problem. The reason has been, that I've used the EA.Element supplied as prameter of the method EA_OnRunElementRule(..).

Now I use the element, like in the other EA_OnRun...Rules. There is only an ID delivered.

Code: [Select]
       
public void EA_OnRunElementRule(EA.Repository Repository, string RuleID, EA.Element Element)
{
      EA.Element element = Repository.GetElementByGuid(Element.ElementGUID);

By using my own "element" recieved out of the repository, no exceptions occure.

Why is an EA.Element in the API defined, that should not be used? All other methods have only an ID as parameter and everything works fine.

Maybe this is a bug (but definitly an inconsitency in the API) that should be changed in the next versions of EA.

The Two