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


Security Identifier, Binaire et Base 64

clock September 23, 2009 14:11 by author dox

Je me suis laissé entendre dire que la migration des données SharePoint n’était pas ce qu’il y a de plus facile. Ah bon ?

Petite mise en situation : Prenez un expert SharePoint (un vrai hein, comme Yoann par exemple !), une base de données qui contient des informations codées dans un champ binaire, un fichier XML qui contient d’autres données (codées en… vous verrez plus loin) et vos identifiants Windows (les fameux SID qui ressemblent à ça : S-1-5-21-xxx). Vous mélangez bien, et vous obtenez ça :

  • 01050000000000051500000038EDA9CF33F7AFDD94FC17C4F4010000
  • S-1-5-21-3484020024-3719296819-3289906324-500
  • AQUAAAAAAAUVAAAAOO2pzzP3r92U/BfE9AEAAA==

Vous l’aurez deviné le premier est le champ binaire stocké dans SQL Server. Le second, notre fameux SID. Et le troisième : le même codé en Base64 ! (Et là on applaudit Arnaud, parce que c’est lui qui a trouvé !)

Yoann a beau être un expert en SharePoint (et je vous jure que c’est vrai), les méthodes de conversion d’une forme vers une autre ne sont pas si évidentes que ça à trouver. D’ailleurs, en fouillant bien, on n’en a pas trouvé beaucoup.

Alors sous vos yeux ébahis, voici une petite classe utilitaire avec les méthodes qui vont bien pour convertir les données d’une forme vers une autre. Si un jour vous avez une migration de données SharePoint, ça pourra toujours être utile.

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Principal;

public class SharePointUtils {

    private static byte[] BinaryStringToByteArray(string binaryString) {
        return Enumerable.Range(0, binaryString.Length).Where(x => x % 2 == 0).
            Select(x => Convert.ToByte(binaryString.Substring(x, 2), 16)).ToArray();
    }

    public static string BinaryStringToSidString(string binaryString) {
        return new SecurityIdentifier(BinaryStringToByteArray(binaryString), 0).ToString();
    }

    public static string SidStringToBinaryString(string sId) {
        StringBuilder sb = new StringBuilder();
        SecurityIdentifier si = new SecurityIdentifier(sId);
        byte[] array = new byte[si.BinaryLength];
        si.GetBinaryForm(array, 0);
        array.ToList<byte>().ForEach(x => sb.AppendFormat("{0:X2}", x));
        return sb.ToString();
    }

    public static string BinaryStringToBase64String(string binaryString) {
        byte[] array = BinaryStringToByteArray(binaryString);
        return Convert.ToBase64String(array);
    }

    public static string Base64StringToBinaryString(string base64String) {
        byte[] array = Convert.FromBase64String(base64String);
        return SidStringToBinaryString(new SecurityIdentifier(array, 0).ToString());
    }
}

Et un exemple d’utilisation :

    string mySid = 
        "S-1-5-21-3484020024-3719296819-3289906324-500";
    string myBinaryString = 
        "01050000000000051500000038EDA9CF33F7AFDD94FC17C4F4010000";
    string myBase64String = 
        "AQUAAAAAAAUVAAAAOO2pzzP3r92U/BfE9AEAAA==";

    string binaryString = SharePointUtils.SidStringToBinaryString(mySid);
    string sidString = SharePointUtils.BinaryStringToSidString(myBinaryString);
    string b64 = SharePointUtils.BinaryStringToBase64String(myBinaryString);
    binaryString = SharePointUtils.Base64StringToBinaryString(myBase64String);
}

Le coup du Linq dans les méthodes, c’est sur une idée d’Arnaud (perso, je l’avais joué à la McGyver, avec une boucle et un compteur…).

En espérant que ça puisse servir à quelqu’un d’autre.

Dom, bien aidé sur le coup d’Arnaud et Yo.

Currently rated 5.0 by 2 people

  • Currently 5/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


Définir un navigateur par défaut lors de son développement Web

clock August 20, 2009 07:55 by author crezenthel

Bonjour,  

Voici une petite astuce permettant de définir le navigateur par défaut dans VS lors d'un développement Web. 

-          Sélectionner dans le projet une page aspx        

-          Ensuite aller dans le menu Fichier/Naviguer avec  

 

-          Si vous ne trouvez pas votre navigateur dans la liste, faites « Ajouter »   

 

-          Indiquer le chemin de l’exécutable et nommer le.

-          Pour finir, choisir son navigateur et cliquer sur le bouton « Par défaut »

 

