Blog du Pôle .NET

Partager pour mieux développer...

WCF : CommunicationException au lieu de FaultException[T]

clock October 21, 2009 04:17 by author Xavier Masclet

J’ai récemment voulu mettre en place une gestion d’exceptions « WCF-compliant » sur un service WCF.

L’idée étant la suivante : le service WCF doit attraper toutes les BusinessException susceptibles d’être levées par la couche métier et les transformer en FaultException<BusinessFault>

J’ai donc mis en place un handler d’exception qui implémente l’interface IErrorHandler ainsi qu’un « comportement de service » (une classe implémentant IServiceBehavior en fait).

Parallèlement à ça j’ai défini un contrat « BusinessFault » et fait en sorte que mes exceptions métier (BusinessException) puissent fournir la BusinessFault correspondante.

 

Voici le code de la BusinessException :

 

public class BusinessException : Exception

{

    public void TranslateToFault(MessageVersion version, ref Message faultMessage)

    {

        string inner = (InnerException == null ? "" : InnerException.GetType().Name);

        BusinessFault tf = new BusinessFault(this.Code, this.Message, inner);

        MessageFault f = MessageFault.CreateFault(new FaultCode("Receiver"), new FaultReason("Erreur métier"), tf);

        erreur = System.ServiceModel.Channels.Message.CreateMessage(version, f, "defaultAction");

    }

 

}

 

BusinessFault est une simple classe marquée comme [DataContract] et possédant 3 accesseurs de type string marqués comme [DataMember].

 

Ci-après le code du handler d’exception :

 

public sealed class MyExceptionHandler : IErrorHandler

{

    bool IErrorHandler.HandleError(Exception ex)

    {

        return true;

    }

 

    void IErrorHandler.ProvideFault(Exception ex, MessageVersion version, ref Message fault)

    {

        BusinessException exception = ex as BusinessException;

        if (exception != null)

        {

            exception.TranslateToFault(version, ref fault);

        }

        else

        {

            HandleUnknownException(ex, version, ref fault);

        }

    }

 

    private void HandleUnknownException(Exception exception, MessageVersion version, ref Message erreur)

    {

        // ...

    }

}

 

Et maintenant le behavior qui permet de transformer automatiquement toutes les BusinessExceptions en FaultException :

 

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]

public sealed class MyExceptionHandlingBehaviorAttribute : Attribute, IServiceBehavior

{

    void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)

    {

    }

 

    void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)

    {

        if (serviceHostBase == null)

        {

            return;

        }

 

        // Ajout du handler d'exception sur tous les dispatchers WCF

        foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)

        {

            dispatcher.ErrorHandlers.Add(new MyExceptionHandler());

        }

    }

 

    void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)

    {

    }

}

 

 

Pour que tout ceci fonctionne bien, il restait à décorer les méthodes de service comme suit :

 

