Generic DataContract in WCF

Posted in .NET Framework // Posted at 2013. 5. 9. 11:53
728x90

WCF 서비스의 반환 값으로 사용자 정의 객체를 사용한다.

WCF 서비스와 클라이언트의 데이터 계약을 위한 DataContract Attribute 설정을 통해 시리얼라이즈 되어 통신이 가능해 진다.

 

그런데 이 반환 객체의 멤버 중, Collection 타입의 멤버는 내부 Item 타입만 다를 뿐이라서 상위 타입 선언을 통해 하나의 클래스만 유지하고 싶었다.

 

예를 들어서 이런 식이다.

[DataContract]

public class ReturnCollectionCategory : ReturnBaseObj
{
       [DataMember]
       public IList<Category> ResultCollection { get; set; }

}

 

[DataContract]

public class ReturnCollectionProduct : ReturnBaseObj
{
       [DataMember]
       public IList<Product> ResultCollection { get; set; }

}

 

위의 코드를 보면, ResultCollection 프로퍼티의 아이템 타입만 다를 뿐 나머지는 모두 동일하다.

따라서 최상위 타입인 System.Object로 아래와 같이 처리하려 했다

 

[DataContract]

public class ReturnCollectionCategory : ReturnBaseObj
{
[DataMember]
public IList<System.Object> ResultCollection { get; set; }

}

 

이렇게 하면 하나의 클래스를 유지하면서 다형적으로 처리할 수 있게 된다.

그런데 문제는 WCF 환경에서 이 객체를 원격 통신용 객체로 이용할 때 발생한다. System.Object 타입을 시리얼라이즈 할 수 없다는 것이다.

 

그래서 아래와 같이 지네릭을 이용하기로 한다.

지네릭을 이용하면, 객체 생성 시점에 타입이 결정되기 때문에 원격 통신에도 문제없이 잘 동작한다.

[DataMember] 
public class ReturnCollectionObj<T> : ReturnBaseObj
{
     [DataMember]
     public IList<T> ResultCollection { get; set; }

 

추가로, 이렇게  서비스 단에서 지네릭 기반으로 생성된 객체를 원격으로 전달받는 클라이언트에서는 지네릭 버전이 아니라 이미 결정된 객체 이름으로 전달받게 된다.

 

즉 서비스 참조로 생성된 프록시 객체를 보면 지네릭 버전의 객체 이름에 임의의 문자열이 추가된 것을 확인할 수 있다. 실제 서비스 환경에서는 이러한 상황이 달갑지 않다.

따라서 아래와 같이 이름을 지정하면 좋을 것이다.

 

[DataContract(Name="ReturnCollectionObj{0}")] 

public class ReturnCollectionObj<T> : ReturnBaseObj
{
[DataMember]
public IList<T> ResultCollection { get; set; }
}

 

이렇게 하면 클라이언트에서 반환 받는 객체 이름은 타입이 결정된 이름이 붙여 진다.

예를 들어 Product 타입으로 객체를 생성했다면, ReturnCollectionObjProduct 가 된다.