WCF中具有接口类型params的通用返回类型

时间:2013-03-28 00:32:50

标签: json wcf generics serialization interface

如何从WCF REST服务中的OperationContracts返回泛型类型参数中的接口类型?更具体地说,它适用于一个操作,但是当我使用作为接口的通用T添加第二个操作时,它不起作用。

我正在使用JSON作为请求和响应格式,为非WCF客户端提供解析所需数据的JSON响应。我没有使用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();
}

我在示例中留下了GetCount()GetDescription(),指出这两个通用结果运行良好,但显然它们是具体类型。甚至GetFooData()工作正常,直到我添加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()时出现错误消息:

Type 'ServiceResult`1[IBarData]' cannot be added to list of known types since
another type 'ServiceResult`1[IFooData]' with the same data contract name
'http://schemas.datacontract.org/2004/07/ServiceResultOfanyType' is
already present. 

错误消息的其余部分是关于碰撞集合类型List<Test>Test[]的红色鲱鱼,这不是这里的情况。

显然,IFooDataIBarData不一样,实现它们的类也不一样。

那么为什么ServiceResult<IFooData>ServiceResult<IBarData>都解析为ServiceResultOfanyType

我错过了什么,或者没有办法解决这个问题?

1 个答案:

答案 0 :(得分:5)

经过多次反复试验,我终于以最小的变化完成了这项工作:

  • 我的服务操作现在返回ServiceResult<T>而不是IServiceResult<T>。事实上,IServiceResult<T>现已完全消失。
  • GetServiceKnownTypes()不再返回ServiceResult<T>的所有变体。我只返回用作DataContract的{​​{1}}。

    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 中接口所引用的泛型类型列表。