2010-01-29 4 views
6

Silverlight 클라이언트를 사용하여 Dictionary<string, object>을 반환하는 ASP.Net WCF 서비스를 호출하려고했습니다. 사전에있는 값이 int, string 또는 Guid과 같은 단순한 유형 인 경우 제대로 작동합니다.사전 배열 <string, object>를 반환하는 WCF 서비스

그러나 이제는 값 중 하나가 Dictionary<string, object>의 배열이되어야하는 시나리오가 있습니다! 모두 잘 컴파일되고 서비스의 서명은 변경되지 않았지만 이제는 서비스 호출이 실패합니다.

아이디어를 고치는 방법은 무엇입니까? KnownTypeServiceKnownType 속성을 사용하여 서비스 클래스 및 메서드에 주석을 추가하려고했지만 작동하지 않았습니다.

[ServiceContract(Namespace = "")] 
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] 
public class Service1 
{ 
    [OperationContract] 
    [ServiceKnownType(typeof(Dictionary<string, object>))] 
    public Dictionary<string, object> GetObject() 
    { 
     return new Dictionary<string, object>() 
      { 
       { "pty1", 1 }, 
       { "pty2", Guid.NewGuid() }, 
       { "pty3", "blah" }, 
       { "pty4", new Dictionary<string, object>[] 
           { 
            new Dictionary<string, object>() 
             { 
              { "pty1", 4 }, 
              { "pty2", Guid.NewGuid() }, 
              { "pty3", "blah" }, 
             } 
            , 
            new Dictionary<string, object>() 
             { 
              { "pty1", 4 }, 
              { "pty2", Guid.NewGuid() }, 
              { "pty3", "blahblah" }, 
             } 
           } 
      } 
     }; 
    } 
} 

귀하의 답변을 주셔서 감사합니다 : 여기

코드의 조각이다. WCF 추적을 켰으며 의심되는 것처럼 직렬화 중에 문제가 있습니다. 문제는 Dictionary<string, object>의 직렬화가 아니며 Array 중 하나는 Dictionary<string, object>입니다.

여기 WCF 서비스에서 기록한 예외입니다.

매개 변수를 직렬화하려고하는 동안 오류가 발생했습니다 : GetObjectResult. InnerException 메시지는 '형식'System.Collections.Generic.Dictionary`2 [[System.String, mscorlib, 버전 2.0.0.0, 문화 = 중립, PublicKeyToken = b77a5c561934e089], [System.Object, mscorlib, 버전 = 2.0. 0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]] [] '데이터 계약 이름이'ArrayOfArrayOfKeyValueOfstringanyType : http://schemas.microsoft.com/2003/10/Serialization/Arrays '인 것은 아닙니다. 알려진 유형 목록에 정적으로 알려지지 않은 유형을 추가하십시오 (예 : KnownTypeAttribute 속성을 사용하거나 DataContractSerializer에 전달 된 알려진 유형 목록에 추가). ' 자세한 내용은 InnerException을 참조하십시오.

단일 데이터 멤버를 사용하여 새로운 DataContract 클래스를 정의하려고 시도했지만 매우 오류가 발생합니다.

다음 코드는 WCF 로깅에서 로그 된 예외입니다. 매개 변수를 직렬화하는 동안

[DataContract] 
[KnownType(typeof(ObjectHolder))] 
public class ObjectHolder 
{ 
    [DataMember] 
    public object Object { get; private set; } 

    public ObjectHolder(object obj) 
    { 
     this.Object = obj; 
    } 
} 

오류가 발생했습니다 : GetObjectResult. InnerException 메시지가 'Type'System.Collections.Generic.Dictionary`2 [[System.String, mscorlib, 버전 2.0.0.0, 문화 = 중립, PublicKeyToken = b77a5c561934e089], [SilverlightApplication7.Web.ObjectHolder, SilverlightApplication7.Web, 버전 = 1.0.0.0, 문화 = 중립, PublicKeyToken = null]] [] '데이터 계약 이름이'ArrayOfArrayOfKeyValueOfstringObjectHolderWAwxSTlb : http://schemas.microsoft.com/2003/10/Serialization/Arrays '이 아닙니다. 알려진 유형 목록에 정적으로 알려지지 않은 유형을 추가하십시오 (예 : KnownTypeAttribute 속성을 사용하거나 DataContractSerializer에 전달 된 알려진 유형 목록에 추가). ' 자세한 내용은 InnerException을 참조하십시오. 예외가 "ArrayOfArrayOfKeyValueOfstringObjectHolder"을 언급 이후

는 다시 나는 ObjectHolder, ObjectHolder[] 심지어 ObjectHolder[][]에 대한 ServiceKnownType와 함께 연주했습니다.

아직 해결 방법이 없습니다.

+0

어떤 오류가 발생합니까? –

+0

내 생각 엔 WCF가 개체를 직렬화하는 데 문제가있을 수 있습니다. 가능하다면 사전을 만들 수도 있습니다. . – sipwiz

+0

나는 sipwiz에 동의한다. 당신은 dictionary를 직렬화하는 데 어려움을 겪을 것이다. 사전에 직렬화 할 수있는 객체가 있어야합니다 (Dictionary 로 Dictionary 를 변경해야 함을 의미 함) – srodriguez

