2013-04-05 2 views
2

J'ai besoin d'appeler des opérations webservice en utilisant le standard wsdl, mais les objets de données doivent être différents dans le client et dans le serveur.Comment utiliser l'interface en tant que DataContract dans WCF

Utilisation d'interfaces pour les objets de données dans une bibliothèque commune, en créant des classes de proxy pour le client et le serveur. Puis, je déclare un contrat d'opération en utilisant l'interface, mais WCF ne le reconnaît pas.

J'ai pourtant essayé d'utiliser DataContractSerializerBehavior et de définir les types connus, pas encore de succès.

Quelqu'un peut-il m'aider? J'ai joint une solution complète avec plus de détails.

public interface Thing 
{ 
    Guid Id {get;set;} 
    String name {get;set;} 
    Thing anotherThing {get;set;} 
} 

[DataContract] 
public class ThingAtServer: BsonDocument, Thing // MongoDB persistence 
{ 
    [DataMember] 
    Guid Id {get;set;} 
    //... 
} 

[DataContract] 
public class ThingAtClient: Thing, INotifyPropertyChanged // WPF bindings 
{ 
    [DataMember] 
    Guid Id {get;set;} 
    //... 
} 

[ServiceContract] 
public interface MyService 
{ 
    [OperationContract] 
    Thing doSomething(Thing input); 
} 

Cliquez ici voyez un Sample project on GitHub avec TestCases

+0

Vous » ne montre pas comment 'Thing' est défini - a-t-il aussi' [DataContract] '? Qu'en est-il de '[BsonDocument]'? Généralement, vous devez définir des objets ** séparés **, légers (style DTO) pour les services WCF - n'héritez pas de choses comme une classe de base MongoDB - vous n'avez pas besoin ni ne voulez sérialiser tout cet état sur votre WCF un service.... –

+0

En outre: WCF est un système de transfert de messages basé sur XML - donc tout ce que vous transmettez dans WCF doit être représentable dans le schéma XML (XSD); les interfaces ne sont pas ** supportées par XSD - vous devez utiliser des ** classes concrètes ** (et les génériques ne sont pas supportés non plus ...) –

Répondre

2

J'ai créé service WCF avec contrat:

[OperationContract] 
CompositeTypeServer GetDataUsingDataContract(CompositeTypeServer composite); 

Mon CompositeTypeServer ressemble à ceci:

[DataContract(Namespace = "http://enes.com/")] 
public class CompositeTypeServer 
{ 
    [DataMember] 
    public bool BoolValue { get; set; } 

    [DataMember] 
    public string StringValue { get; set; } 
} 

Puis j'ai créé cl projet ient avec le type CompositeTypeClient:

[DataContract(Namespace = "http://enes.com/")] 
public class CompositeTypeClient 
{ 
    [DataMember] 
    public bool BoolValue { get; set; } 

    [DataMember] 
    public string StringValue { get; set; } 
} 

J'ai ajouté la référence à mon service et choisi de réutiliser les types. Tout a fonctionné comme le charme. J'ai pu utiliser CompositeTypeClient du côté client. Donc, l'astuce consistait à spécifier l'espace de noms pour DataContract afin qu'ils correspondent à la fois sur le client et le service.

[DataContract(Namespace = "http://enes.com/")] 

PS. Je peux fournir la pleine solution de fonctionnement de VS sur demande.

0

Basé sur ServiceKnownTypeAttribute (MSDN documentation), j'ai changé les types attendus en fonction de la situation. L'idée principale est mise en œuvre dans la classe XHelper, responsable de retourner la Type[] correcte selon la situation:

public static class XHelper 
{ 

    public static Boolean? IsClient = null; 
    public static Type[] ClientTypes; 
    public static Type[] ServerTypes; 

    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider pProvider) 
    { 
     if (!IsClient.HasValue) 
      throw new Exception("Invalid value"); 
     if (IsClient.Value) 
      return ClientTypes; 
     return ServerTypes; 
    } 
} 

Vous devez inclure la balise ServiceKnownType dans l'interface qui a le ServiceContract savoir XHelper classe.

[ServiceContract(Namespace = MyProxyProvider.MyNamespace)] 
[ServiceKnownType("GetKnownTypes", typeof(XHelper))] 
public interface MyService 
{ 
    [OperationContract] 
    Thing2 CopyThing(Thing1 input); 
} 

Au début de l'unité de test, qui a été informé du droit Type[] pour chaque situation:

[AssemblyInitialize] 
    public static void TestInitialize(TestContext pContext) 
    { 
     XHelper.ClientTypes = new Type[] { typeof(Thing1ProxyAtClient), typeof(Thing2ProxyAtClient), typeof(Thing2ProxyAtClient) }; 
     XHelper.ServerTypes = new Type[] { typeof(Thing1ProxyAtServer), typeof(Thing2ProxyAtServer), typeof(ThingNProxyAtServer) }; 
    } 

Cliquez ici ne voir le code final Sample project on GitHub avec TestCases