Et le tour est joué.

 

@+ Bientôt

Christophe REZENTHEL 

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


Outil de modélisation

clock May 19, 2009 06:05 by author yvue

Bonjour à tous,

Je suppose que vous êtes nombreux à chercher un outil de modélisation pratique (et eventuellement gratuit ;) )

Avec Alexandre, nous sommes tombés sur "OPEN MODELSPHERE" (http://www.modelsphere.com/modelsphere.html)

Ce petit soft sous licence GNU permet tres facilement de réaliser un MCD ou les schémas UML généralement utilisés (Use Case, Class Diagram, Sequence Diagram)

Vous remarquerez très rapidement sa facilité d'utilisation et surtout (vis à vis d'un AnalyseSI par exemple), on arrive à faire ce que l'on veut !!!!

A vos souris

 

Yoann Vue

 

 

Be the first to rate this post

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


Lorsque le Guid ne convient pas, le ShortGuid arrive à la rescousse

clock April 30, 2009 11:02 by author gcelet

Il arrive, dans certains scénario, que le Guid n'est pas adapté: il est trop long ou il n'est pas très joli! Mais lorsque l'on a gouté au Guid, il est difficile de s'en passer. Il existe un moyen de raccourcir un Guid: le ShortGuid!

Le ShortGuid s'utilise exactement de la même façon que le Guid:

ShortGuid shortGuidEmpty = ShortGuid.Empty; // Crée un ShortGuid vide
ShortGuid shortGuidA = ShortGuid.NewGuid(); // Crée un nouveau ShortGuid
Console.WriteLine("guidEmpty     : {0}", guidEmpty);
Console.WriteLine("shortGuidEmpty: {0}", shortGuidEmpty);
Console.WriteLine("shortGuidA    : {0}", shortGuidA);

Ce qui donne:

guidEmpty : 00000000-0000-0000-0000-000000000000
shortGuidEmpty: AAAAAAAAAAAAAAAAAAAAAA
shortGuidA    : 058fO04LSECNqoho_He67g

On peut convertir facilement le ShortGuid vers un Guid ou string:

Guid guidA = shortGuidA; // Convertit implicitement le ShortGuid en Guid
string stringA = shortGuidA; // Convertit implicitement le ShortGuid en String
Console.WriteLine("guidA         : {0}", guidA);

Ce qui donne:

guidA : 3b1f9fd3-0b4e-4048-8daa-8868fc77baee

Et inversement:

Guid guidB = Guid.NewGuid();
ShortGuid shortGuidB = guidB; // Convertit implicitement un Guid en ShortGuid
string stringC = "5Cqn2204Q0GTbI9dStW0fg";
ShortGuid shortGuidC = stringC; // Convertit implicitement une String en ShortGuid
Console.WriteLine("guidB         : {0}", guidB);

La comparaison avec le type Guid et String se fait naturellement:


Console.WriteLine("shortGuidA == shortGuidA: {0}", shortGuidA == shortGuidA);
Console.WriteLine("shortGuidA == shortGuidB: {0}", shortGuidA == shortGuidB);

Ce qui donne:

shortGuidA == guidEmpty: False
shortGuidA == shortGuidA: True
shortGuidA == shortGuidB: False

Voici le code de la classe ShortGuid:

