Вы используете типы перечислений в своих веб-службах WCF?

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


person Darin Dimitrov    schedule 28.11.2008    source источник


Ответы (9)


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

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

  • Если перечисление вводится только, у вас нет проблем.
  • If the enumerate can be an out parameter then if you add a new element and you return it, old clients could have problems:
    • If the client is using a .NET-generated proxy it will break before the caller can handle it (in the deserialization)
    • Даже если сгенерированный код для прокси-сервера поддерживал изменение (например, если он сопоставляет перечисление со строкой), пользовательский код в клиенте может некорректно обрабатывать новое неожиданное значение (это может легко быть неисполненным путем)

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

На эту тему есть хороший пост Дэра Обасанджо.

person MMind    schedule 25.04.2009
comment
В качестве обходного пути для обратной совместимости перечислений их можно объявить как [DataContract], и только старые значения установить как [DataMember], но оставить новые значения без атрибута. - person Michael Freidgeim; 15.04.2012
comment
Если enumerate вводится, только у вас нет проблем. Не совсем верно: если вы переименовали одно из значений, используемых сгенерированным .NET прокси, то старый клиент, отправивший вам старое имя, получит исключение когда серверу не удалось десериализовать значение. - person Richardissimo; 03.12.2019

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

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

person khebbie    schedule 17.12.2008

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

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

person Greg Beech    schedule 17.12.2008
comment
Обратная совместимость, упомянутая MMind, является серьезной проблемой, которую часто упускают из виду. - person Michael Freidgeim; 15.04.2012

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

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

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

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

Честно говоря, все зависит от ваших потребностей.

person Maxime Rouiller    schedule 28.11.2008

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

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

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

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

enum ErrorCodes
{
  OK,
  GenericError,
  SomeOtherError,
}

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

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

person BalintN    schedule 15.01.2014
comment
Не сохраняющиеся дыры были исправлены в более поздних версиях .Net (например, 4.5.1). - person user3085342; 14.07.2017

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

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

Я думаю, это не имеет отношения к функциональному значению перечисления.

Придерживайтесь передового опыта, и вы будете в безопасности.

person Zackatoustra    schedule 12.01.2012
comment
Перечисления могут быть объявлены как [DataContract] и только старые значения установлены как [DataMember], но новые значения оставлены без атрибута до нового ОСНОВНОГО выпуска - person Michael Freidgeim; 15.04.2012

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

person Kwal    schedule 28.11.2008

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

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

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

[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));
    }
}
person Scott Hannen    schedule 29.12.2015

Сюжет из реального мира (значения изменены на анонимность). Используйте, чтобы иметь неявный enum в приложении

public enum { orange, banana, mango }

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

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

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

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

Исправить:

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

Так ... это может тебя укусить.

person Noctis    schedule 17.04.2018