2011-12-06 2 views
1

WCF 파생/기본 계약 문제가 있습니다. 나는 BaseThing 객체를 반환하는 서버 인터페이스/계약을 체결 한 :WCF : 기본 개체 (DataContractResolver)가있는 계약의 파생 개체 반환

[OperationContract] 
BaseThing Get_base_thing(); 

이 (BaseThing에서 유래)는 DerivedThing을 가지고 구현하고 BaseThing로 반환이 원하는 서버. WCF에 BaseThing 부분 만 DerivedThing 부분 만 운송하고 싶다고 말하는 방법은 무엇입니까?

Get_base_thing에있는 경우 DerivedThing에 대한 참조를 반환하는 경우 서버 측에 SerializationException이 표시됩니다.

나는 DataContractResolver을 정의해야한다고 생각하는데 MSDN 기사 Using a Data Contract Resolver을 살펴 봤지만 이것은 적어도 100 % 명확하지 않습니다.

DataContractResolver은 파생 된 객체의 기본 부분 만 전송하도록 WCF에 알려야합니까?

KnownType 속성을 사용하면 더 간단하게 할 수 있습니까?

답변

1

게시 후 나는 또한이 동일한 질문을 발견했습니다 How to serialize a derived type as base. 나를 위해 marc에 의해 받아 들여지지 않은 두 번째 대답은이 문제를 해결하는 가장 쉬운 방법입니다. 즉,
[DataContract(Name="BaseClass")]
으로 장식하십시오.이 솔루션은 파생 된 객체가이 객체를 전송할 때마다 기본으로 전송된다는 것을 의미합니다. 내게는 문제가되지 않았다면 DataContractResolver 라우트를 사용해야한다. DataContractResolver 노선에

일부 노트 : 이것은 당신이 어떤 통화에서 파생 같이 유도하지만,베이스 등의 다른에 전달할 수 있습니다
1 - 이름 = 접근 방식에 대해 사용하지 않을 경우 - 당신이 할 필요가있는 경우.
2. knownTypeResolver가 false를 반환하기 때문에 datacontractrsolver 아티클의 DeserializeAsBaseResolver를 사용하여 예외가 발생합니다. 이 호출의 반환 값을 무시하고 TryResolveType에서 항상 true를 반환하도록 수정합니다. 그것은 작동하는 것 같습니다.
3.우리가 기본 클래스로 직렬화했기 때문에 파생 클래스에서 [DataContract]가 필요하지 않다고 생각했습니다. 그건 틀렸다. 개체는 파생 개체로 serialize되고 기본 개체로 공용화되므로 [DataContract]를 사용하여 파생 된을 장식해야하지만 불필요하게 일련 화되지 않도록 [DataMembers]로 필드를 표시하지 마십시오.
4. 명령 줄 호스트와 서비스 호스트가있는 경우 둘 모두에 계약 확인자를 삽입하는 코드가 필요합니다. 나는 이것을 내 결정자에게 정적으로 두는 것이 유용하다는 것을 알았다.
5. cd.Operations.Find("Get_gateway_data")에 대한 호출의 "Get_gateway_data"문자열은 해당 개체를 반환하는 계약 메서드의 이름입니다. 이 동작을 원할 때마다이 작업을 수행해야합니다.

이 방법에 대한

최종 코드 :

public class DeserializeAsBaseResolver : DataContractResolver { 

    public static void Install(ServiceHost service_host) { 
     // Setup DataContractResolver for GatewayProcessing to GatewayData resolution: 
     ContractDescription cd = service_host.Description.Endpoints[0].Contract; 
     OperationDescription myOperationDescription = cd.Operations.Find("Get_gateway_data"); 
     DataContractSerializerOperationBehavior serializerBehavior = myOperationDescription.Behaviors.Find<DataContractSerializerOperationBehavior>(); 
     if (serializerBehavior == null) { 
      serializerBehavior = new DataContractSerializerOperationBehavior(myOperationDescription); 
      myOperationDescription.Behaviors.Add(serializerBehavior); 
     } 
     serializerBehavior.DataContractResolver = new DeserializeAsBaseResolver(); 
    } 

    public override bool TryResolveType(Type type, Type declaredType, 
             DataContractResolver knownTypeResolver, 
             out XmlDictionaryString typeName, 
             out XmlDictionaryString typeNamespace) { 

     bool ret = knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace); 
     //return ret; // ret = false which causes an exception. 
     return true; 
    } 

    public override Type ResolveName(string typeName, string typeNamespace, 
            Type declaredType, DataContractResolver knownTypeResolver) { 

     return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) ?? declaredType; 
    } 

호스트 코드 (서비스 또는 명령 줄) :

using (ServiceHost service_host = new ServiceHost(typeof(GatewayServer))) { 

// Setup DataContractResolver for GatewayProcessing to GatewayData resolution: 
DeserializeAsBaseResolver.Install(service_host); 

// Open the host and start listening for incoming messages. 
try { service_host.Open(); } 
3

알려진 유형은이 문제를 해결하지 못합니다.

서버에서 사용중인 개체 모델과 사용중인 서비스 계약간에 심각한 차이가있는 것처럼 들릴 수 있습니다. 세 가지 가능한 솔루션이있는 것으로 보입니다.

1) 모든 작업에서 자동으로 확인하도록 지정한 Data Contract Resolver. 이 중 하나를 포함하여 많은 예제가 있습니다 : http://blogs.msdn.com/b/youssefm/archive/2009/06/05/introducing-a-new-datacontractserializer-feature-the-datacontractresolver.aspx.

2) 서비스 계약에 더 잘 부합하도록 개체 모델을 맞 춥니 다. 즉, BaseThing-DerivedThing 관계를 관리하기 위해 상속이 아닌 포함을 사용하십시오. 그런 식으로 서버에서 DerivedThing으로 작업하고 단순히 DerivedThing.BaseThing을 반환합니다. BaseThing을 클라이언트에서 서버로 전송해야하는 경우에도 더 효과적입니다.

3) AutoMapper와 같은 것을 사용하여 명시 적 변환을 사용하면 서버에서 사용중인 개체와 외부에 노출 된 개체간에 차이가 있음을 작업에서 분명히 알 수 있습니다.

+0

내가 이름을 강조하기 원하기 때문에 아래에있는 내 자신의 대답을 받아 변경했습니다 = "BaseClass"apprach는 내가 찾고 있던 것입니다. 귀하의 의견을 보내 주셔서 감사합니다. +1 KnownType은 해결되지 않습니다. – Ricibob