Флаги с веб-сервисами

У меня есть перечисление атрибута флага, которое находится за веб-службой следующим образом:

[Serializable,Flags]
public enum AccessLevels
{
    None = 0,
    Read = 1,
    Write = 2,
    Full = Read | Write
}

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

{
   None = 1,
   Read = 2,
   Write = 4,
   Full = 8
}

И, таким образом, когда потребитель проверяет доступ "Чтение", это будет ложным, даже если "testItem" является "Полный"

((testItem & Svc.Read) == Svc.Read)

Как я могу правильно предоставлять флаги через веб-службу?

EDIT:

Согласно этой статье, возможно, не удастся сделать то, что я ищу. Иван Кривяков утверждает, что

Несовершенная прозрачность перечислений

Оказалось, что перечисления не такие, как как мы хотели бы, чтобы они были. Есть три липких вопроса:

  • Если код на стороне сервера объявляет перечисление и назначает определенный числовой значения для его членов, эти значения не будет виден клиенту.
  • Если код на стороне сервера объявляет перечисление [Flags] с "составной" маской значения (как в White = Red | Green | Blue), это неправильно отражено на клиентская сторона.
  • Если сервер или клиент передает "незаконное" значение, которое находится за пределами объем перечисления, он вызывает исключение в XML-де-сериализаторе на другая сторона.

Так что я задаюсь вопросом, является ли это просто ограничением и не возможно.

Ответ 1

Я провел обширные исследования по этому вопросу и обнаружил, что невозможно сериализовать константы перечисления через веб-службу. Обратите внимание, что для достижения вашей цели вам не нужны перечисления None или Full. Эти два перечисления могут подразумеваться с помощью комбинации чтения/записи:

Вы можете использовать полный доступ, если ваш AccessLevels = Read | Написать  и нет, если ваши AccessLevels = 0 [ничего]

Ваши перечисления будут выглядеть так:

[Serializable,Flags]
public enum AccessLevels
{
    Read = 1,
    Write = 2
}

Ответ 2

У меня была аналогичная проблема и обошел ее, добавив еще одну веб-службу, чтобы сначала вернуть значения флагов.

Затем они стали значениями, которые я использовал в сравнении.

Возможно, это не чистое решение, но оно работает.

Edit:

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

Однако, выкалывая, кажется, что перечисление 0,1,2, сопоставленное с 1,2,4 через веб-службу (даже если установлено значение атрибута [Flags]), является общей проблемой.

Решение, предлагаемое рядом людей, состоит в том, чтобы изменить исходное определение перечисления и начать с 1, а не 0.

Ответ 3

Флаги должны быть кратными двум, а в вашем случае ваши флаги (0,1,2,3). Попробуйте изменить свое определение структуры следующим образом:

[Serializable,Flags]
public enum AccessLevels{    
None = 1,    
Read = 2,    
Write = 4,    
Full = Read | Write}

И посмотрите, работает ли он лучше.

(Надеюсь, я не сделаю себе дурака, его поздно и Im на пути к кровати..)

Ответ 4

Один из вариантов - предоставить более подробный класс вместо enum, например.

[Serializable]
public class AccessPermission{
 public boolean None{get;set;}
 public boolean Read{get;set;}
 public boolean Write{get;set;}
 public boolean Full{get;set;}

 public AccessPermission(AccessLevels level){
  None = false;
  Read = false;
  Write = false;
  Full = false;

  switch(level){
  case AccessLevels.None:
   break;
  case AccessLevels.Read:
   Read = true;
   break;
  case AccessLevels.Write:
   Write = true;
   break;
  case AccessLevels.Full:
   Read = true;
   Write = true;
   Full = true;
   break;
  }
 }
} 

Другим вариантом, который я могу видеть, является предоставление метода в том, какой язык используется для успешного взаимодействия целого, которое вы отправляете. Оператор флага означает, что С# выполняет маскировку бит, чтобы определить, отмечен ли отдельный флаг

0001 -> None
0010 -> Read
0100 -> Write
0110 -> Full

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


public static boolean CanRead(int accessLevel){
 return (accessLevel | 2) > 0 // return true if read bit set, using bitwise or
}

public static boolean CanWrite(int accessLevel){
 return (accessLevel | 4) > 0 // return true of write bit set.
}

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