9

OperationContractsWCF REST サービスのジェネリック型パラメーターでインターフェイス型を返すにはどうすればよいですか? Tより具体的には、1 つの操作では機能しますが、インターフェイスであるジェネリックを使用して 2 番目の操作を追加すると機能しません。

要求と応答の形式として JSON を使用し、必要なデータの JSON 応答を解析する非 WCF クライアントにフィードします。SOAP、またはサービスによって生成された WSDL を使用していません。

私のサービスインターフェース:

[ServiceContract]
[ServiceKnownType("GetServiceKnownTypes", typeof(ServiceKnownTypesHelper))]
public interface IMyService
{
    [WebGet(UriTemplate="count")]
    [OperationContract]
    IServiceResult<int> GetCount();

    [WebGet(UriTemplate="desc")]
    [OperationContract]
    IServiceResult<string> GetDescription();

    [WebGet(UriTemplate="foo")]
    [OperationContract]
    IServiceResult<IFooData> GetFooData();

    // Fails when I invoke either method if I uncomment this operation.
    //[WebGet(UriTemplate="bar")]
    //[OperationContract]
    //IServiceResult<IBarData> GetBarData();
}

これら 2 つの一般的な結果が正常に機能することを指摘するために、例を残しましたが、明らかにそれらは具象型GetCount()です。GetDescription()そして、インターフェイスがどこにあるかGetFooData()の 2 番目のメソッドを追加するまでは、問題なく動作します。IServiceResult<T>T

との戻り値の型は同じGetFooData()GetBarData()はなく、それらを実装する具象クラスも同じではありません。

実装が問題の核心であるとは思わないため、実装をスケルトンに縮小したと想像するかもしれません。

#region My service implementation
public class MyService : IMyService
{
    public IServiceResult<int> GetCount()
    {
        return new ServiceResult<int>(42);
    }
    public IServiceResult<string> GetDescription()
    {
        return new ServiceResult<string>("Muffins");
    }
    public IServiceResult<IFooData> GetFooData()
    {
        return new ServiceResult<IFooData>(new FooData() { Foo = 99 });
    }
    public IServiceResult<IBarData> GetBarData()
    {
        return new ServiceResult<IBarData>(new BarData() { Bar = "Elvis was here" });
    }
}
#endregion

#region ServiceKnownTypesHelper.GetServiceKnownTypes():
public static class ServiceKnownTypesHelper
{
    private static IList<Type> serviceKnownTypes = new List<Type>()
        {
            typeof(FooData),
            typeof(BarData),
            typeof(ServiceResult<int>),
            typeof(ServiceResult<string>),
            typeof(ServiceResult<IFooData>),
            typeof(ServiceResult<IBarData>),
        };

    public static IEnumerable<Type> GetServiceKnownTypes(ICustomAttributeProvider paramIgnored)
    {
        return serviceKnownTypes;
    }
}
#endregion

#region IServiceResult<T> and its concrete implementation:
public interface IServiceResult<T>
{
    IList<string> Errors { get; }
    T Value { get; set; }
}

[DataContract]
public class ServiceResult<T> : IServiceResult<T>
{
    public ServiceResult(T value)
    {
        this.Value = value;
    }

    private IList<string> errors = new List<string>();

    [DataMember]
    public IList<string> Errors
    {
        get
        {
            return this.errors;
        }
    }

    [DataMember]
    public T Value { get; set; }
}
#endregion

#region IFooData and its concrete implementation:
public interface IFooData
{
    int Foo { get; set; }
}

[DataContract]
public class FooData: IFooData
{
    [DataMember]
    public int Foo { get; set; }
}
#endregion

#region IBarData and its concrete implementation:
public interface IBarData
{
    string Bar { get; set; }
}

[DataContract]
public class BarData: IBarData
{
    [DataMember]
    public string Bar { get; set; }
}
#endregion

GetBarData()そして、ブラウザから呼び出したときのエラーメッセージ:

タイプ 'ServiceResult`1[IBarData]' は既知のタイプのリストに追加できません。
同じデータ コントラクト名を持つ別の型 'ServiceResult`1[IFooData]'
「http://schemas.datacontract.org/2004/07/ServiceResultOfanyType」は
すでに存在します。

List<Test>エラー メッセージの残りの部分は、コレクション型との衝突に関する注意書きですがTest[]、ここでは当てはまりません。

明らかに、IFooDataIBarDataは同じではなく、それらを実装するクラスも同じではありません。

では、なぜServiceResult<IFooData>ServiceResult<IBarData>の両方が に解決されるのServiceResultOfanyTypeでしょうか?

何か足りないのですか、それともこれを修正する方法はありませんか?

4

1 に答える 1

5

多くの試行錯誤の後、私は最終的に最小限の変更でこれを機能させました:

  • 私のサービス操作はServiceResult<T>、 の代わりに返されるようになりIServiceResult<T>ました。実際、IServiceResult<T>今では完全になくなりました。
  • GetServiceKnownTypes()のすべてのバリアントを返さなくなりましたServiceResult<T>DataContractとして使用されるのみを返しTます。

    #region My service interface
    [ServiceContract]
    [ServiceKnownType("GetServiceKnownTypes", typeof(ServiceKnownTypesHelper))]
    public interface IMyService
    {
        [WebGet(UriTemplate="count")]
        [OperationContract]
        ServiceResult<int> GetCount();
    
        [WebGet(UriTemplate="desc")]
        [OperationContract]
        ServiceResult<string> GetDescription();
    
        [WebGet(UriTemplate="foo")]
        [OperationContract]
        ServiceResult<IFooData> GetFooData();
    
        [WebGet(UriTemplate="bar")]
        [OperationContract]
        ServiceResult<IBarData> GetBarData();
    }
    #endregion
    #region My service implementation (minus bodies)
    public class MyService : IMyService
    {
        public ServiceResult<int> GetCount() {}
        public ServiceResult<string> GetDescription() {}
        public ServiceResult<IFooData> GetFooData() {}
        public ServiceResult<IBarData> GetBarData() {}
    }
    #endregion
    #region ServiceKnownTypes
    // My list of ServiceKnownTypes is now much shorter and simpler. I was feeding the service too much information
    public static class ServiceKnownTypesHelper
    {
        private static IList<Type> serviceKnownTypes = new List<Type>()
            {
                typeof(FooData),
                typeof(BarData),
                //typeof(ServiceResult<int>),
                //typeof(ServiceResult<string>),
                //typeof(ServiceResult<IFooData>),
                //typeof(ServiceResult<IBarData>),
            };
    
        // Remaining implementation is the same as before
    }
    #endregion
    #region ServiceResult<T> with no interface (it's not used or needed)
    [DataContract]
    public class ServiceResult<T> //: IServiceResult<T>
    {
        // implementation is the same as before
    }
    #endregion
    

これで、これらのメソッドをすべて呼び出して、ServiceContract.

于 2013-04-02T22:13:00.640 に答える