Использование перечислений в службах передачи данных WCF

17

Я пытаюсь вручную создать службу данных WCF с использованием модели данных POCO, и я не могу понять, как правильно выставлять enum . Предположим, что простая модель:

public class Order
{
   public int ID {get; set;}
   public string Description {get; set;}
   public OrderStatus Status {get; set;}
}

public enum OrderStatus
{
   New,
   InProcess,
   Complete
}

Как вы можете предоставить ценную информацию в свойстве OrderStatus через службу данных OData WCF?

Если вы ничего не делаете, Служба данных генерирует ошибку времени выполнения (enum is invalid property). Единственный ответ, который я видел, по крайней мере, разрешает ошибку: отметьте свойство enum как Ignored, например:

[System.Data.Services.IgnoreProperties("Status")]
public class Order ...

Это работает, но это заставляет вас «опускать» ценную информацию с уровня сервиса. Существуют ли другие варианты работы с значениями перечисления в службах данных WCF?

РЕДАКТИРОВАТЬ: Обратите внимание, что это службы передачи данных WCF (aka Astoria). Это не сырые службы WCF, и в этом случае ответы более ясны.

    
задан Todd 25.08.2010 в 23:12
источник
  • Рекомендуется избегать перечислений в веб-службах, поскольку они создают тонкие обратные проблемы. См. Stackoverflow.com/a/788281/52277 –  Michael Freidgeim 21.07.2013 в 12:04

6 ответов

16

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

    
ответ дан Vitek Karas MSFT 26.08.2010 в 02:59
  • Я боялся этого. Счастлив хотя бы ясным подтверждением. Я пытаюсь обходные методы обертки, поэтому мне не нужно вносить большие изменения в мою модель только для использования служб данных. Надеемся, что один из способов обхода будет работать! –  Todd 26.08.2010 в 06:41
  • @Vitek: перечисления представляют собой чрезвычайно распространенную конструкцию программирования, и это странный шаг назад, чтобы не использовать их. Существуют ли какие-либо планы по включению поддержки перечислений в будущие версии стандарта OData или будут ли службы WCF Data Services предоставлять дополнительную поддержку, если известно, что оба конца находятся в стеке MSFT? –  Eric J. 06.02.2012 в 06:31
  • Мы понимаем, что перечисления распространены, к сожалению, они до сих пор не встречались с баром. Они довольно высоки в нашем списке вещей, которые нужно сделать дальше. –  Vitek Karas MSFT 06.02.2012 в 10:43
  • @Vitek: Я опубликовал более общую версию этого вопроса и был бы признателен за любую проницательность, которую вы можете предложить stackoverflow.com/questions/3570249/... BTW, несмотря на некоторые грубые грани, я большой поклонник работы MSFT делает в этой области. –  Eric J. 08.02.2012 в 01:11
  • Ссылка в вашем комментарии указывает на этот вопрос, не могли бы вы отплатить рифту? :-) –  Vitek Karas MSFT 08.02.2012 в 13:57
Показать остальные комментарии
5

Может быть, мы можем «обмануть» его с помощью обходного пути ниже:

[System.Data.Services.IgnoreProperties("Status")]
public class Order
{
   public int ID {get; set;}
   public string Description {get; set;}
   public OrderStatus Status {get; set;}
   public int StatusValue
   {
      get
      {
           return (int)this.Status;
      }
      set
      {
          // Add validation here
          this.Status = (OrderStatus)value;
      } 
   }
}

public enum OrderStatus
{
   New,
   InProcess,
   Complete
}
    
ответ дан Boris Modylevsky 26.08.2010 в 16:07
  • Очень близко к окончательному решению, которое я использовал! –  Todd 27.08.2010 в 23:56
5

Как следствие, подход «обертка» в конечном итоге работает. По существу, небольшой класс записывается, чтобы обернуть enum и вернуть примитивы int в службе данных:

[IgnoreProperties("EnumValue")]
public class OrderStatusWrapper
{
    private OrderStatus _t;

    public int Value
    {
        get{ return (int)_t; }
        set { _t = (OrderStatus)value; }
    }

    public OrderStatus EnumValue
    {
        get { return _t; }
        set { _t = value; }
    }

    public static implicit operator OrderStatusWrapper(OrderStatus r)
    {
        return new OrderStatusWrapper { EnumValue = r };
    }

    public static implicit operator OrderStatus(OrderStatusWrapper rw)
    {
        if (rw == null)
            return OrderStatus.Unresolved;
        else
            return rw.EnumValue;
    }
}  

В основном это было основано на рекомендациях по работе с ограничениями enum EF4:

Ссылка

Надеюсь, что этот метод поможет другим, которые следуют.

    
ответ дан Todd 27.08.2010 в 23:55
  • Заменить _s с помощью _t –  Pakman 14.03.2012 в 21:27
  • Тодд, я не могу понять, как использовать эту обертку ... можете ли вы уточнить? –  Stephen Chung 03.07.2014 в 14:45
2

Предполагая DataContract Serialization, например:

[DataContract]
public class Order
{
   [DataMember]
   public int ID {get; set;}
   [DataMember]
   public string Description {get; set;}
   [DataMember]
   public OrderStatus Status {get; set;}
}

[DataContract]
public enum OrderStatus
{
    [EnumMember]
    New,
    [EnumMember]
    InProcess,
    [EnumMember]   
    Complete
}
    
ответ дан StuartLC 25.08.2010 в 23:18
  • Это обычно работает для обычных служб WCF, но в этом случае я спрашиваю о службах данных WCF (ранее называвшихся Astoria). В моих тестах это решение НЕ работает для использования перечислений в Data Services. Вы тестировали это с помощью служб передачи данных WCF? –  Todd 25.08.2010 в 23:34
  • Упс - отступает. В ссылках на сообщение Троя есть грязный хак, который может сработать для вас - добавьте в объект дополнительный сериализуемый int, а затем перечислите перечисление в getter / seters (но проигнорируйте перечисление) –  StuartLC 25.08.2010 в 23:43
0

Вам нужно сделать перечисление Контрактом данных.

См. здесь пример: Ссылка

[Edit] По-видимому, это не всегда так, как показано здесь: Совместное использование с помощью службы WCF

    
ответ дан Troy Guinn 25.08.2010 в 23:16
  • Спасибо за быстрый ввод, но я думаю, вы пропустили, что это службы данных WCF, а не обычный WCF. Я пробовал типичные атрибуты DataContract / EnumMember, но они, похоже, не работают с службами данных WCF (он же Astoria). –  Todd 25.08.2010 в 23:35
0

Вам нужно написать собственный QueryPrivider

    public object GetPropertyValue(object target, ResourceProperty resourceProperty)
    {
        object result = null;
        PropertyInfo info = target.GetType().GetProperty(resourceProperty.Name);
        if (info != null)
            result = info.GetValue(target, null);
        if (result is Enum)
            return Convert.ToInt32(result);
        return result;
    }


    public ResourceType GetResourceType(object target)
    {
        ResourceType result = null;
        Type tp = target.GetType();
        if (tp.IsEnum)
        {
            result =  ResourceType.GetPrimitiveResourceType(typeof(Int32));
            return result;
        }
        ....
        return result;
    }
    
ответ дан Slava 09.12.2011 в 10:26
  • Действительно ли это для службы данных WAT? Если да, не могли бы вы дать более подробную информацию о том, как это сделать? –  Jerther 26.11.2014 в 18:02