Я слышал, что некоторые люди говорили, что перечисления являются злыми и не должны использоваться в веб-сервисах из-за несоответствий между сервером и клиентом, если назначены некоторые значения, или если перечисление отмечено Flags. Они также сказали, что веб-сервисы, отображающие перечисления, сложнее поддерживать, но не могут действительно дать мне жизнеспособные аргументы. Итак, из вашего опыта, каковы плюсы и минусы использования перечислений в веб-службе WCF?
Используете ли вы типы перечисления в своих веб-службах WCF?
Ответ 1
Причина, по которой люди рекомендуют избегать перечислений в webservices, заключается в том, что они создают тонкие обратные проблемы.
То же самое относится к обычным перечислениям, но в веб-службах проблема особенно понятна специально в прокси-серверах .NET(см. ниже).
- Если перечисление введено только у вас нет проблем.
- Если перечисление может быть параметром out, то, если вы добавите новый элемент и вернете его, у старых клиентов могут возникнуть проблемы:
- Если клиент использует прокси-сервер .NET, он сломается до того, как вызывающий может обработать его (в десериализации)
- Даже если сгенерированный код прокси-сервера поддерживает изменение (например, если он отображает перечисление на строку), пользовательский код на клиенте может не обрабатывать должным образом новое неожиданное значение (это может быть легко никогда не исполняемый путь)
Определяя параметр как строку, вы сигнализируете пользователю вашего API, что значение может измениться в будущем. Даже если вы считаете, что значение никогда не изменится, это хорошая практика, чтобы быть готовой.
хороший пост от Dare Obasanjo по этой теме.
Ответ 2
Я использовал перечисления в WCF, также в сценариях совместимости. Если вы контролируете обе стороны службы, с ней проще работать. Если вы контролируете только одну сторону службы, вам нужно следить за проблемами, которые вы упомянули.
Перечисления намного лучше, чем строковые переменные или что еще вы можете использовать. Использование строк вместо перечислений - это анти-шаблон, называемый "сыпучий гуси" в SOA.
Ответ 3
Перечисления полностью поддерживаются в WSDL и XSD через элемент схемы xsd:enumeration
. Он обеспечивает поддержку как одиночных значений, так и индексов флагов, где несколько значений в перечислении флагов разделяются пробелами.
Таким образом, у вас не должно возникнуть проблемы с использованием перечислений с любыми стандартизованными платформами.
Ответ 4
Конечно, все зависит от того, где вы собираетесь использовать этот сервис WCF.
Если это одно приложение, которое будет его использовать, то изменение контракта не будет иметь никаких эффектов.
Если это несколько внутренних приложений, изменение контракта может потребовать некоторых изменений в других приложениях.
И, наконец, если служба WCF является общедоступной, вам может потребоваться предоставить 2 версии службы с разной версией, чтобы пользователи, потребляющие их, имели время для передачи своей версии клиента новой службе.
Все зависит от ваших потребностей честно.
Ответ 5
Перечисления в WSDL должны рассматриваться как проблема обслуживания.
Добавление или удаление значения перечисления является (должно быть!) триггером для основного обновления интерфейса. Если перечисление является выходным значением, вам обязательно нужно определить новую версию WSDL через новый URI, чтобы не допустить, чтобы текущие клиенты нарушили установленный контракт ( "что, если они получат эти новые неожиданные значения взамен?" ) Если перечисление является входным значением, вы можете рассматривать это как незначительное обновление ( "поскольку текущие клиенты не должны знать об этом новом значении" ), но тогда единственный способ для этих клиентов получить преимущество от добавления этого новая опция /functionnality (вы добавили это новое значение перечисления по какой-либо причине, верно?) было бы попросить их переключиться позже или раньше на новую версию интерфейса.
И это не связано с функциональным значением перечисления, я думаю.
Оставайтесь на стороне лучших практик, и вы будете в безопасности.
Ответ 6
Использование чего-либо другого, кроме перечислений, не решает проблему совместимости, оно только скрывает его. Предположим, вы используете int для замены перечисления. Вы действительно решили проблему совместимости или просто замаскировали ее до тех пор, пока время выполнения клиента не достигнет неизвестного значения?
Однако стоит упомянуть одно: прокси WCF не воссоздают явно установленные числовые значения перечисления. Если перечисление объявлено "дырками", например
enum ErrorCodes
{
OK = 0,
GenericError = 100,
SomeOtherError = 101,
}
представление на стороне клиента будет таким:
enum ErrorCodes
{
OK,
GenericError,
SomeOtherError,
}
... который на клиенте приводит к (int) ErrorCodes.GenericError, являющемуся 1.
У вас будет синтаксическая эквивалентность, но не числовая эквивалентность.
Ответ 7
Я использовал перечисления в моих службах на базе WCF без каких-либо проблем. Возможные проблемы, которые вы упомянули, - это, безусловно, все, что нужно учитывать, хотя, если вы убедитесь, что вы применяете перечисления в довольно статических ситуациях, у вас, вероятно, не будет больших проблем.
Ответ 8
Вот подход. Возможно, это громоздко. Мне просто не нравится, когда я не могу использовать перечисления.
Он грациозно обрабатывает десериализацию нераспознанного значения, вместо этого возвращает значение по умолчанию. Значение по умолчанию должно быть безопасным - либо приемлемый резерв, либо то, что приложение может признать исключительным. (Как "Unspecified." )
Расширения не позволяют проверять нуль перед сравнением.
[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));
}
}