/// <summary>
/// Represents a globally unique identifier (GUID) with a 
/// shorter string value. Sguid
/// </summary>
public struct ShortGuid : IComparable, IComparable<ShortGuid>, IComparable<Guid>, IComparable<string>
{
#region Static
/// <summary>
/// A read-only instance of the ShortGuid class whose value 
/// is guaranteed to be all zeroes. 
/// </summary>
public static readonly ShortGuid Empty = new ShortGuid(Guid.Empty);
#endregion
#region Fields
Guid _guid;
string _value;
#endregion
#region Contructors
/// <summary>
/// Creates a ShortGuid from a base64 encoded string
/// </summary>
/// <param name="value">The encoded guid as a 
/// base64 string</param>
public ShortGuid(string value)
{
_value = value;
_guid = Decode(value);
}
/// <summary>
/// Creates a ShortGuid from a Guid
/// </summary>
/// <param name="guid">The Guid to encode</param>
public ShortGuid(Guid guid)
{
_value = Encode(guid);
_guid = guid;
}
#endregion
#region Properties
/// <summary>
/// Gets/sets the underlying Guid
/// </summary>
public Guid Guid
{
get { return _guid; }
set
{
if (value != _guid)
{
_guid = value;
_value = Encode(value);
}
}
}
/// <summary>
/// Gets/sets the underlying base64 encoded string
/// </summary>
public string Value
{
get { return _value; }
set
{
if (value != _value)
{
_value = value;
_guid = Decode(value);
}
}
}
#endregion
#region ToString
/// <summary>
/// Returns the base64 encoded guid as a string
/// </summary>
/// <returns></returns>
public override string ToString()
{
return _value;
}
#endregion
#region Equals
/// <summary>
/// Returns a value indicating whether this instance and a 
/// specified Object represent the same type and value.
/// </summary>
/// <param name="obj">The object to compare</param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj is ShortGuid)
return _guid.Equals(((ShortGuid)obj)._guid);
if (obj is Guid)
return _guid.Equals((Guid)obj);
if (obj is string)
return _guid.Equals(((ShortGuid)obj)._guid);
return false;
}
#endregion
#region GetHashCode
/// <summary>
/// Returns the HashCode for underlying Guid.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return _guid.GetHashCode();
}
#endregion
#region NewGuid
/// <summary>
/// Initialises a new instance of the ShortGuid class
/// </summary>
/// <returns></returns>
public static ShortGuid NewGuid()
{
return new ShortGuid(Guid.NewGuid());
}
#endregion
#region Encode
/// <summary>
/// Creates a new instance of a Guid using the string value, 
/// then returns the base64 encoded version of the Guid.
/// </summary>
/// <param name="value">An actual Guid string (i.e. not a ShortGuid)</param>
/// <returns></returns>
public static string Encode(string value)
{
Guid guid = new Guid(value);
return Encode(guid);
}
/// <summary>
/// Encodes the given Guid as a base64 string that is 22 
/// characters long.
/// </summary>
/// <param name="guid">The Guid to encode</param>
/// <returns></returns>
public static string Encode(Guid guid)
{
string encoded = Convert.ToBase64String(guid.ToByteArray());
encoded = encoded
.Replace("/", "_")
.Replace("+", "-");
return encoded.Substring(0, 22);
}
#endregion
#region Decode
/// <summary>
/// Decodes the given base64 string
/// </summary>
/// <param name="value">The base64 encoded string of a Guid</param>
/// <returns>A new Guid</returns>
public static Guid Decode(string value)
{
value = value
.Replace("_", "/")
.Replace("-", "+");
byte[] buffer = Convert.FromBase64String(value + "==");
return new Guid(buffer);
}
#endregion
#region Operators
/// <summary>
/// Determines if both ShortGuids have the same underlying 
/// Guid value.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static bool operator ==(ShortGuid x, ShortGuid y)
{
if ((object)x == null) return (object)y == null;
return x._guid == y._guid;
}
/// <summary>
/// Determines if both ShortGuids do not have the 
/// same underlying Guid value.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static bool operator !=(ShortGuid x, ShortGuid y)
{
return !(x == y);
}
public static bool operator ==(ShortGuid x, Guid y)
{
if ((object)x == null) return (object)y == null;
return x._guid == y;
}
public static bool operator !=(ShortGuid x, Guid y)
{
return !(x == y);
}
public static bool operator ==(Guid x, ShortGuid y)
{
if ((object)x == null) return (object)y == null;
return x == y._guid;
}
public static bool operator !=(Guid x, ShortGuid y)
{
return !(x == y);
}
/// <summary>
/// Implicitly converts the ShortGuid to it's string equivilent
/// </summary>
/// <param name="shortGuid"></param>
/// <returns></returns>
public static implicit operator string(ShortGuid shortGuid)
{
return shortGuid._value;
}
/// <summary>
/// Implicitly converts the ShortGuid to it's Guid equivilent
/// </summary>
/// <param name="shortGuid"></param>
/// <returns></returns>
public static implicit operator Guid(ShortGuid shortGuid)
{
return shortGuid._guid;
}
/// <summary>
/// Implicitly converts the string to a ShortGuid
/// </summary>
/// <param name="shortGuid"></param>
/// <returns></returns>
public static implicit operator ShortGuid(string shortGuid)
{
return new ShortGuid(shortGuid);
}
/// <summary>
/// Implicitly converts the Guid to a ShortGuid 
/// </summary>
/// <param name="guid"></param>
/// <returns></returns>
public static implicit operator ShortGuid(Guid guid)
{
return new ShortGuid(guid);
}
#endregion
#region CompareTo
public int CompareTo(object other)
{
if (ReferenceEquals(other, null))
return 1;
if (other is ShortGuid)
return CompareTo((ShortGuid) other);
if (other is Guid)
return CompareTo((System.Guid) other);
if (other is string)
return CompareTo((string) other);
throw new ArgumentException("other");
}
public int CompareTo(ShortGuid other)
{
return _guid.CompareTo(other._guid);
}
public int CompareTo(Guid other)
{
return _guid.CompareTo(other);
}
public int CompareTo(string other)
{
return _value.CompareTo(other);
}
#endregion
}

