3

次の(例)インターフェイスを備えたWCFサービスがあります。

[ServiceContract]
[ServiceKnownType(typeof(Foo))]
[ServiceKnownType(typeof(Bar))]
[ServiceKnownType(typeof(Baz))]
public interface IMyInterface
{
    [OperationContract]
    void ProcessMessage(Message message);

    [OperationContract]
    void ProcessMessages(IEnumerable<Message> messages);
}

FooBarおよびBazはすべて のタイプですMessage

またはオブジェクトを使用して WCF クライアントから呼び出すことができ、すべて正常に動作しProcessMessage()ます。ただし、これは失敗するため、配列(またはリストまたはその他)で呼び出すことはできません。FooBarBazProcessMessages(...)IEnumerable

パラメータhttp://tempuri.org/:messagesをシリアル化しようとしてエラーが発生しました 。InnerException メッセージは、「タイプ 'XXFoo' データ コントラクト名 'Foo: http://schemas.datacontract.org/2004/07/XX ' は想定されていません」でした。DataContractResolver の使用を検討するか、既知の型のリストに静的に認識されていない型を追加します。たとえば、KnownTypeAttribute 属性を使用するか、DataContractSerializer に渡される既知の型のリストにそれらを追加します。詳細については、InnerException を参照してください。

生成されたクライアント コードを見ると、次のように表示されreference.csます。

...
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyInterface/ProcessMessage", ReplyAction="http://tempuri.org/IMyInterface/ProcessMessageResponse")]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(X.X.Foo))]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(X.X.Bar))]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(X.X.Baz))]
void ProcessMessage(X.X.Message message);

...
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyInterface/ProcessMessages", ReplyAction="http://tempuri.org/IMyInterface/ProcessMessagesResponse")]
void ProcessMessages(X.X.Message[] messages);

ServiceKnownTypeAttributes が に追加されていることに気付きましたProcessMessageが、 ではありませんProcessMessagesServiceKnownTypeAttributeメソッドに同じs のセットを手動で追加し、をProcessMessages含む配列を使用してクライアントから呼び出すと、正常に動作します。FooBarBaz

Visual Studio で 2 番目のメソッドでもこれらの属性を生成するにはどうすればよいですか? 私がIMyInterface間違っていますか?[ServiceKnownType(typeof(...))]間違った場所に追加しましたか?どこで私は間違えましたか?

編集 おそらく、Messageクラスが "外部" アセンブリ (幸いなことに制御できます) にあり、Nuget パッケージにパッケージ化されていることを言及する必要があります。これは、WCF サービスとクライアントの両方で "再利用types...」オプションがこのアセンブリに対して有効になっています。

4

1 に答える 1

2

型が異なるアセンブリにある、および/または変更が難しいためMessage、これをクライアント アセンブリに配置して機能させることができます。

namespace X.X
{
    [KnownType(typeof(Foo))]
    public partial class Foo
    {
    }
    [KnownType(typeof(Bar))]
    public partial class Bar
    {
    }
    [KnownType(typeof(Baz))]
    public partial class Baz
    {
    }
}

(あなたがそれをひどく明白に言っているように見えることは知っていますが、うまくいきます。)

MessageFooBar、およびBazが同じアセンブリにある場合は、属性をクラスに追加するだけKnownTypeですMessage

[KnownType(typeof(Foo))]
[KnownType(typeof(Bar))]
[KnownType(typeof(Baz))]
public abstract class Message

そうすれば、クライアントに対して特別なことをする必要はありません。

また、あなたの動作を再現できる唯一の方法はMessage、独自のアセンブリを配置し、クライアント プロジェクトと WCF ライブラリ プロジェクトの両方からそれを参照し、[参照されたアセンブリで型を再利用する] チェックボックスを使用することでした。KnownTypeクラスがすべてクライアント側で生成される場合、一部が参照され、一部が生成されるのではなく、すべての属性がで生成されるため、はるかに簡単に機能しますMessage

于 2013-09-12T18:50:57.780 に答える