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?
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).
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.
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.
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.
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.
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é.
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.
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.
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.
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));
}
}