Grégory Célet

ShortGuid.cs (8.73 kb)

Be the first to rate this post

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


Créer un Dictionary[string, List[T]] en LinqToObject ...

clock February 20, 2009 08:23 by author Xavier Masclet

.... ou comment créer un dictionnaire de "regroupement" a partir d'une liste simple.

Au départ on a en entrée : List<Communes> lesCommunes.

Et on voudrait créer un dictionnaire de ces meme communes ayant pour clé leur code postal. MAIS.... plusieurs communes pouvant avoir le meme code postal, on souhaiterait avoir en valeur non pas une Commune, mais une liste de communes. Autrement dit :

> Dictionary<string, List<Commune>>

 Ceci se fait via la requête suivante en utilisant la méthode d'extension ToDictionary<TKey, TSource>(...) :

var rqt = from c in lesCommunes
              group c by c.CodePostal into communes_par_CP
              select new { list = communes_par_CP };

Dictionary<string, List<Commune>> lesCommunesParCodePostal = rqt.ToDictionary(a => a.list.Select(b => b.CodePostal).First(), c => c.list.Select(y => y).ToList<Commune>());

 Et tant qu'à faire, autant pousser jusqu'au SortedDictionary....:

SortedDictionary<string, List<Commune>> lesCommunesParCodePostal = new SortedDictionary<string, List<Commune>>(rqt.ToDictionary(a => a.list.Select(b => b.CodePostal).First(), c => c.list.Select(y => y).ToList<Commune>()));

Be the first to rate this post

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


Héritage de classe générique sur une Window

clock January 21, 2009 04:38 by author Xavier Masclet
Par défaut en WPF les formulaires héritent de la classe System.Windows.Window.
Or il est peut être interessant de les faire hériter d'une classe tierse dans laquelle on factorise un certain nombre de choses (cette classe héritant elle même de System.Windows.Window pour que tout fonctionne bien).

Dans le cas de l'héritage d'un type simple il suffit de procéder comme suit :

1. On définit un type de base (à ajouter dans l'assembly contenant les formulaires ou dans une assembly connue de cette dernière)

namespace IHM.Common
{
   public class MyBaseWindow : Window

   {
      //...
   }
}

2. Il faut faire hériter notre formulaire de ce type

 - Coté code :

using IHM.Common;
namespace IHM.UI
{
   public class Window1 : MyBaseWindow
   {
      //...
   }
}

 - Et coté XAML : (et oui ! Le compilateur nous y oblige sous peine d'une erreur "Partial declarations of 'IHM.UI.Window1' must not specify different base classes")


   <src:MyBaseWindow
        x:Class="IHM.UI.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:src="clr-namespace:IHM.Common"
        Title="Une Fenetre"
        Height="300"
        Width="300">
   ...
   </src:MyBaseWindow>


Comment faire si maintenant nous souhaitons hériter d'une classe générique ?
En l'occurrence :

namespace IHM.Common
{
   public class MyBaseWindow<T> : Window

   {
      //...
   }
}

1. Coté code pas de soucis :

using IHM.Common;
using Rules;

namespace IHM.UI
{
   public class Window1 : MyBaseWindow<MyRule>
   {
      //...
   }
}

2. Coté XAML, petite subtilité avec l'utilisation de la propriété "TypeArguments" qui permet de spécifier le type générique à utiliser :

   <src:MyBaseWindow
        x:Class="IHM.UI.Window1"
        x:TypeArguments="r:MyRule"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:src="clr-namespace:IHM.UI"
        xmlns:r="clr-namespace:Rules;assembly=Rules"
        Title="Recherche de personnes"
        Height="300"
        Width="300">
   </src:MyBaseWindow>

Notez la déclaration du namespace : xmlns:r="clr-namespace:Rules;assembly=Rules" (préfixé par la lettre 'r')
qui permet au compilateur de retrouver notre type 'MyRule' dans la spécification du type générique : x:TypeArguments="r:MyRule"

Currently rated 4.3 by 3 people

  • Currently 4.333333/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


Calendrier

<<  July 2010  >>
MoTuWeThFrSaSu
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678
Afficher en pleine page

Visiteurs