代码之家  ›  专栏  ›  技术社区  ›  JMD

WCF中具有接口类型参数的泛型返回类型

  •  9
  • JMD  · 技术社区  · 13 年前

    如何从 OperationContracts 在我的WCF REST服务中?更具体地说,它适用于一个操作,但当我使用泛型添加第二个操作时就不行了 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 是一个接口。

    的返回类型 获取食物数据() 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
    

    以及当我调用时的错误消息 获取条形数据() 从浏览器:

    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[] ,这里的情况并非如此。

    清晰地 IFooData IBarData 不一样,实现它们的类也不一样。

    那么为什么 ServiceResult<IFooData> ServiceResult<IBarData> 双方都决心 ServiceResultOfanyType ?

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

    1 回复  |  直到 13 年前
        1
  •  5
  •   JMD    13 年前

    经过多次尝试和错误,我终于用最少的更改完成了这项工作:

    • 我的服务操作现在返回 ServiceResult<T> 而不是 IServiceResult<T> 事实上 IServiceResult<T> 现在已经完全消失了。
    • GetServiceKnownTypes() 不再返回的所有变体 服务结果<T> 。我只返回 DataContract s用作 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 .

    推荐文章