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


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


Performances WCF

clock September 12, 2008 06:01 by author yvue

Un post interessant sur certaines configurations à mettre en place pour améliorer les perfs WCF

 http://www.iserviceoriented.com/blog/post/Configuring+Performance+Options+-+WCF+Gotcha+3.aspx

Yoann Vue 

 

Be the first to rate this post

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


MSDN Technet Tour 2008

clock September 2, 2008 12:27 by author aequoy

Juste un petit billet pour vous signaler que le Technet Tour 2008 passera sur Lille les 13 et 14 octobre 2008.

Inscrivez vous en cliquant sur l'image

Inscrivez vous.

Alexandre Equoy

Currently rated 5.0 by 1 people

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


Workflow Foundation Part #1

clock August 14, 2008 09:00 by author dox

J'étais parti pour faire un article sur WCF, mais comme tout a déjà été dit, ça attendra un peu.
Cet article est le premier d'une série consacrée à Workflow Foundation (WF). Je vais essayer tout au long de ces articles, d'illustrer quelques une des fonctionnalités de WF, entre autres :

  • les workflows séquentiels
  • les workflows à états
  • les activités parallèles, conditionnelles et les conditions
  • la persistence dans Workflow Foundation
  • le tracking...

On va commencer doucement, avec un premier workflow de type séquentiel. Et pour ça, nous allons partir d'un exemple : Il fait beau dehors et Bob aimerait poser quelques jours de congés. Bob va donc déposer une demande de congés, qui devra être validée par son chef, puis par les ressources humaines. Une fois sa demande acceptée, Bob sera notifié qu'il peut aller profiter du soleil.
Cool

Première Etape : Le Workflow

Pour réaliser tout ça, nous allons avoir besoin d'un workflow (de type séquentiel ici, puisque les étapes se déroulent les unes après les autres). Voilà à quoi pourrait ressembler notre workflow

 

Il est composé de 3 activités de type HandleExternalEvent, et d'une activité CallExternalMethod qui vont permettre de :

  • d'abord réagir à une demande de congés
  • ensuite réagir à la validation par le supérieur de Bob
  • puis celle des ressources humaines
  • et enfin, appeler une méthode qui notifiera Bob de l'état de sa demande.

Deuxième Etape : L'interface 

Puisque notre workflow réagit à des événements et qu'il appelle une méthode externe, il nous faut définir ces éléments. Pour cela, nous crééons une interface qui contient les définitions suivantes :

[ExternalDataExchange]
public interface IDemandeCongesService {
  event EventHandler<DemandeCongesEventArgs> CongesDemandes;
 
event EventHandler<DemandeCongesEventArgs> ValidesSuperieur;
 
event EventHandler<DemandeCongesEventArgs> ValidesRH;
 
void NotifierDemandeAcceptee(Guid instanceId, DemandeCongesData data);
}

Ce qu'il faut noter dans la définition de cette interface :

  • L'interface est marquée de l'attribut ExternalDataExchange pour indiquer qu'elle sert à communiquer avec un workflow.
  • Les événements sont typés et héritent de la classe ExternalDataEventArgs. Ils sont également marqués de l'attribut Serializable.
  • L'objet DemandeCongesEventArgs contient une propriété de type DemandeCongesData. Cet objet contient les informations propres à notre demande de congés (nom de l'employé, le nombres de jours...), lui aussi marqué de l'attribut Serializable.

Il ne nous reste plus qu'à associer les propriétés de nos activités aux événements et méthodes correspondants.

Troisième Etape : L'implémentation et l'application hôte 

Un worfklow dans WF fonctionne un peu de la même façon qu'un service WCF. Il ne peut être démarré tel quel. Il a besoin d'une application hôte pour héberger le runtime de Workflow Foundation, qui se chargera ensuite de charger/créer une instance de notre workflow et de la démarrer.

Pour faire simple, nous regrouperons toute la logique métier dans une application de type Windows (le Web c'est mal Tongue out). Cette application contient une fenêtre principale et une classe qui contient l'implémentation de notre interface IDemandeCongesService. Voici un petit aperçu de notre application finale :

Ceci reste un exemple assez simple de ce qu'on peut faire avec Workflow Foundation. Les autres fonctionnalités de WF seront abordées dans les prochains articles de cette série. Dans le prochain épisode... Le workflow a états. En attendant, vous pouvez télécharger le contenu complet de l'exemple en suivant ce lien : WFpart01.zip (20,96 kb).

Par Dominique Thery,
To be continued...

Currently rated 4.3 by 3 people

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


Cloud Computing : la tête dans les nuages

clock July 23, 2008 00:29 by author aequoy

Le Cloud computing kezako ?

Le terme regroupe l'ensemble des technologies offrant la possibilité de disperser un système d'information sur des infrastructures prises en charge par un ou plusieurs prestataires.

D'un point de vue infrastructure, cela correspond en raccourci à la mouvance de grilles de serveurs, de la virtualisation,  de partage de ressources et de l'externalisation.

C'est bien joli de disperser l'infrastructure mais qu'en est-il de ce qu'elle héberge  (les softs) ? 

Que ceux qui se souviennent des spécifications de CORBA se remettent à plancher, ça y est, c'est à la mode !! Laughing

Depuis l'arrivée de WCF (Windows Communication Foundation), nous entendons parler de plus en plus d'architecture SOA viables, d'architectures "Software as a service", de bus de services.

L'émergence d'outils tels que Live Mesh, popFly tendent à montrer que nous allons vers d'avantages de services.

Microsoft a publié fin 2007, les premières guidelines de la mise en place d'un bus de service.

WCF + Biztalk + WF (Workflow Foundation) sont au coeur de ce bus.

 

L'arrivée d'ADO.Net Data Services, les futurs SQL Server Data Services vont permettre d'exposer en plus des services, les données sur les protocoles "internet compliant".

Microsoft parle donc maintenant non plus d'ESB (enterprise service bus) mais d'ISB (internet service bus). Quasimment toutes les technologies sorties (framework 3.0 et 3.5) s'intègrent dans cette idée.

Ce qui est intéressant ici n'est pas de compter le nombre d'acronymes pompeux utilisés Tongue out mais plutôt de remarquer que, comme d'habitude diront les anciens, les briques unitaires que Microsoft sort finissent par s'assembler pour donner des possibilités de plus en  plus évoluées.

PS :

Le but ici n'est certainement pas de se faire l'oracle de ce qui va se passer mais juste de constater un état de fait. Irons nous enfin vers des architectures orientées services viables ?

L'échec cuisant de CORBA me fait remémorer quelques commentaires par rapport à ce renouveau de l'orienté service :

  • plutôt que l'orienté service, je pense qu'il faut parler d'orienté métier
  • le marketing ne gagne pas sur le long terme (même si j'adore le marketing Laughing)
  • la complexité échoue toujours
  • les technologies qui marchent sont celles où le coût d'entrée est très faible car se sont les technologies qui sont suceptibles d'être massivement utilisés.

Liens : 

ESB Guidance : http://www.codeplex.com/esb

Biztalk en support de cet ISB : http://labs.biztalk.net/Overview.aspx

Webcast des techdays 2008

Pour les nostalgiques : Rise and Fall of CORBA

Alexandre Equoy 

Be the first to rate this post

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


Calendrier

<<  February 2012  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
2728291234
567891011
Afficher en pleine page

Visiteurs