[FaultContract(typeof(BusinessFault)]

PersonneDataContract EnregistrerPersonne(PersonneDataContract personneDataContract);

 

Et enfin décorer la classe d’implémentation de service avec l’attribut précédemment créé :

 

[MyExceptionHandlingBehaviorAttribute]

public class MyService : IMyService

{

}

 

Et voilà. “Normalement” tout doit fonctionner…

En effet ca fonctionne bien… tant que le endpoint de mon service utilise du basicHttpBinding !

Dès que l’on passe en wsHttpBinding, ca ne fonctionne plus, en effet coté client au lieu de récupérer une FaultException<BusinessFault>, je récupère une CommunicationException, bof bof !

Pour corriger cela, il est en fait nécessaire de spécifier une action sur la fault fournie par le service et il faut aussi spécifier cette même action sur les méthodes de service. Ainsi il suffit de définir une constante FaultAction, par exemple :

 

public class Constantes

{

    public const string MyFaultAction = "http://MyService/Fault";

}

 

Ensuite il faut modifier notre méthode TranslateToFault (sur la classe BusinessException) comme ceci :

 

public void TranslateToFault(MessageVersion version, ref Message faultMessage)

{

    string inner = (InnerException == null ? "" : InnerException.GetType().Name);

    BusinessFault tf = new BusinessFault(this.Code, this.Message, inner);

    MessageFault f = MessageFault.CreateFault(new FaultCode("Receiver"), new FaultReason("Erreur métier"), tf);

    erreur = System.ServiceModel.Channels.Message.CreateMessage(version, f, Constantes .MyFaultAction);

}

 

Notez l’utilisation de la constante dans l’appel de la méthode Message.CreateMessage, pour le paramètre « Action ».

 

Enfin il reste à spécifier cette action sur la méthode de service qui devient donc :

 

[FaultContract(typeof(BusinessFault), Action = Constantes.MyFaultAction)]

PersonneDataContract EnregistrerPersonne(PersonneDataContract personneDataContract, ErrorManager errorManager);

 

Une fois régénéré le proxy coté client, ce dernier est maintenant en mesure de catcher correctement des FaultException<BusinessFault> levées par le service.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Un profiler de mémoire bien sympathique…

clock August 20, 2009 12:23 by author lnyffels

Lors d’un précédent ticket, j’ai brièvement décrit comment invoquer un objet .NET à partir d’un client COM écrit en VB (non managé).

Pour rappel cela se fait par l’intermédiaire d’un wrapper CCW (COM Callable Wrapper). Le CCW est un objet COM non managé qui est créé par le CLR au même titre que l’objet .NET qu’il encapsule. Toutefois, contrairement au client .NET qu'il enveloppe, le wrapper CCW fait l'objet d'un décompte de références selon le mode COM standard. Quand le décompte de références du wrapper CCW atteint zéro, le wrapper libère sa référence à l'objet managé. Un objet managé sans aucune référence restante est collecté lors du cycle garbage collection suivant. (cf. lien msdn suivant : http://msdn.microsoft.com/en-us/library/f07c8z1c.aspx)

 

Aussi, il est nécessaire que le CCW soit « déréférencé » par le client COM VB pour que les objets managés .NET qu’il référence soient également détruits par le garbage collector. Etant de nature plutôt méfiante lorsqu’il s’agit d’interopérabilité COM / .NET et n’étant un as du VB ;-), il me paraissait utile de vérifier cela via un profiler de mémoire. J’avais utilisé il y a quelques années de cela chez un ce mes clients préférés l’utilitaire Optimize-it de Borland. Mais celui-ci n’a semble t’il plus évolué depuis le Framework 1.1. Il en existe beaucoup en .NET mais assez peu sont capables de remonter les objets managés et les objets non managés.   J’en ai trouvé un plutôt sympa qui m’a apporté le service que j’attendais. Il s’agit de « .NET Memory Profiler 3.1 » de la société SciTeck Software (http://memprofiler.com). Le soft m’a permis de m’attacher au processus client, de prendre des photos (snapshot) à différents intervalles et après plusieurs sollicitations je me suis aperçu que les objets .NET étaient bien libérés par le garbage collector. La preuve en 2 images… ;-)  

Snapshot 1 :

Snapshot 2 : 

Conclusion : l’interopérabilité COM / .NET, « ça marche pas pas si mal que cela » !

Laurent Nyffels 

 

 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Echanger des collections d’objets via « COM Callable Wrapper »

clock August 19, 2009 12:08 by author lnyffels

Confronté récemment à une problématique d’intéropérabilité VB / .NET, je souhaitais poster ce ticket qui je l’espère pourra servir à certains.

Nous avons tous un jour ou l’autre dû dans nos développements sous .NET invoquer un « vieux » composant COM réalisé en VB6, en C++ ou en Delphi… Cela se fait assez facilement dans Visual Studio 2005 ou 2008, et l’objet COM exposé apparait comme un objet .NET. Ceci est rendu possible grâce au wrapper RCW (Runtime Callable Wrapper) dont la fonction principale est de « marchaliser » les appels entre un client .NET et l’objet COM invoqué.

Mais nous sommes surement moins nombreux à avoir été confronté à la problématique inverse. A savoir, comment exposer un objet .NET à un composant COM existant.

La problématique est moins triviale car un composant COM développé en VB6 ou en C++ unmanaged n’est pas capable de dialoguer nativement avec une assembly .NET.  Il existe heureusement un Wrapper .NET qui permet d’exposer un objet .NET sous la forme d’un composant COM. C’est la fonction du CCW «COM Callable Wrapper ».

 Je ne vais pas dans ce ticket décrire toutes les étapes nécessaires pour réaliser cela, car il existe des liens, notamment sur MSDN qui le font très bien. Cf : http://msdn.microsoft.com/en-us/library/f07c8z1c(VS.71).aspx

Comme souvent, les exemples que l’on trouve nous montrent comment renvoyer une simple chaine de caractères ou un objet. Toutefois, lorsqu’il s’agit de passer une collection d’objets complexes définis en VB6 en paramètre d’une méthode d’une classe .NET ou de renvoyer une collection d’objets cela se complique un peu…

En fait, même si vous avez fait tout ce qu’il faut pour exposer une classe .NET en COM via CCW en décorant votre classe avec les attributs qui vont bien  [GUID()] [ComVible()] etc… et utilisé l’utilitaire Regasm.exe, vous arrivez bien à renvoyer un objet vers votre client COM mais pas une collection de cet objet.

Euh… un petit exemple peut être…

Voilà, je souhaite invoquer la méthode « GetUtilisateur » de  la classe .NET « ProxyUtilisateur  » d’une assembly « ClassProxyRefCOM » exposée en COM  pour qu’elle me renvoie un objet « MappingUtilisateur ».

En VB6, cela donne un truc du genre :

 
Dim oProxyService As ClassProxyRefCOM.ProxyUtilisateur
Dim oMappingUser As ClassProxyRefCOM.MappingUtilisateur
Set oProxyService = CreateObject("ClassProxyRefCOM.ProxyUtilisateur")
Set oMappingUser = oProxyService.GetUtilisateur(UserNT)

Pour se faire, il a fallu nous seulement décorer et exposer la classe ProxyUtilisateur, mais également la classe « MappingUtilisateur » pour qu’elle soit connue comme un objet COM.

En C#, cela donne un truc comme cela :

 

[Guid("3661703D-2BB9-46a2-8723-72B78B7E0390")]

[ComVisible(true)] 

public class MappingUtilisateur : ClassProxyRefCOM.IMappingUtilisateur 

{

     private string _prenom;

     private string _nom;

      private string _email;

        private string _profilNT; 

       public MappingUtilisateur()        {}

       public string Prenom   {    get { return _prenom; }    set { _prenom = value; }        }

       public string Nom        {    get { return _nom; }     set { _nom = value; }        }

        ……  

} 

Au passage, n’oubliez pas de cocher l’option « Register for COM Interop » dans les propriétés de votre projet .NET. Cette option fait la registration de la dll en COM dans la base des registres pour vous et crée le fichier tlb que vous pouvez ensuite utiliser dans Visual Studio 6 en référence de votre projet VB6. Enfin je ne vais pas vous refaire le cours…

Au final cela fonctionne correctement !!!

Toutefois imaginer maintenant que vous vouliez renvoyer une collection d’objet MappingUtilisateur, via une méthode GetListUtilisteurs(). Et bien vous ne pouvez pas exposer en COM une collection d’objets sans passer par une astuce. Celle-ci consiste à exposer un objet qui hérite d’une …. ArrayList .NET.

En C#, cela donne du code du style :

[Guid("F5113128-784F-4125-8AA4-A00F9762C73C")]

 [ComVisible(true)]

 public class MyCollectionCOM :ArrayList

 {

        public MyCollectionCOM() : base()        { }  

       public object GetByIndex(int idx)        return this[idx];   }

       public int NbElem()    {     return this.Count;     }

  }

De ce fait, vous pouvez déclarer un objet « MyCollectionCOM » en VB6 capable de recevoir votre collection de « MappingUtilisateur » :

Dim oProxyService As ClassProxyRefCOM.ProxyUtilisateur 
Set oProxyService = CreateObject("ClassProxyRefCOM.ProxyUtilisateur")
Dim arr As ClassProxyRefCOM.MyCollectionCOM
Set arr = oProxyService.GetListUtilisateurs()

Dans un prochain ticket, je parlerai du mécanisme de libération des objets CCW et .NET et du « profiler » de mémoire qui m’a permis de m’en assurer…

Laurent Nyffels

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Authentification Reporting Services 2008

clock May 20, 2009 09:55 by author yvue

Bonjour à tous,

Juste une petite configuration Reporting Services 2008.

Petit rappel pour ceux qui ne sont pas au courant, Reporting Services dans sa version SQL Server 2008 ne nécessite plus l'installation d'un serveur IIS.
Vous allez dire "C'est très pratique" ... Oui mais quand on a pris l'habitude de corriger notamment nos problèmes de sécurité avec IIS, il faut desormais trouver comment fonctionne RS 2008.

Première chose toute bete : l'emplacement des logs est "C:\Program Files\Microsoft SQL Server\MSRS10.MSSQLSERVER\Reporting Services\LogFiles" si vous installez RS par défaut.

Ensuite, si, comme moi, vous êtes confrontés à un problème d'authentification (dans mon cas, la plateforme mettait en place une authentification Kerberos par défaut ???)
Dans ce cas c'est le fichier :C:\Program Files\Microsoft SQL Server\MSRS10.MSSQLSERVER\Reporting Services\ReportServer\rsreportserver.xml qui va vous interessez !!

un petit tour dans sa structure XML pour y configurer (ou plutot desactiver) le type d'authentification Windows Negotiate ...

<Authentication>
<AuthenticationTypes>
<!--<RSWindowsNegotiate/>-->
<RSWindowsNTLM/>
</AuthenticationTypes>
<EnableAuthPersistence>true</EnableAuthPersistence>
</Authentication> 

 

Yoann Vue 
 

 

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Entity Framework : release des multiples providers de bases de données

clock February 2, 2009 11:40 by author aequoy

En ce début d'année, une liste d'annonce autour du Framework Entity vient nous rassurer quant à la pérénité de la technologie.

Devart offre un Provider supportant l'accès à Oracle, MySQL et PostgreSQL.

Sybase annonce le support du framework Entity sur iAnywhere.

Npgsql2.0RTM fournit un support du framework Entity sur PostgreSQL.

IBM annonce l'arrivée d'un provider Entity pour DB2.

Alexandre Equoy

Currently rated 4.5 by 2 people

  • Currently 4.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Dynamic Language Runtime

clock December 10, 2008 13:27 by author aequoy

Pour comprendre l’intégration des langages dynamiques dans .Net 4, il faut commencer par creuser sur l'élément moteur : le Dynamic Language runtime.

La mission première du DLR est de permettre aux langages dynamiques (python, ruby, pHp, javascript…) de s’interfacer avec .Net.

Un deuxième objectif est de permettre l’interopérabilité entre .Net et les interfaces COM IDispatch de manière simple et claire.

Un troisième  objectif est de rendre les langages .Net plus « dynamiques » en supportant le DLR.

 

Avec les types dynamiques, l’objet est maître de déterminer en runtime s’il supporte ou non le message ou l’opération qui lui est envoyé. Les objets dynamiques participent donc à un protocole de message afin de négocier de quelle manière un message abstrait est passé à un autre objet.

 

Les notions importantes à retenir du DLR sont :

·         Modèle de hosting commun pour attaquer la DLR : l’objet ScriptRuntime est le point d’entrée vers les langages dynamiques. Il permet d’exécuter du code dans le contexte d’exécution (ScriptScope) au travers d’un moteur de script (ScriptEngine) qui va choisir le langage dans lequel le code va être exécuté.

·         Utilisation d’arbres sémantiques (Expression Trees) : là on attaque une notion très abstraite du domaine de la linguistique (dédicace à Jeannine Leguy ;)). Le but étant d’organiser les expressions sous forme arborescente afin que l’analyseur syntaxique puisse résoudre facilement ces expressions.

