2010-08-25 15 views
17

Sto provando a creare manualmente un servizio dati WCF utilizzando un modello di dati POCO e non riesco a capire come esporre correttamente i valori enum. Assumendo un modello semplice come:Utilizzo di enumerazioni nei servizi dati WCF

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

public enum OrderStatus 
{ 
    New, 
    InProcess, 
    Complete 
} 

Come si espone le preziose informazioni nella proprietà OrderStatus tramite il servizio dati OData WCF?

Se non si esegue alcuna operazione, il servizio dati genera un errore di runtime (enum non è una proprietà valida). L'unica risposta che ho visto che almeno risolve l'errore è quello di marcare la proprietà enum come Ignorato, come ad esempio:

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

Questo funziona, ma ti costringe a "omettere" preziose informazioni dal livello di servizio. Ci sono altre opzioni per lavorare con i valori enum in WCF Data Services?

EDIT: Si prega di notare questo è WCF Data Services (aka Astoria). Non si tratta di servizi WCF grezzi, nel qual caso le risposte sono più chiare.

+0

Si consiglia di evitare le enumerazioni in webservices perché creano problemi all'indietro compatibili sottili. Vedi http://stackoverflow.com/a/788281/52277 –

risposta

16

Enums non sono attualmente supportati in WCF Data Services (il protocollo OData non li supporta neanche). La tipica soluzione alternativa consiste nell'utilizzare valori stringa e costanti o interi e valori costanti.

+0

Avevo paura di ciò. Felice di avere una chiara conferma almeno. Sto provando alcune soluzioni alternative per "wrapper", quindi non devo apportare grandi modifiche al mio modello solo per utilizzare i servizi dati. Speriamo che uno dei workaround funzionerà! – Todd

+1

@Vitek: Gli Enum sono un costrutto di programmazione tremendamente comune, ed è un bizzarro passo indietro non usarli. Ci sono piani per includere il supporto enum nelle versioni future dello standard OData, oppure i servizi dati WCF forniranno supporto opzionale quando entrambe le estremità sono note nello stack MSFT? –

+0

Capiamo che le enumerazioni sono comuni, sfortunatamente non hanno mai incontrato il bar fino ad ora. Sono piuttosto in alto nella nostra lista di cose da fare dopo però. –

0

È necessario rendere l'enum un contratto di dati.

Vedi qui per un esempio: http://consultingblogs.emc.com/merrickchaffer/archive/2007/04/03/Passing-Enum-values-into-WCF-Service-operations.aspx

[Edit] A quanto pare, che non è sempre il caso come si vede qui: Sharing Enum with WCF Service

+0

Grazie per l'input rapido, ma penso che ti sia sfuggito che si tratta di servizi di dati WCF, non di un semplice WCF.Ho provato i tipici attributi DataContract/EnumMember, ma non sembrano funzionare con WCF Data Services (aka Astoria). – Todd

2

Supponendo DataContract serializzazione, in questo modo:

[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 
} 
+0

Generalmente funziona per i servizi WCF semplici, ma in questo caso sto chiedendo informazioni su WCF Data Services (precedentemente noto come Astoria). Nei miei test, questa soluzione NON funziona per l'utilizzo di enumerazioni in Data Services. Hai provato questo con i servizi dati WCF? – Todd

+0

Oops - apols. C'è un brutto attacco nei link sul post di Troy che potrebbe funzionare per voi - aggiungere un int extra serializzabile all'entità e quindi lanciare l'enum al getter/setter (ma ignorare l'enum) – StuartLC

5

forse possiamo "barare" con la seguente soluzione:

[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 
} 
+0

Molto vicino alla soluzione finale che ho usato! – Todd

5

Come follow-up, l'approccio "wrapper" è in definitiva ciò che ha funzionato. In sostanza, una piccola classe viene scritto per avvolgere il enum e tornare primitivi int valori in Data Service:

[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; 
    } 
} 

Questo è stato in gran parte basato sul consiglio dato per lavorare intorno enum limiti di EF4:

http://blogs.msdn.com/b/alexj/archive/2009/06/05/tip-23-how-to-fake-enums-in-ef-4.aspx

Spero che questa tecnica aiuti gli altri che seguono.

+3

Sostituisci _s con _t – Pakman

+0

Todd, non riesco a capire come usare questo wrapper ... puoi elaborare? –

0

è necessario scrivere proprio 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; 
    } 
+0

E 'veramente per un servizio dati Wcf? Se sì, potresti fornire maggiori dettagli su come ottenere questo risultato? – Jerther

Problemi correlati