web-dev-qa-db-fra.com

Utilisez-vous des types enum dans vos services Web WCF?

J'ai entendu certaines personnes dire que les énumérations sont diaboliques et ne devraient pas être utilisées dans les services Web en raison des incohérences pouvant survenir entre le serveur et le client si certaines valeurs sont attribuées ou si l'énumération est marquée avec les indicateurs attribut. Ils ont également déclaré que les services Web exposant les enums étaient plus difficiles à gérer mais ne pouvaient pas vraiment me donner des arguments viables. Ainsi, d’après votre expérience, quels sont les avantages et les inconvénients de l’utilisation d’énums dans un service Web WCF?

40
Darin Dimitrov

Les utilisateurs recommandent d'éviter les enums dans les services Web, car ils créent de subtils problèmes de compatibilité avec les versions antérieures.

Il en va de même pour les énumérations classiques, mais dans les services Web, le problème est encore plus évident, en particulier dans les mandataires générés par .NET (voir ci-dessous).

  • Si l'énumération est uniquement entrée, vous n'avez aucun problème.
  • Si l'énumération peut être un paramètre de sortie, si vous ajoutez un nouvel élément et que vous le renvoyez, les anciens clients risquent d'avoir des problèmes:
    • Si le client utilise un proxy généré par .NET, il sera interrompu avant que l'appelant puisse le gérer (dans la désérialisation).
    • Même si le code généré pour le proxy prend en charge la modification (par exemple, s'il mappe l'énumération sur une chaîne), le code utilisateur du client peut ne pas traiter correctement la nouvelle valeur inattendue (il peut facilement s'agir d'un chemin jamais exécuté).

En définissant le paramètre en tant que chaîne, vous signalez à l'utilisateur de votre API que la valeur peut changer à l'avenir. Même si vous pensez que la valeur ne changera jamais, c'est une bonne pratique d'être prêt.

Il y a un bon article de Dare Obasanjo sur ce sujet.

41
MMind

J'ai utilisé des énumérations dans WCF, également dans des scénarios d'interopérabilité. Si vous contrôlez les deux côtés du service, il est plus facile de travailler avec. Si vous ne contrôlez qu'un côté du service, vous avez besoin: faire attention aux problèmes que vous avez mentionnés.

Les énumérations sont tellement meilleures que les variables de chaîne ou ce que vous pourriez choisir d’utiliser. L’utilisation de chaînes au lieu d’énums est un modèle anti appelé «loosey Goosey» dans SOA.

17
khebbie

Les énumérations sont entièrement prises en charge dans WSDL et XSD via l'élément de schéma xsd:enumeration. Il fournit un support pour les énumérations de valeurs uniques et de style de drapeaux, où plusieurs valeurs dans une énumération de drapeaux sont séparées par des espaces.

Vous ne devriez donc avoir aucun problème à utiliser des énumérations avec des plates-formes conformes aux normes.

10
Greg Beech

Bien sûr, tout dépend de l'endroit où vous allez utiliser ce service WCF.

Si c'est une seule application qui l'utilisera, la modification du contrat n'aura aucun effet.

S'il s'agit de plusieurs applications internes, la modification du contrat peut nécessiter des modifications sur les autres applications.

Enfin, si le service WCF est public, vous devrez peut-être fournir 2 versions du service avec des versions différentes pour que les utilisateurs les consommant aient le temps de transférer leur version du client vers le nouveau service.

Tout dépend de vos besoins honnêtement.

3
Maxime Rouiller

Les énumérations dans les WSDL doivent être considérées comme une préoccupation pour la maintenance.

L'ajout ou la suppression d'une valeur d'énumération est (devrait être!) Un déclencheur pour une mise à jour majeure de l'interface. Si l'énum est une valeur de sortie, vous devez nécessairement définir une nouvelle version du WSDL à l'aide d'une nouvelle URI, afin d'empêcher les clients actuels de rompre le contrat établi ("Que se passe-t-il s'ils reçoivent l'une de ces nouvelles valeurs inattendues en retour?") Si l'énum est une valeur d'entrée, vous pouvez le considérer comme mineur update ("puisque les clients actuels n'auront pas besoin de connaître cette nouvelle valeur"), mais le seul moyen pour ces clients de bénéficier de l'ajout de cette nouvelle option/fonctionnalité (vous avez ajouté cette nouvelle valeur enum pour une raison, droit?) serait de leur demander de basculer, plus tard ou plus tôt, vers la nouvelle version de l'interface.

