6

WCF Soap サービスのメソッドを呼び出すと、エラーがスローされ、svlog ファイルに次のエラーが表示されます。

タイプ 'xxx.ActiveDirectoryService.classes.WCF.Message' データ コントラクト名 'Message: http://schemas.datacontract.org/2004/07/xxx.ActiveDirectoryService.classes.WCF ' は想定されていません。DataContractResolver の使用を検討するか、既知の型のリストに静的に認識されていない型を追加します。たとえば、KnownTypeAttribute 属性を使用するか、DataContractSerializer に渡される既知の型のリストにそれらを追加します。

あちこちで KnownType を使用しようとしましたが、成功しませんでした (その使用法が 100% 正しいかどうか確信が持てないことを認めなければなりません)。

ここに私のインターフェイス/クラスがあります:

[ServiceContract]
public interface IActiveDirectory
{
    [OperationContract]
    [WebGet]
    void Dummy();

    [OperationContract]
    [WebGet]
    AbstractMessage Dummy2();

    [OperationContract]
    [WebGet]
    AbstractMessage Dummy3();

    [OperationContract]
    [WebGet]
    AbstractMessage SetPassWord(string customer, string customerPassword, string userLogin, string userPassword);
}

[DataContract]
public abstract class AbstractMessage
{
    [DataMember]
    public virtual bool IsError { get; set; }

    [DataMember]
    public virtual string ErrorMessage { get; set; }

    [DataMember]
    public virtual string ReturnValue { get; set; }
}

public class Message : AbstractMessage
{
<...>
}


[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
[KnownType(typeof(AbstractMessage))]
public class ActiveDirectory : IActiveDirectory
{
    public void Dummy()
    {
    }

    public AbstractMessage Dummy2()
    {
        return new AbstractMessage();
    }

    public AbstractMessage Dummy3()
    {
        return new Message();
    }

    public AbstractMessage SetPassWord(string customer, string customerPassword, string userLogin, string userPassword)
    {
    <...>

        return message; // message is of type Message
    }
}

編集: 12AM35 GMT+1

Dummy() メソッドを追加しました。

  • クライアントからのダミーの呼び出しは正常に機能します。
  • クライアントから Dummy2 を呼び出すと正常に動作します。
  • クライアントから Dummy3 を呼び出すと、同じエラーが発生します。

編集 12AM39 GMT+1

次の変更を加えても役に立ちませんでした。

[DataContract]
[KnownType(typeof(AbstractMessage))]
public class Message : AbstractMessage

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
[KnownType(typeof(AbstractMessage))]
[KnownType(typeof(Message))]
public class ActiveDirectory : IActiveDirectory

編集: 13AM31 GMT+1

Dummy3 の戻り値の型を Message に設定すると、クライアント コードでの Dummy3 の呼び出しが機能します。
WCF + ポリモーフィズムには奇妙な点があります...

4

3 に答える 3

4

WCF サービスは DTO を返す必要があります。これらはインターフェイスにすることはできず、抽象基本クラスを返したい場合は、実際に返す予定の型の実装をデータ コントラクト シリアライザーに伝える必要があります。

AbstractMessage 型については (操作コントラクトの一部として) 既に認識していますが、操作コントラクトで明示的に宣言されていないその型のすべての実装は、既知の型で宣言する必要があります。

これを追加してみてください:

[ServiceContract]
[ServiceKnownType(typeof(Message))]
public interface IActiveDirectory
{
    ...
}

Messageここでは、このサービスがそのメソッドへの引数として型のオブジェクトを返す (または期待する) 可能性があることをデータ コントラクト シリアライザーに伝えています。

これも同様に機能するはずです:

[DataContract]
[KnownType(typeof(Message))]
public abstract class AbstractMessage
{
    ...
}

Message既知のタイプであるデータ コントラクト シリアライザーに伝えたい場合AbstractMessage

ServiceKnownTypes の代わりにサービスで KnownTypes を使用し、親クラスではなく派生クラスに既知の型を適用しようとしたため、変更が機能しなかったと思います。これは、言語で慣れていることです (メッセージはAbstractMessage) ですが、WCF ではそれをひっくり返して、派生実装を親クラス (AbstractMessage には実装 Message があります) に配置する必要があり、制限される可能性があります。

あなたが言った:There 's something odd with WCF + Polymorphism...

私を信じてください。WCF がポリモフィズムをサポートしているとは考えないほうがよいでしょう。DTO を返すだけで、これらをポリモーフィックにしようとすると、多くの問題に直面することになります。ポリモーフィズムはインターフェイスを使用して実装され、WCF ではインターフェイスを使用できません。抽象クラスを使用すると、c# には多重継承がないため、DTO はオブジェクトの単一のビューしか表現できず、ドメイン モデル クラスの複数のインターフェイスを表す DTO を作成できないことがすぐにわかります。(件名に関するこの質問を参照してください)

KnownTypesServiceKnownTypesまたは構成のいずれかを使用して、既知の型の知識を渡す方法の詳細については、こちらの回答を参照してください。

于 2013-06-17T11:39:00.253 に答える
3
[KnownType(typeof(AbstractMessage))]

コンパイラは、AbstractMessage を返すことを既に認識しています。説明から理解できないのは、AbstractMessage から派生したインスタンスです。それらはあなたが知らせる必要があるタイプです。AbstractMessage から派生し、そこに返される型は既知の型である必要があり、これは AbstractMessage 自体で宣言する必要があります。

[KnownType(typeof(DerivedMessage1))]
[KnownType(typeof(DerivedMessage2))]
[KnownType(typeof(DerivedMessage3))]

あなたの場合、データ コントラクト シリアライザーに伝える属性が必要AbstractMessageですMessage

[ServiceBehavior(...)]
[KnownType(typeof(Message))]
public class ActiveDirectory : IActiveDirectory
{
    public AbstractMessage Dummy3()
    {
        return new Message();
    }
}
于 2013-06-17T10:35:17.757 に答える
0

私はかつてその問題を抱えていました。私の場合、私が知る限り、wcf-シリアライザーは適切に機能するために非抽象型を必要とします。したがって、私の場合、抽象クラスとインターフェースから通常のオブジェクトに切り替えると、うまくいきました。

于 2013-06-17T10:17:37.463 に答える