Question

J'ai googlé et lu pendant des heures maintenant et je ne peux pas trouver quelqu'un qui traite mon scénario spécifique ...

Je veux utiliser des interfaces dans mes contrats de service WCF pour coupler vaguement le service des classes utilisées à chaque extrémité du fil. Cela nous permettra d'avoir un ensemble de bas niveau qui ne contient que les contrats de service et de données (seulement les interfaces) que nous pouvons distribuer à un consultant. A leur extrémité du fil, ils peuvent instancier leurs classes de données qui mettent en œuvre nos données Interface contrat, nous l'envoyer sur le fil, et notre service WCF convertiront ensuite / CAST / whatever que les données entrantes dans notre version d'une classe de données qui implémente la même interface.

Voici un exemple. IDataContract contient les informations nues que je veux transmettre sur le fil. Les critères d'évaluation et d'autres config WCF spécifiques sont toutes choses par défaut (mes problèmes peuvent se situer dans ce que, pour que je puisse inclure plus si c'est là où je dois changer les choses).

EDIT : J'ai inclus plus du code et renomme un cours de couple pour aider ce soit moins confus. Le nom et les ajouts aux espaces de noms DataContractAttributes, ainsi que les deux sections dans les fichiers de configuration sont nouveaux ajouts à partir d'informations ce billet de blog . Si je passe à une classe de base abstraite au lieu d'une interface, il fonctionne . Cependant, je voudrais obtenir ce travail avec une interface si possible.

Bibliothèque partagée (mon code, partagé avec les auteurs du client):

public interface IDataContract
{
    string MyProperty { get; set; }
}
[ServiceContract]
public interface ITestService
{
    [OperationContract]
    IDataContract TestSharedInterface(IDataContract clientData);
}

Code client (la leur):

[DataContract(Name = "IDataContract", Namespace = "http://services.sliderhouserules.com")]
public class ClientDataClass : IDataContract
{
    [DataMember]
    public string MyProperty { get; set; }
}
private static void CallTestSharedInterface()
{
    EndpointAddress address = new EndpointAddress("http://localhost/ServiceContractsTest.WcfService/TestService.svc");
    ChannelFactory<ITestService> factory = new ChannelFactory<ITestService>("ITestService", address);
    ITestService proxy = factory.CreateChannel();
    ((IClientChannel)proxy).Open();

    IDataContract clientData = new ClientDataClass() { MyProperty = "client data" };
    IDataContract serverData = proxy.TestSharedInterface(clientData);
    MessageBox.Show(serverData.MyProperty);
}

config du client:

<system.runtime.serialization>
    <dataContractSerializer>
        <declaredTypes>
            <add type="ServiceContractsTest.Contracts.DataContracts.IDataContract, ServiceContractsTest.Contracts">
                <knownType type="ServiceContractsTest.WcfClient.ClientDataClass, ServiceContractsTest.WcfClient"/>
            </add>
        </declaredTypes>
    </dataContractSerializer>
</system.runtime.serialization>

code serveur (mine):

public class TestService : ITestService
{
    public IDataContract TestSharedInterface(IDataContract clientData)
    {
        ServerDataClass convertedClientData = (ServerDataClass)clientData;
        IDataContract serverData = new ServerDataClass() { MyProperty = convertedClientData.MyProperty + " + server data added" };
        return serverData;
    }
}
[DataContract(Name = "IDataContract", Namespace = "http://services.sliderhouserules.com")]
public class ServerDataClass : IDataContract
{
    [DataMember]
    public string MyProperty { get; set; }
}

config serveur:

<system.runtime.serialization>
    <dataContractSerializer>
        <declaredTypes>
            <add type="ServiceContractsTest.Contracts.DataContracts.IDataContract, ServiceContractsTest.Contracts">
                <knownType type="ServiceContractsTest.WcfService.ServerDataClass, ServiceContractsTest.WcfService"/>
            </add>
        </declaredTypes>
    </dataContractSerializer>
</system.runtime.serialization>

Je reçois une erreur de sérialisation sur l'appel client se plaignant de types connus. Est-ce que je manque juste des métadonnées balisage dans cette classe de client? Je suis à une perte à l'endroit où connaître même le problème même des mensonges, comme je l'ai essayé toutes les recherches que je peux penser et personne ne semble avoir traité ce scénario spécifique.

En fait, je veux ClientDataClass à serialize à <IDataContract><MyProperty>client data</MyProperty></IDataContract> puis être en mesure de désérialiser que dans une instance de ServerDataClass. Cela semble qu'il devrait être possible.

Était-ce utile?

La solution

Si vos contrats de données sont des interfaces WCF ne peuvent pas savoir quel objet à instancier pour une requête entrante. Il n'y a pas besoin de la classe pour être le même que dans le service, après tout le service Ajouter Référence lit le WSDL et génère de nouvelles classes sur la base d'informations de type dans le WSDL.

Autres conseils

Ce blog me donne la bonne direction pour trouver la solution à mon problème. En fait, j'ai exactement le même scénario comme sliderhouserules décrit dans son poste.

Mais dans mon scénario, je ne peux pas utiliser une classe abstraite ou une base pour Hériter de. Donc, j'ai utilisé une classe TypesHelper pour lire la section DataContractSerializer par moi-même et passer les types pertinents au service WCF.

namespace ExampleNamespace
{
  public interface IJustAInstance { }

  [ServiceContract]
  [ServiceKnownType("GetKnownTypes", typeof(ExampleNamespace.TypesHelper))]
  public interface ICreateInstance
  {
    IJustAInstance CreateInstance();
  }

  public static class TypesHelper
  {
    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    {
      DataContractSerializerSection section = (DataContractSerializerSection)
        ConfigurationManager.GetSection(
        "system.runtime.serialization/dataContractSerializer");
      if (dataContractSerializerSection != null)
      {
        foreach (DeclaredTypeElement item in dataContractSerializerSection.DeclaredTypes)
        {
          foreach (TypeElement innterItem in item.KnownTypes)
          {
            Type type = Type.GetType(innterItem.Type);
            if (typeof(IJustAInstance).IsAssignableFrom(type ))
              yield return type;
          }
        }
      }
    }
  }
}

Vous pouvez créer un BaseContract que votre ClientContract et ServerContract peuvent fournir (comme la propriété) et que vous pouvez utiliser dans le constructeur respectif lors de la création de nouvelles instances du ClientContract ou ServerContract. Ensuite, il suffit d'ajouter le BaseContract à votre lib partagée.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top