2013-03-28 26 views
9

Làm cách nào để trả về loại giao diện trong thông số loại chung từ OperationContracts trong dịch vụ WCF REST của tôi? Cụ thể hơn, nó hoạt động cho một hoạt động nhưng không phải khi tôi thêm một thao tác thứ hai với một số chung là T là một giao diện.Loại trả về chung với thông số loại giao diện trong WCF

Tôi đang sử dụng JSON làm định dạng yêu cầu và phản hồi, cho khách hàng không WCF phân tích cú pháp phản hồi JSON cho dữ liệu cần thiết. Tôi không sử dụng SOAP, hoặc WSDL do dịch vụ tạo ra.

giao diện dịch vụ của tôi:

[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(); 
} 

tôi rời GetCount()GetDescription() trong ví dụ này chỉ ra rằng hai kết quả chung hoạt động tốt, nhưng rõ ràng họ là loại bê tông. Và thậm chí GetFooData() hoạt động tốt cho đến khi tôi thêm phương thức thứ hai là IServiceResult<T> trong đó T là một giao diện.

Loại trả về GetFooData()GetBarData() không giống nhau, cũng như không phải là các lớp cụ thể triển khai chúng.

Bạn có thể tưởng tượng rằng tôi đã giảm việc thực hiện một bộ xương như tôi không nghĩ rằng việc thực hiện là trung tâm của vấn đề:

#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 

Và được thông báo lỗi khi tôi gọi GetBarData() từ trình duyệt :

 
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. 

phần còn lại của các thông báo lỗi là một cá trích đỏ về va chạm loại bộ sưu tập List<Test>Test[], mà không phải là trường hợp ở đây.

Rõ ràng, IFooDataIBarData không giống nhau và cũng không phải là lớp học triển khai chúng.

Vậy tại sao ServiceResult<IFooData>ServiceResult<IBarData> cả hai đều giải quyết thành ServiceResultOfanyType?

Tôi có thiếu thứ gì đó hay không có cách nào để sửa lỗi này?

+0

Cho đến nay, giải pháp duy nhất tôi tìm thấy là làm phẳng các kiểu ServiceResult chung thành một nhóm cố định 'ServiceResultOfIFooData: ServiceResult ' các lớp và thay đổi OperationContracts để trả về các loại đó. Điều này làm cho tôi bị bệnh mặc dù vì nó vi phạm mục đích của việc có generics ở nơi đầu tiên. – JMD

+0

Tôi đã thử [ghi đè tên của DataContract] (http://msdn.microsoft.com/en-us/library/ms731045 (v = vs.100) .aspx) cho ServiceResult bằng cách sử dụng '[DataContract (Name =" ServiceResultOf {0} ")]' nhưng {0} vẫn được giải quyết thành "anyType", khi nhìn lại, là đáng thất vọng nhưng không hoàn toàn bất ngờ, vì đây có thể là chính xác những gì đang được thực hiện theo mặc định khi Name không bị ghi đè. – JMD

+0

Câu hỏi hay. Tôi đã có cùng một vấn đề và thực sự muốn tránh sử dụng các lớp cụ thể. Bạn có thể tìm thấy một giải pháp khác với giải pháp được đề cập trong câu trả lời được chấp nhận không? – smoksnes

Trả lời

5

Sau nhiều thử và sai, tôi đã cuối cùng đã làm việc này với những thay đổi tối thiểu:

  • hoạt động dịch vụ của tôi bây giờ trở ServiceResult<T> thay vì IServiceResult<T>. Trên thực tế, IServiceResult<T> hiện đã biến mất hoàn toàn.
  • GetServiceKnownTypes() không còn trả về tất cả các biến thể của ServiceResult<T>. Tôi chỉ trả về số DataContract được sử dụng làm 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 
    

bây giờ tôi có thể gọi tất cả các phương pháp đó và trở lại danh sách các kiểu generic gọi bằng giao diện của họ trong ServiceContract.

+3

Tôi đã đăng câu trả lời của riêng mình vì ít nhất một người nghĩ rằng câu hỏi này đáng giá. Vì vậy, hy vọng, cùng một ai đó có thể tìm thấy câu trả lời hữu ích. – JMD

Các vấn đề liên quan