WCF:タジェネリック医薬品およびServiceKnownType
-
21-09-2019 - |
質問
いて以下の
[ServiceContract]
[ServiceKnownType(typeof(ActionParameters))]
[ServiceKnownType(typeof(SportProgram))]
[ServiceKnownType(typeof(ActionResult<SportProgram>))]
public interface ISportProgramBl
{
[OperationContract]
IActionResult<ISportProgram> Get(IActionParameters parameters);
}
私は"Get"メソッドを取得します以下のようなエラー:
誤りがありましたがっserializeパラメータ http://tempuri.org/:GetResult.のInnerExceptionメッセージ'タイプ'PPS.ます。DomainModel.ます。ます。ActionResult`1[[PPS.ます。DomainModel.SportProgram.ISportProgram、PPS.ます。DomainModel、バージョン=1.0.0.0文=neutral,PublicKeyToken=nullの場合]]'データ契約の名前"ActionResultOfanyType: http://schemas.datacontract.org/2004/07/PPS.Core.DomainModel.Support.Action なく変更になることがあります。を追加できないプロダクト種別名を静的にリストの種類、例えば、KnownTypeAttribute属性または追加したり、リストの種類に渡されるDataContractSerializer.'.をご覧くださいInnerExceptionます。
このエラーが見えることを解決することができActionResultでの解決ができていないとかISportProgramもしていま ServiceKnownType(typeof(ActionResult < SportProgram>)) 私のサービスインタ---
この参照をスタブ生成されるようになりますので、できることは知られていた全確:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="SportProgramStb.ISportProgramBl")]
public interface ISportProgramBl {
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ISportProgramBl/Get", ReplyAction="http://tempuri.org/ISportProgramBl/GetResponse")]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(PPS.Core.DomainModel.SportProgram.SportProgram))]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(PPS.Core.DomainModel.Support.Action.ActionParameters))]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(PPS.Core.DomainModel.Support.Action.ActionResult<PPS.Core.DomainModel.SportProgram.SportProgram>))]
object Get(object parameters);
}
なぜ、このようなおかしい????注そのWCFサービスが正しく...ですの例外の場合に結果が返されます。
最後にActionResultようになります:
public interface IActionResult<T>
{
T Result { get; set; }
}
乾杯 アンソニー
解決
まあ、これはSOA対OOP「インピーダンスの不一致」の別のケースだと思います。 2つの世界はまったく別です。
WCFでは、クライアントからサーバーに渡されているものはすべて渡されます。 シリアル化されたメッセージ - 参照は使用されていません。
これは、クライアントにシリアル化し、サーバーに送信し、そこでそれを使用して使用したいすべてのことを意味します。 コンクリート - インターフェイスを通過することはできません。「解決されていない」ジェネリックを使用することはできません。それを綴る必要があります。基本的に、クライアントからワイヤーを介してサーバーに渡されているのは、XMLスキーマで表現可能でなければなりません。
これには多くの意味があります:
- インターフェイスなし - インターフェイスを通過することはできません - コンクリートタイプで作業する必要があります
- 「自動」継承はありません - 基本クラスを定義して派生クラスに基づいて派生クラスを渡すことはできません - それらも特異的にする必要があります(それがServicnedType属性のためです)
- 自動ジェネリックはありません - 繰り返しますが、代わりにコンクリートタイプを使用する必要があります
これは多くの制限のように聞こえるかもしれませんが、それはWCFがすべてのメッセージベースの通信を使用しているためです - 紹介、継承、ジェネリックなどに対処することはできません - あなたはそれを綴る必要があります。
ですから、私はあなたにそれ自体の答えを本当に持っていません - あなたはあなたの戦略を再考し、あなたのクライアントとサーバーがWCFを介して情報を交換する方法を変える必要があると思います。
マーク
PS:私はさらに調査を行いましたが、私のすべての理解に反して、ワイヤー全体のインターフェイスや抽象的なベースクラスに基づいているものをシリアル化する方法があるようです。ワイヤーの両端にあるネット(つまり、それは いいえ たとえばJavaと相互運用可能)。
見る NetDatacontractSerializerのAaron Skonnardブログ投稿 そして別の ブログ投稿 と さらに別の netDatacontractSerializerを使用する方法を示して、 IPerson
メソッドのパラメーターとして。
他のヒント
これは私が解決した問題の1つです Servicestack.net - 私のオープンソース.NETおよびMono Webサービスフレームワーク。
サービススタックは大きな影響を受けました Martin Fowlersデータ転送オブジェクトパターン DTOを使用してWebサービスを定義できるようにすることができるためです。つまり、SOAの方法です:)。
私は、あなたが期待するように振る舞う私自身のWSDLを生成することにより、WCFに固有のこの制限を避けます。 WCFの複雑な構成 / ServiceContractのモデルを置き換える利点として、SOAP WebサービスもMonoで機能します。 ライブデモを参照してください.
それは古い質問であり、受け入れられた答えは完全に正しいですが、私はこれを類似した問題を検索する際にこれを考え出し、自分の経験を共有できると考えました。多くの場合、頭痛ですが、WCFとインターフェイスと組み合わせたジェネリックを使用することが可能です。これは、私が行った別の(類似の)実装の実用的な例です。
[ServiceContract]
[ServiceKnownType(typeof(CollectionWrapper<IAssociation>))]
public interface IService :
{
[OperationContract]
ICollectionWrapper<IAssociation> FindAssociation(string name, int pageSize, int page);
}
public interface ICollectionWrapper<TModel>
{
int TotalCount { get; set; }
IEnumerable<TModel> Items { get; set; }
}
[KnownType(typeof(OrganizationDto))]
[KnownType(typeof(CompanyDto))]
public class CollectionWrapper<TModel> : ICollectionWrapper<TModel>
{
[DataMember]
public int TotalCount { get; set; }
[DataMember]
public IEnumerable<TModel> Items { get; set; }
}
public class CompanyDto : IAssociation
{
public int Id { get; set; }
public string Name { get; set; }
}
public class OrganizationDto : IAssociation
{
public int Id { get; set; }
public string Name { get; set; }
}
ここで重要なのは、の組み合わせを使用することです KnownType
と ServiceKnownType
.
あなたの場合、あなたはこのようなことをすることができます:
[ServiceContract]
[ServiceKnownType(typeof(ActionParameters))]
[ServiceKnownType(typeof(ActionResult<ISportProgram>))] // Actual implementation of container, but interface of generic.
public interface ISportProgramBl
{
[OperationContract]
IActionResult<ISportProgram> Get(IActionParameters parameters);
}
[KnownType(typeof(SportProgram))] // Actual implementation here.
public class ActionResult<T>
{
// Other stuff here
T FooModel { get; set; }
}
これは、共有契約(実際のサービスインターフェイスへのアクセス)があり、契約を消費する場合に機能します。 ChannelFactory<ISportProgramBl>
. 。サービスの参照で動作するかどうかはわかりません。
ただし、ここに記載されているように、実装にいくつかの問題があるようです。
そして、ここで尋ねられ、答えた別の同様の質問:
ご返しIListのでも、このシステムの問題を問Tです。
いであればokを返すインターフェースではなくタイプです。
コンクリートタイプではなく、オブジェクトのインターフェイスを指定していますか?
PPS.Core.DomainModel.Support.Action.ActionListResult<IList<PPS.Core.DomainModel.SportProgram.ISportProgram>>
編集:
私が言っているのは、既知のタイプリストに渡されるジェネリック(インターフェイスを介してサブオブジェクトを含む)を渡すすべての具体的なタイプです。すべてのタイプが知られていない連続化の問題がありました。