답변

0

하나의 속성을 가진 클래스를 정의 해보십시오. 이 속성은 문자열, 객체 사전입니다.

DataContract/DataMember를 사용하여 클래스를 표시하십시오. 그런 다음 해당 클래스를 사용하여 인터페이스를 정의하십시오.

8

먼저 서비스 통합 커뮤니케이션의 후드에서 발생하는 상황을 파악하는 데 도움이되는 configure WCF tracing을 앱 cofig 파일에 입력해야합니다. 이 경우 통신 프로세스 중에 발생하는 모든 오류를 쉽게 얻을 수 있습니다.

이제 문제를 해결해 보겠습니다. 나는 거의 알려진 유형의 문제를 확신합니다. 서비스 지향 세계에서는 DataContractSerializer가 직렬화 된 개체에 이러한 정보를 제공하지 않기 때문에 서비스 계약에 참여할 수있는 모든 구체적인 유형을 수동으로 정의해야합니다.

이 경우 당신이 다음을 수행해야한다는 의미 : 당신은 서비스 계약에 물건을 사용하지 않습니다에
[ServiceKnownType(typeof(string))] 
[ServiceKnownType(typeof(Guid))] 
[ServiceKnownType(typeof(int))] // but I think DataContractSerializer can deal himself with primitives 
[ServiceKnownType(typeof(YourClass))] //UserDefined types you should add manually 
public Dictionary<string, object> GetObject() 

이 또한 내가 추천 그것은 아주 오류가 발생하기 쉬운 때문이다. 서비스가 DataContractSerializer이 계약에 SomeClass을 기대하지 않기 때문에 런타임 오류가 발생이 사전을 반환하려고 할 때,이 경우

new Dictionary<string, object>() 
{ 
{ "pty1", 4 }, 
{ "pty2", Guid.NewGuid() }, 
{ "pty3", new SomeClass() }, //OOPS!!! 
} 

: 나중에 당신이나 당신의 동료 중 하나가 한 줄의 코드를 수정하는 것을 고려하십시오. 당신이 공장 방법과 KnownTypeAttribute (더 자세한이 방법, 미만을 추가해야합니다, 당신은 몇 가지 새로운 유형을 추가 할 경우이 경우

[DataContract] 
[KnownType(typeof(Guid))] 
[KnownType(typeof(SomeClass1))] 
[KnownType(typeof(SomeClass2))] 
public class MyType 
{ 
    private MyType(object obj) { 
    Object = obj; 
    } 

    public static MyType FromSomeClass1(SomeClass1 c1) { 
    return new MyType(c1); 
    } 

    public static MyType FromSomeClass2(SomeClass2 c2) { 
    return new MyType(c2); 
    } 

    public static MyType FromGuid(Guid guid) { 
    return new MyType(guid); 
    } 

    [DataMember] 
    public object Object { get; private set; } 
} 

이 문제를 해결하기

한 가지 방법은 별도의 유형을 만드는 것입니다 발생하기 쉬운 오류).

그러나 클라이언트와 서비스가 WCF로 작성된 경우 주 서비스 지향 원칙을 희생하고 DataContractSerializer 대신 NetDataContractSerializer을 사용할 수 있습니다. NetDataContractSerializer는 DataContractSerializer를 보완하도록 설계되었습니다. NetDataContractSerializer를 사용하여 형식을 serialize하고 DataContractSerializer로 deserialize 할 수 있습니다. 그러나 DataContractSerializer는 직렬화 된 XML에 CLR 유형 정보를 포함하지만 NetDataContractSerializer에는 CLR 유형 정보가 포함됩니다. 따라서 NetDataContractSerializer는 KnownTypes 항목이없는 CLR 형식의 serialization 및 deserialization에 사용할 수 있습니다.

+0

알 수없는 형식이지만 사전에 포함 된 개체 형식이 아니라는 점을 지적하여 개선 할 수있는 최상의 대답입니다.이 때문에 [ServiceKnownType (typeof (Dictionary ))]는 도움이되지 않지만 [ServiceKnownType (typeof (types_which_the_object_might_be)]가 추가됩니다. –

0

그러나 이제는 사전 값 배열 중 하나가 필요합니다.

문제는 WCF가/시리얼 라이저 방법을 알고 DataMember 속성으로 표시되지 않은 및/또는 ServiceKnownType의 추가되지 않습니다 객체의 배열을 직렬화하지 않습니다. 일부 서비스 방법이있는 경우

는 예를 들어, 그 매개 변수

public interface IService 
    function DoSomething(Parameter as Object) as integer 
end interface 

같은 임의의 오브젝트를하면, 전달하려는 정수 Integer()의 배열, 당신은 명시 적으로 정수의 배열을 추가해야합니다 말 알려진 유형의 서비스를 입력하십시오.

<ServiceKnownType(GetType(Integer()))> 
public interface IService 
    function DoSomething(Parameter as Object) as integer 
end interface 

그런 다음 서비스 방법은

dim Service as IService 
dim Argument as Integer() 
Service.DoSomething(Argument) 

모든 아이디어를 어떻게 해결하는 방법을 호출 할 수 있습니다?

<ServiceKnownType(GetType(Dictionary(Of String, Object)()))> 속성을 추가해보세요.

관련 문제