Используете ли вы типы enum в своих веб-сервисах WCF? - PullRequest
41 голосов
/ 28 ноября 2008

Я слышал, как некоторые люди говорят, что перечисления являются злыми и не должны использоваться в веб-службах из-за несоответствий, которые могут возникнуть между сервером и клиентом, если назначены некоторые значения, или если перечисление помечено знаком Флаги атрибут. Они также сказали, что веб-сервисы, выставляющие перечисления, сложнее поддерживать, но они не могли дать мне веских аргументов. Итак, из вашего опыта, каковы плюсы и минусы использования перечислений в веб-сервисе WCF?

Ответы [ 9 ]

41 голосов
/ 25 апреля 2009

Причина, по которой люди рекомендуют избегать перечислений в веб-сервисах, заключается в том, что они создают тонкие проблемы с обратной совместимостью.

То же самое относится к обычным перечислениям, но в веб-сервисах проблема еще более ясна, особенно в сгенерированных .NET прокси (см. Ниже).

  • Если перечисление вводится только у вас нет проблем.
  • Если перечисление может быть параметром out, то, если вы добавляете новый элемент и возвращаете его, у старых клиентов могут возникнуть проблемы:
    • Если клиент использует прокси-сервер, сгенерированный .NET, он сломается, прежде чем вызывающий может его обработать (при десериализации)
    • Даже если сгенерированный код для прокси-сервера поддерживает изменение (например, если он отображает перечисление в строку), пользовательский код на клиенте может не обрабатывать должным образом новое неожиданное значение (это может быть просто не выполненный путь)

Определяя параметр в виде строки, вы сообщаете пользователю вашего API, что значение может измениться в будущем. Даже если вы думаете, что значение никогда не изменится, это хорошая практика, чтобы быть готовым.

На эту тему есть хороший пост от Dare Obasanjo.

17 голосов
/ 17 декабря 2008

Я использовал перечисления в WCF, также в сценариях взаимодействия. Если вы контролируете обе стороны сервиса, с ним легче работать. Если вы контролируете только одну сторону службы, вам нужно обратить внимание на проблемы, которые вы упомянули.

Перечисления намного лучше, чем строковые переменные, или что еще вы можете использовать. Использование строк вместо перечислений - это анти-паттерн, называемый «слабый Goosey» в SOA.

10 голосов
/ 17 декабря 2008

Перечисления полностью поддерживаются в WSDL и XSD через элемент схемы xsd:enumeration. Он обеспечивает поддержку как отдельных значений, так и перечислений в стиле флагов, где несколько значений в перечислении флагов разделены пробелами.

Таким образом, у вас не должно возникнуть проблем с использованием перечислений на любых платформах, соответствующих стандартам.

3 голосов
/ 29 ноября 2008

Конечно, все зависит от того, где вы собираетесь использовать эту службу WCF.

Если это будет одно приложение, то изменение договора не будет иметь никаких последствий.

Если это несколько внутренних приложений, изменение договора может потребовать некоторых изменений в других приложениях.

И, наконец, если служба WCF является общедоступной, вам может потребоваться предоставить 2 версии службы с разными версиями, чтобы у людей, которые их потребляют, было время перенести свою версию клиента в новую службу.

Все зависит честно от ваших потребностей.

2 голосов
/ 16 января 2014

Использование чего-либо еще, кроме перечислений, не решает проблему совместимости, а только скрывает ее. Предположим, вы используете int для замены enum. Вы действительно решили проблему совместимости или просто замаскировали ее, пока время выполнения клиента не достигнет неизвестного значения?

Однако стоит упомянуть одну вещь: прокси-серверы WCF не воссоздают явно заданные числовые значения перечисления. Если enum объявлен с "дырками", как

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

представление на стороне клиента будет таким

enum ErrorCodes
{
  OK,
  GenericError,
  SomeOtherError,
}

... что на клиенте приводит к (int) ErrorCodes.GenericError, равному 1.

У вас будет синтаксическая эквивалентность, но не числовая эквивалентность.

2 голосов
/ 12 января 2012

Перечисления в WSDL должны рассматриваться как забота о техническом обслуживании.

Добавление или удаление значения перечисления является (должно быть!) Триггером для серьезного обновления интерфейса. Если перечисление является выходным значением, то вам обязательно нужно определить новую версию WSDL через новый URI, чтобы текущие клиенты не нарушали установленный контракт («что если они получат одно из этих новых, неожиданных значений в ответ») ? ") Если перечисление является входным значением, вы можете рассматривать это как незначительное обновление («поскольку текущие клиенты не должны знать об этом новом значении»), но тогда единственный способ для этих клиентов получить выгоду от добавления этого новая опция / функциональность (вы добавили это новое значение перечисления по какой-то причине, верно?) будет заключаться в том, чтобы попросить их переключиться позже или раньше на новую версию интерфейса.

И это не имеет никакого отношения к функциональному значению enum, я думаю.

Оставайтесь на стороне лучших практик, и вы будете в безопасности.

1 голос
/ 29 ноября 2008

Я без проблем использовал перечисления в моих службах на основе WCF. Возможные проблемы, о которых вы упомянули, безусловно, стоит учитывать, хотя если вы убедитесь, что применяете перечисления в довольно статичных ситуациях, у вас, вероятно, не будет особых проблем.

0 голосов
/ 17 апреля 2018

Реальная история (значения изменены для анонимности). Используется для неявного enum в приложении

public enum { orange, banana, mango }

Некоторый рефакторинг вокруг порядка и новых значений, и мы решили сделать это явным:

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

выглядит безобидно ...
Следующая вещь, веб-сайт взрывается. Почесать голову, проверить сервис, добавить отладочные сообщения, все вроде нормально.
Вниз по кроличьей норе, один день спустя, причиной является базовый сервис wcf, который использовал перечисление в качестве типа возврата.

Очевидно, Wcf не любит перечисления без значения по умолчанию .

Fix:

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

Так что ... это может вас укусить.

0 голосов
/ 30 декабря 2015

Вот подход. Может быть, это громоздко. Мне просто не нравится, когда я не могу использовать перечисления.

Изящно обрабатывает десериализацию нераспознанного значения, возвращая вместо него значение по умолчанию. Значение по умолчанию должно быть безопасным - либо приемлемый запасной вариант, либо что-то, что приложение может распознать как исключительное. (Например, «Не указано».)

Расширения исключают необходимость проверки на ноль перед сравнением.

[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));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...