2013-03-28 4 views
9

내 WCF REST 서비스의 OperationContracts에서 일반 형식 매개 변수의 인터페이스 형식을 반환하려면 어떻게해야합니까? 더 구체적으로 말하자면, 하나의 연산에서 작동하지만, 인터페이스 인 일반 T을 가진 두 번째 연산을 추가 할 때가 아닙니다.WCF의 인터페이스 유형 매개 변수를 사용하는 일반 반환 형식

요청 및 응답 형식으로 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()을 왼쪽하지만 분명히 그들은 콘크리트 종류가 있습니다. 그리고 이 인터페이스 인 IServiceResult<T>의 두 번째 방법을 추가 할 때까지 GetFooData()도 문제없이 작동합니다.

반환 유형은 GetFooData()GetBarData()이 같지 않으며이를 구현하는 구체적인 클래스도 아닙니다.

당신은 내가 구현이 문제의 핵심이다 생각하지 않는 한 나는 골격 구현을 감소했습니다 상상할 수 : 나는 브라우저에서 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[]에 대한 레드 헤링 (Red Herring)이다.

분명히 IFooDataIBarData은 동일하지 않으며 해당 클래스를 구현하는 클래스도 아닙니다.

그렇다면 ServiceResult<IFooData>ServiceResult<IBarData>은 모두 ServiceResultOfanyType으로 해결됩니까?

내가 누락되었거나 해결할 방법이 없습니까?

+0

지금까지 살펴본 유일한 해결책은 Generic ServiceResult 유형을 고정 된 'ServiceResultOfIFooData : ServiceResult '클래스로 평평하게하고 해당 유형을 대신 반환하도록 OperationContracts를 변경하는 것입니다. 이것은 처음부터 generics를 가지고있는 목적을 위반하기 때문에 나를 아프게합니다. – JMD

+0

ServiceResult 에 대해 [DataContract (Name = ")를 사용하여 [DataContract의 이름 재정의] (http://msdn.microsoft.com/en-us/library/ms731045(v=vs.100).aspx) 되돌아 보면 실망 스럽지만 완전히 예기치 않은 "anyType"으로 {0}이 여전히 해결됩니다. Name이 대체되지 않은 경우 기본적으로 수행되는 작업 일 것입니다. – JMD

+0

큰 질문입니다. 나는 동일한 문제를 안고 있으며 실제로 구체적인 클래스를 사용하지 않으려합니다. 수락 된 답변에서 언급 한 해결책 이외의 다른 해결책을 찾았습니까? – smoksnes

답변

5

많은 시행 착오 후, 나는 마침내 최소한의 변경으로이 작업을 가지고 :

  • 내 서비스 운영 지금 ServiceResult<T> 대신 IServiceResult<T> 돌아갑니다. 사실 IServiceResult<T>은 이제 완전히 사라졌습니다.
  • GetServiceKnownTypes()은 더 이상 ServiceResult<T>의 모든 변형을 반환하지 않습니다. 나는 만을 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 자신의 인터페이스에 의해 참조 일반적인 유형의 목록을 다시 얻을 수 있습니다.

+3

적어도 한 사람이 그 질문이 upvote의 가치가 있다고 생각해서 내 자신의 답변을 게시했습니다. 따라서, 같은 사람이 대답을 유용하게 사용할 수 있기를 바랍니다. – JMD

관련 문제