2

ServiceKnownType 属性で指定されたヘルパー メソッドを実行するのに問題があります。簡単にするために、2 つのアセンブリを用意します。1 つはサービス インターフェイスとデータ コントラクト用のインターフェイスを含み、もう 1 つはサービス実装と具体的なデータ コントラクトを含みます。

これは、私のサービスとその実装の簡略化/簡素化されたバージョンです。

MyService.Interface.dll

// IMyService.cs
[ServiceContract]
IMyService
{
    [OperationContract]
    IList<IMyData> GetData();
}

// IMyData.cs
public interface IMyData
{
    int Foo { get; set; }
}

MyService.dll (MyService.Interface.dll への参照付き)

// MyService.svc.cs
public class MyService: IMyService
{
    public IList<IMyData> GetData()
    {
        // Instantiate List<IMyData>, add a new MyData to the list
        // return the List<IMyData>.
    }
}

// MyData.cs
[DataContract]
public class MyData : IMyData
{
    [DataMember]
    public int Foo { get; set; }
}

問題の根本は、サービス定義が具象型ではなくインターフェース型を使用するため、の結果をシリアル化するために、サービスに具象クラスと具象ジェネリック クラスGetData()について通知する必要があることです。MyDataList<IMyData>

簡単な答えは、IMyService を次のように装飾することです。

[ServiceKnownType(typeof(MyData))]
[ServiceKnownType(typeof(List<IMyData>))]

ただし、MyDataMyService.Interface.dll 内で参照されていないアセンブリで定義されています (循環参照によるものではありません)。

ServiceKnownType次に考えたのは、MyService 自体の「ヘルパー メソッド」形式を使用することでした。

[ServiceKnownType("GetDataContracts", MyService)]
public class MyService: IMyService
{
    public static IEnumerable<Type> GetDataContracts(ICustomeAttributeProvider provider)
    {
        // create a List<Type>, add MyData to it, and return it.
    }
    //...
}

私が見る限り、GetDataContracts決して呼び出されないことを除いて、それはうまくいくはずです。私はそれを別の静的クラスに移動しようとしました(MyServiceと並行してその中にネストされています)が、そこで停止するブレークポイントを取得することはできません。

編集: web.config を介して既知の型を追加しても、ジェネリック型をそのように追加できないため、どちらも機能しないと言うつもりでした。web.config を使用して、単純で具体的なタイプのみを追加できます。

<knownType type="TypeName, Assembly" />

具象List<IMyData>のアセンブリに完全修飾型名がありません。

4

1 に答える 1

2

修理済み。その答えは、ヘルパー メソッド フォームを使用して ServiceKnownType をサービス実装ではなくサービス インターフェイスに追加し、必要な型を反映するヘルパー クラスをコード内の具象型を参照して追加するのではなく追加することでした。(そのアセンブリへの参照を追加できないため、それを行うことができなかったことを思い出してください。)

[ServiceContract]
[ServiceKnownType("GetDataContractTypes", typeof(MyServiceHelper))]
public interface IMyService
{ ... }

そして、新しい MyServiceHelper クラスを Nightingale.Interface に追加しましたが、公開されていないため、「純粋な」インターフェイスのみにしたいアセンブリからクラスを不必要に公開することについては心配していません。

// Not public outside of this assembly.
static class MyServiceHelper
{
    public static IEnumerable<Type> GetDataContractTypes(ICustomAttributeProvider paramIgnored)
    {
        // Get the assembly with the concrete DataContracts.
        Assembly ass = Assembly.Load("MyService");  // MyService.dll
        // Get all of the types in the MyService assembly.
        var assTypes = ass.GetTypes();
        // Create a blank list of Types.
        IList<Type> types = new List<Type>();
        // Get the base class for all MyService data contracts
        Type myDataContractBase = ass.GetType("MyDataContractBase", true, true);
        // Add MyService's data contract Types.
        types.Add(assTypes.Where(t => t.IsSubclassOf(myDataContractBase)));
        // Add all the MyService data contracts to the service's known types so they can be serialized.
        return types;
    }
}

私の DataContract クラスはすべて共通の基本クラスを拡張するため、この特定のソリューションは私にとってはうまくいきます。私の場合、同じセットになる DataContract 属性を持つアセンブリからすべてのタイプをロードするように作り直すことができます。

于 2013-02-20T21:07:11.670 に答える