2009-01-06 10 views
1

J'ai une application ASP.NET 2.0 sous IIS qui a la fonctionnalité de en exportant certaines données vers un logiciel appelé HFM (Oracle Hyperion Financial Management). Pour effectuer cette exportation, l'application .net utilise une API basée sur les objets COM fournis par le client HFM (le client est installé sur la même machine que le serveur, etc.).NET force Objets COM version

Mon problème est que l'API fournit un méthode pour se connecter au serveur HFM mais ne pas se déconnecter.
La documentation indique que pour se déconnecter, l'application doit appeler la méthode Marshal.ReleaseComObject() sur chaque objet COM créé. Mais il y a beaucoup d'actions complexes effectuées et je ne suis pas capable de libérer tous les objets créés.
Donc, mon application ne se déconnecte pas.

J'ai remarqué que lorsque je remplace les fichiers dll de l'application ASP.NET (ce qui semble réinitialiser les objets instanciés par .NET), l'application se déconnecte automatiquement.

J'ai essayé plusieurs fois d'appeler:

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

Mais le problème reste. Je cherche un moyen de m'assurer que TOUT objet créé, même les objets COM sont libérés. J'ai essayé avec Marshal.FinalReleaseComObject() mais ce n'est pas mieux. Comme je mets un lock() sur cette section, il y a toujours au plus un utilisateur sur cette partie, donc je peux même utiliser des techniques hardcore pour libérer les objets COM.

Y at-il un moyen de savoir quel objet ou au moins le type de l'objet qui n'a pas été libéré?

Merci pour votre aide.

Répondre

1

Mais il y a beaucoup d'actions complexes effectuées et je ne suis pas capable de libérer tous les objets créés.

Il y a votre problème.

Vous cherchez une solution de facilité. Mais vous travaillez avec COM. Le seul moyen facile de vous en sortir est lorsque votre processus/domaine d'application est fermé.

+0

Vous aviez raison, après une analyse approfondie et des simplifications de processus, nous avons remarqué que certains objets n'étaient pas correctement libérés. C'était la raison du problème. –

2

Pouvez-vous mettre un type de wrapper générique qui implémente IDisposable autour de chacune de ces instances COM?

Ensuite, vous pouvez appeler Marshal.FinalReleaseComObject (ou boucle sur Marshal.ReleaseComObject vérifier la refcount) dans le Dispose, méthode, et seulement instancier l'objet COM via un using qui fait référence à votre type d'emballage .

Un autre avantage de cette astuce de wrapper est que vous pouvez utiliser le CLR profiler pour inspecter les instances de votre type qui n'ont pas encore été éliminées, répondant ainsi à votre dernière question.

1

Il est absolument important de définir la variable sur Null/Nothing après avoir appelé Marshal.ReleaseComObject ou Marshal.FinalReleaseComObject.

Dim cn As ADODB.Connection 
cn = New ADODB.Connection 
cn.Open(_cnnstr) 
cn.Execute(sbDML.ToString) 
cn.Close() 
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cn) 
cn = Nothing '!!!IMPORTANT!!! - Do not remove, MUST be explicitly called! 

De plus, je constate que la création d'une autre méthode permet d'éviter des problèmes à traiter avec des objets COM locaux (variables placés sur la pile). Par exemple, si vous avez une méthode qui fait tout, enveloppez-la dans une autre méthode, ajoutez un appel à garbage collection, puis appelez le wrapper.

Public Sub MainMethod 
    '... 
    Marshal.FinalReleaseComObject(foo) 
    foo = Nothing '!!!IMPORTANT!!! - Do not remove, MUST be explicitly called! 
End Sub 

Public Sub WrapperMethod 
    Call MainMethod 
    GC.Collect() 
End Sub 

je crois que l'appel supplémentaire, avec la création d'une pile d'addition pour les variables locales, force les objets à être entièrement collectés plus rapidement et provoque les objets COM à libérer entièrement.

Je suis ce modèle depuis quelques années, et je n'ai eu aucun problème depuis.