Frage

Wie würde ich den WCF-Dienst sagen, welche KnownTypes zu verwenden, wenn Daten vorbei an den Client zurück?

ich weiß, ich das [ServiceKnownType] Attribut verwenden, die den Service-Aufruf Lauf Fein von einem WCF-Testserver macht, aber es ist immer noch nicht aus dem Client. Bin ich etwas fehlt hier?

[OperationContract]
[ServiceKnownType(typeof(SubClassA))]
[ServiceKnownType(typeof(SubClassB))]
BaseClassZ GetObject();

Fehlermeldung vom Client ist:

  

{ "Element   'Http://schemas.datacontract.org/2004/07/BaseClassZ'   enthält die Daten von einem Typ, der abbildet   der Name   'Http://schemas.datacontract.org/2004/07/SubClassA'.   Der Deserializer hat keine Kenntnis von   jede Art, die diesem Namen zuordnet.   Betrachten wir ein DataContractResolver mit   oder fügen Sie den Typ entspricht   ‚SubClassA‘ in die Liste der bekannten Typen   - zum Beispiel durch das Knowntype Attribut oder durch   Hinzufügen zu der Liste der bekannten Typen   bestanden DataContractSerializer. "}

Serialisieren / Deserialisieren das Objekt auf dem WCF-Server eine DataContractSerializer und eine Liste des KnownTypes funktioniert gut mit.

UPDATE: Es scheint, ich den Client bekommen kann das Objekt korrekt zu lesen, wenn ich hinzufügen Knowntype auf die Basisklasse Attribute, aber ich bin noch auf der Suche nach einem Weg, um diese, wenn möglich, da die Basisklasse ist für viele Produkte verwendet und ich will nicht die Knowntype-Attribute auf der Basisklasse zu jeder Zeit ich ein neues Element hinzuzufügen.

haben zu ändern
[DataContract]
[KnownType(typeof(SubClassA))]
[KnownType(typeof(SubClassB))]
public class BaseClassZ 
{
    ...
}
War es hilfreich?

Lösung

Um zu vermeiden, Ihr Service-Code abzuschrecken setzte die bekannten Typen in web.config des Dienstes:

<system.runtime.serialization>
    <dataContractSerializer>
        <declaredTypes>
            <add type="SomeNs.BaseClassZ, SomeAssembly">
                <knownType type="SomeNs.SubClassA, SomeAssembly" />
                <knownType type="SomeNs.SubClassB, SomeAssembly" />
            </add>
        </declaredTypes>
    </dataContractSerializer>
</system.runtime.serialization>

Wenn Sie es durch Code tun mögen, müssen Sie dieses Attribut auf der Service-Schnittstelle verwenden und nicht auf der Arbeitsweise, aber ich würde den deklarativen Ansatz bevorzugen:

[ServiceContract]
[ServiceKnownType(typeof(SubClassA))]
[ServiceKnownType(typeof(SubClassB))]
public interface IFoo
{
    [OperationContract]
    BaseClassZ GetObject();
}

UPDATE:

Ich habe , welche die Verwendung von web.config ein Beispielprojekt setzt configure bekannten Typen, die meine ist bevorzugter Ansatz. Und ein anderes Beispielprojekt den zweiten Ansatz zu demonstrieren.


UPDATE 2:

Nach der Silverlight-Anwendung Client auf Ihrem aktualisierten Code sucht wir die folgende Definition bemerken:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.IService1")]
public interface IService1 {

    [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetMany", ReplyAction="http://tempuri.org/IService1/GetManyResponse")]
    System.IAsyncResult BeginGetMany(System.AsyncCallback callback, object asyncState);

    System.Collections.ObjectModel.ObservableCollection<MyCommonLib.BaseClassZ> EndGetMany(System.IAsyncResult result);

    [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetSingle", ReplyAction="http://tempuri.org/IService1/GetSingleResponse")]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassA))]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassB))]
    System.IAsyncResult BeginGetSingle(System.AsyncCallback callback, object asyncState);

    MyCommonLib.BaseClassZ EndGetSingle(System.IAsyncResult result);
}

Beachten Sie, wie die BeginGetSingle Methode die bekannte Art enthält Attribut, während die BeginGetMany Methode nicht den Fall ist. In der Tat sollten diese Attribute auf der Service-Definition platziert werden, so dass die Klasse sieht wie folgt aus.

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.IService1")]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassA))]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassB))]
public interface IService1
{
    [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetMany", ReplyAction="http://tempuri.org/IService1/GetManyResponse")]
    System.IAsyncResult BeginGetMany(System.AsyncCallback callback, object asyncState);

    System.Collections.ObjectModel.ObservableCollection<MyCommonLib.BaseClassZ> EndGetMany(System.IAsyncResult result);

    [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetSingle", ReplyAction="http://tempuri.org/IService1/GetSingleResponse")]
    System.IAsyncResult BeginGetSingle(System.AsyncCallback callback, object asyncState);

    MyCommonLib.BaseClassZ EndGetSingle(System.IAsyncResult result);
}

Da dies eine automatisch generierte Klasse ist es könnte ein Fehler in der SLsvcUtil.exe und svcutil.exe wie es das gleiche Verhalten zeigt. Setzt man die bekannte Art Attribute auf ihrem richtigen Platz löst das Problem. Das Problem ist, dass diese Klasse durch ein Werkzeug automatisch generiert wird und wenn Sie versuchen, es aus der WSDL zu regenerieren wird es vermasselt wieder.

So scheint es, dass, wenn Sie die folgende Service-Definition haben:

[ServiceContract]
[ServiceKnownType(typeof(SubClassA))]
[ServiceKnownType(typeof(SubClassB))]
public interface IService1
{
    [OperationContract]
    BaseClassZ[] GetMany();

    [OperationContract]
    BaseClassZ GetSingle();
}

Und die drei Datenverträge hier verwendet werden, zwischen dem Client und dem Server geteilt, wenn die Definition des Dienstes zu importieren, wobei das Verfahren, dass gibt eine Auflistung nicht die richtige bekannter Art-Attribute in dem generierten Client-Proxy bekommt. Vielleicht ist dies beabsichtigt.

Andere Tipps

Ich verbrachte Stunden heute auf das, was, so gut ich kann sagen, genau das gleiche Problem. Die Lösung war für mich die AddGenericResolver Methode von IDesign des ServiceModelEx Bibliothek zu verwenden.

Hinweis: .NET 4.0 erforderlich, da es verwendet DataContractResolver

Sie können es finden auf IDesign Downloads .

Alles, was ich in meinem Fall zu tun hatte, war die folgende Codezeile hinzu:

Client.AddGenericResolver( typeof ( K2Source ) );

Ich hoffe, das hilft jemand anderes da draußen sparen ein paar Stunden!

Sie können mehr Informationen in dem Buch finden "Programmieren WCF Dienstleistungen: Mastering WCF und der Azure AppFabric Service Bus" von Juval Löwy

Es gibt einen anderen Weg, dies zu tun. Anstatt mit „Dienstverweis hinzufügen“ können Sie die Proxy-Klassen codieren. Es ist ein wenig mehr Codierung zunächst aber gibt Ihnen eine viel stabilere und robuste Lösung. Wir haben herausgefunden, dass dies spart Zeit auf lange Sicht.

Siehe auch: http://www.dnrtv.com/default.aspx?showNum= 122

. Hinweis: Dies funktioniert nur, wenn Sie sowohl die Kontrolle über die Server und den Client

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