2009-03-25 21 views
12

Sto cercando di creare un servizio WCF in grado di memorizzare/recuperare una gamma di tipi diversi. è la seguente esempio lavorabile e anche considerato il design accettabile:Polimorfismo in WCF

[ServiceContract] 
public interface IConnection 
{   
    [OperationContract] 
    IObject RetrieveObject(Guid ObjectID); 

    [OperationContract] 
    Guid StoreObject(IObject NewObject); 


} 

[ServiceContract] 
[ServiceKnownType(IOne)] 
[ServiceKnownType(ITwo)] 
public interface IObject 
{ 
    [DataMember] 
    Guid ObjectID; 

} 

[ServiceContract] 
public interface IOne:IObject 
{ 
    [DataMember] 
    String StringOne; 

} 

[ServiceContract] 
public interface ITwo:IObject 
{ 
    [DataMember] 
    String StringTwo; 

} 

Quando si utilizza il servizio, avrei bisogno di essere in grado di passare i tipi bambino nel metodo storeObject e farli tornare come il loro tipo di bambino dal RetrieveObject metodo.

Ci sono opzioni migliori?

Grazie, Rob

risposta

17

Il tuo esempio non viene compilato perché le interfacce non possono contenere campi, che è quello che ObjectID, StringOne e StringTwo sono. Quello che stai cercando di definire con IObject, IOne e ITwo è un contratto di dati, non un contratto di servizio. Pertanto, dovresti utilizzare l'attributo DataContract, non l'attributo e le classi ServiceContract, non le interfacce.

[DataContract] 
[KnownType(typeof(MyOne))] 
[KnownType(typeof(MyTwo))] 
public class MyObject 
{ 
    [DataMember] 
    Guid ObjectID; 
} 
[DataContract] 
public class MyOne : MyObject 
{ 
    [DataMember] 
    String StringOne; 
} 
[DataContract] 
public class MyTwo : MyObject 
{ 
    [DataMember] 
    String StringTwo; 
} 

Si noti che queste sono classi, non interfacce. L'attributo DataContract ha sostituito l'attributo ServiceContract. L'attributo KnownType ha sostituito l'attributo ServiceKnownType. Questo è più canonico da quello che ho visto.

Il tuo contratto di servizio sarebbe quindi essere definito in questo modo:

[ServiceContract] 
public interface IConnection 
{ 
    [OperationContract] 
    [ServiceKnownType(typeof(MyOne))] 
    [ServiceKnownType(typeof(MyTwo))] 
    MyObject RetrieveObject(Guid ObjectID); 

    [OperationContract] 
    [ServiceKnownType(typeof(MyOne))] 
    [ServiceKnownType(typeof(MyTwo))] 
    Guid StoreObject(MyObject NewObject); 
} 

È possibile inserire il ServiceKnownType attributi a livello di contratto (vale a dire, sotto l'attributo ServiceContract) per averlo si applicano a tutte le operazioni del contratto.

[ServiceContract] 
[ServiceKnownType(typeof(MyOne))] 
[ServiceKnownType(typeof(MyTwo))] 
public interface IConnection 
{ 
    [OperationContract] 
    MyObject RetrieveObject(Guid ObjectID); 

    [OperationContract] 
    Guid StoreObject(MyObject NewObject); 
} 

È possibile uso interfacce nei vostri contratti dati come questo:

interface IEmployee 
{ 
    string FirstName 
    { get; set; } 
    string LastName 
    { get; set; } 
} 
[DataContact] 
class Employee : IEmployee 
{...} 

Tuttavia, l'interfaccia IEmployee non è incluso nei metadati esportato. Quindi se usi svcutil per generare le tue classi proxy, i tuoi clienti non sapranno nulla di IEmployee. Questo non è un grosso problema se il tuo servizio e il tuo cliente risiedono nella stessa applicazione (che è un buon modo per comunicare tra domini app). Tuttavia, se il tuo cliente è separato dal tuo servizio (nella stragrande maggioranza dei casi, lo sarà), questo diventa problematico perché dovrai duplicare manualmente l'interfaccia IEmployee sul lato client.

+0

È possibile fare un esempio concreto di come utilizzare l'interfaccia IEmployee di cui si parla, con WCF? – Kenci

+0

@ Davis Davis, una cosa è la mancanza :) Forse un pezzo di xml? –