Frage

Ich habe gegoogelt und jetzt stundenlang lesen, und ich kann niemanden finden, die sich mit meinem speziellen Szenario ...

Ich mag Schnittstellen zu loses Paar in meinen WCF Serviceverträgen verwenden, um den Service von den an jedem Ende des Drahtes verwendeten Klassen. Dies wird es uns ermöglichen, ein Low-Level zu haben, Montag, die nur die Service- und Datenverträge enthält (nur Schnittstellen), dass wir zu einem Berater der Hand können. An ihrem Ende des Drahtes können sie ihre Datenklassen instanziiert, die unsere Daten Kontrakt-Schnittstelle implementieren, sie über den Draht zu uns senden, und unser WCF-Dienst wird dann übersetzen / cast / was auch immer, dass eingehende Daten in unser Version einer Datenklasse, dass Geräte die gleiche Schnittstelle.

Hier ist ein Beispiel. IDataContract enthält die bloßen Informationen, die ich den Draht übertragen über will. Die Endpunkte und andere WCF-spezifische Konfiguration sind all Standard-stuff (meine Probleme, dass liegen, so kann ich mehr davon enthalten, wenn das ist, wo ich Dinge ändern muß).

Bearbeiten : Ich habe mehr von Code enthalten und umbenannt ein paar Klassen, um ihm Hilfe weniger verwirrend. Der Name & Namespace Ergänzungen der DataContractAttributes, sowie die beiden Abschnitte in den Konfigurationsdateien sind neu basierend auf Informationen von diese Blog-Post . Wenn ich auf eine abstrakte Basisklasse statt einer Schnittstelle zu wechseln, es funktioniert . Ich möchte jedoch diese Arbeit mit einer Schnittstelle erhalten, wenn möglich.

Shared Library (mein Code, mit Client-Autoren gemeinsam):

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

Client-Code (das die):

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

Client config:

<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>

Server-Code (von mir):

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

Server config:

<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>

Ich erhalte eine Serialisierung Fehler auf der Anruf-Client über bekannte Typen beschweren. Fehle ich nur einige Metadaten-Markup in diesem Client-Klasse? Ich bin ratlos, wohin man auch das Problem sogar Lügen weiß, wie ich alle Such versucht habe ich denken kann, und niemand scheint mit diesem speziellen Szenario behandelt zu haben.

Grundsätzlich möchte ich ClientDataClass serialisiert zu <IDataContract><MyProperty>client data</MyProperty></IDataContract> und dann in der Lage sein, dass in einer ServerDataClass Instanz deserialisieren. Dies scheint, wie sollte es möglich sein.

War es hilfreich?

Lösung

Wenn Sie Ihre Datenverträge sind Schnittstellen WCF kann nicht wissen, was für eine eingehende Anfrage an instantiate Objekt. Es besteht keine Notwendigkeit für die Klasse die gleiche wie in den Dienst zu sein, nach all den Dienstverweis hinzufügen die WSDL liest und erzeugt neue Klassen basierend auf dem Typ Informationen in der WSDL.

Andere Tipps

Dieser Blog gibt mir die richtige Richtung, um die Lösung für mein Problem zu finden. Eigentlich habe ich genau das gleiche Szenario wie sliderhouserules beschreibt in seinem Beitrag.

Aber in meinem Szenario kann ich keine abstrakte oder Basisklasse erben verwenden aus. Also habe ich eine TypesHelper Klasse verwendet, um die DataContractSerializer Abschnitt von mir zu lesen und die entsprechenden Typen der WCF-Dienst übergeben.

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

Sie könnten eine BaseContract schaffen, dass Ihre ClientContract und ServerContract zur Verfügung stellen können (als Eigentum), und dass Sie in dem jeweiligen Konstruktor verwenden können, wenn neue Instanzen der ClientContract oder ServerContract zu schaffen. Dann müssen Sie nur die BaseContract zu Ihrem gemeinsamen lib hinzuzufügen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top