·         Intégration d’emplacement d'appel dynamique (DynamicSites, SiteBinders, Rules) permettant de lier un appel dynamique (message émis par C# par exemple) à une cible (objet Python par exemple).

·         Typage dynamique partagé au travers de l’interface IDynamicObject et de MetaObject. MetaObject permet l’interopérabilité entre les langages. IDynamicObject va permettre de rendre le comportement dynamique.

·         Un ensemble d’utilitaires (default binder, tuples, big integers, adapters pour permettre aux types statiques de participer au protocol IDynamicObject)

 Voilà un petit aperçu du DLR. Il va falloir pas mal de temps afin de creuser les impacts, les apports du type dynamic dans .Net.

Alexandre Equoy

Currently rated 4.5 by 2 people

  • Currently 4.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


C# 4 : Dynamic object

clock December 8, 2008 23:00 by author aequoy

Pour celles et ceux qui n'ont pas suivi la PDC 2008, une des nouveautés montrées par la team C# dans C#4 concerne la possibilité d'exécuter des opérations, dont les détails ne seront connus qu'à l'exécution, en utilisant le mécanisme de délégation soutenu par le DLR (Dynamic Language Runtime).

Ca paraît complexe dit comme cela :) (la phrase n'est pas de Marcel Proust) et bien en fait ça l'est:)