Et cela n’a pas à voir avec le sens fonctionnel de l’énum, ​​je pense.

Restez du côté des meilleures pratiques et vous serez en sécurité.

2
Zackatoustra

Utiliser autre chose que des énumérations ne résout pas votre problème de compatibilité, il ne fait que le masquer. Supposons que vous utilisez un int pour remplacer une énumération. Avez-vous vraiment résolu le problème de compatibilité ou l'avez-vous simplement masqué jusqu'à ce que l'exécution du client atteigne la valeur inconnue?

Cependant, il convient de mentionner une chose: les mandataires WCF ne recréent pas explicitement les valeurs numériques enum définies. Si l'énumération est déclarée avec "trous", comme

enum ErrorCodes
{
  OK = 0,
  GenericError = 100,
  SomeOtherError = 101,
}

la représentation côté client sera comme ça

enum ErrorCodes
{
  OK,
  GenericError,
  SomeOtherError,
}

... qui, sur le client, donne (int) ErrorCodes.GenericError égal à 1.

Vous aurez une équivalence syntaxique, mais pas une équivalence numérique.

2
BalintN

J'ai utilisé des énumérations dans mes services basés sur WCF sans aucun problème. Les problèmes que vous mentionnez sont certainement des éléments à prendre en compte, bien que si vous vous assurez d'appliquer des enums dans des situations relativement statiques, vous n'aurez probablement pas beaucoup de problèmes.

1
Kwal

Histoire du monde réel (les valeurs ont changé pour l'anonymat). Utiliser pour avoir une enum implicite dans l'application

public enum { orange, banana, mango }

Un peu de refactoring autour de l’ordre et de nouvelles valeurs, et nous décidons de le rendre explicite: 

public enum { orange=1, banana=2, grape=3, mango=4 }

semble inoffensif ...
La prochaine chose, un site Web explose. Scratch Head, vérifier le service, ajouter des messages de débogage, tout semble bien se passer.
En bas du terrier du lapin, un jour plus tard, il s’agit d’un service wcf de base qui utilisait l’énum en tant que type de retour.

Apparemment, Wcf n'aime pas les énumérations sans default value.

Réparer:

public enum { wcfBugBane=0, orange=1, banana=2, grape=3, mango=4 }

Alors ... ça pourrait te mordre.

0
Noctis

Voici une approche. Peut-être que c'est lourd. Je n'aime vraiment pas ne pas pouvoir utiliser d'énums.

Il gère gracieusement la désérialisation d'une valeur non reconnue, en renvoyant la valeur par défaut. La valeur par défaut doit être sûre - soit une solution de repli acceptable, soit un élément reconnu par l'application comme étant exceptionnel. (Comme "non spécifié.")

Les extensions évitent d'avoir à effectuer une vérification nulle avant la comparaison.

[DataContract]
public class EnumValue<T> where T : struct
{
    [DataMember]
    private string _raw = string.Empty;

    [IgnoreDataMember]
    private bool _parsed;

    [IgnoreDataMember]
    private T _parsedValue;

    public EnumValue()
    {
        Set(default(T));
    }

    public EnumValue(T value)
    {
        Set(value);
    }

    internal T Value
    {
        get
        {
            if (_parsed) return _parsedValue;
            if (!Enum.TryParse<T>(_raw, out _parsedValue))
            {
                _parsedValue = default(T);
            }
            _parsed = true;
            return _parsedValue;
        }
    }

    public void Set(T value)
    {
        _raw = value.ToString();
        _parsedValue = value;
        _parsed = true;
    }
}

public static class EnumValueExtensions
{
    public static T GetValue<T>(this EnumValue<T> enumValue) where T : struct
    {
        return enumValue == null ? default(T) : enumValue.Value;
    }

    public static bool EqualsValue<T>(this EnumValue<T> enumValue, T compareTo) where T : struct
    {
        return (enumValue.GetValue().Equals(compareTo));
    }
}
0
Scott Hannen