Un petit exemple s'impose :

dynamic d = GetDynamicObject();<br/>
d.MethodeResolueAlExecution();
//Marcel Proust Powered :)

Comme vous pouvez voir, la variable locale "d" est du type dynamic, qui est un type compris par le compilateur. Ce code compile (donc on release;) )et il aurait compilé quel que soit le nom de la méthode. Le type "dynamic" est un type très spécial (^^).

Pour le compilateur, la différence avec une variable normale est qu'il n'est pas possible d'émettre un IL (Intermediate Language ) appelant la méthode MethodeResolueAlExecution car il ne connait pas le type "d". Il émet donc un "emplacement d'appel dynamique" pour permettre de résoudre l'appel à l'exécution (via le DLR).

Mais à quoi cela peut-il servir ????

Cela va permettre d'utiliser C#, pour invoquer des méthodes écrites avec des langages dynamiques tels Python/Ruby où, chose plus intéressante, sur n'importe quel objet COM IDispatch, sans même un chargement interop (ou wrapper).

Un exemple issu de codeplex mettant en évidence (c'est pas si évident que cela en fait :) ) le DLR :

J'ai une méthode écrite en python (satan, sors de ce corps !!!)

def welcome(name): return "Hello '" + name + "' from IronPython"

La suite, un main C# qui va charger puis appeler la méthode :

static void Main(string[] args) {
Console.WriteLine("Loading helloworld.py...");
ScriptRuntime py = Python.CreateRuntime();
dynamic helloworld = py.UseFile("helloworld.py");
Console.WriteLine("helloworld.py loaded!");
for (int i = 0; i < 1000; i++) {
Console.WriteLine(helloworld.welcome("Employee #{0}"), i)
}
Console.WriteLine(); }

Pour la route, un webcast d'Anders Hejlsberg explicant la signification de l'introduction des types dynamiques dans C#4.

Je vous invite à regarder Deep Dive: Dynamic Languages in Microsoft .NET c'est extrêmement intéressant !

Alexandre Equoy

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


PLINQ dans VS 2010 .Net4

clock November 9, 2008 02:17 by author aequoy
Depuis hier je joue un peu :D avec VS 2010.
Entre 2 plantages, j'ai pratiqué quelques exemples de requêtes parallèlisées via PLINQ.
Dans ma machine virtuelle, il est pour l'instant très difficile de mesurer le gain (quelques millisecondes dans mes premiers tests).
En lisant un peu le blog de la team parallel extensions, il serait possible de simuler dans la machine virtuelle le multi coeur grâce à hyperV.

Donc wait and see, j'essaierai de mettre cela en place dans un futur proche avec l'aide d'un ingénieur IT.

En attendant, c'est assez bluffant, quasi-indolore au niveau du code.
Par contre les objets de requêtage PLINQ sont complètement différents de ceux de Linq (objectquery dans mon cas).
Linq

PLinq

Alexandre Equoy

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


UML et VS 2010

clock November 8, 2008 10:23 by author aequoy
Une des nouveautés de VS2010 concerne l'intégration de diagrammes UML (Yoann tu vas adorer :) )
Les 12 diagrammes UML ne sont pas intégrés.
Les 5 diagrammes les plus importants font leur apparition en plus du diagramme de classe existant :
  • Diagramme de cas d'utilisation
  • Diagramme d'activité
  • Diagramme de séquence
  • Diagramme de composant
  • Diagramme de couche
Personnellement c'est une excellente nouvelle qui va nous permettre d'intégrer plus de modélisation et de pilotage dans nos développements.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Graphs d'objets dans VS 2010

clock November 8, 2008 09:47 by author aequoy

Alexandre Equoy

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Calendrier

<<  March 2010  >>
MoTuWeThFrSaSu
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234
Afficher en pleine page

Visiteurs