2010-01-29 31 views
6

Tôi đã cố gắng sử dụng ứng dụng SilverLight để gọi dịch vụ WC.Net ASP.Net sẽ trả về Dictionary<string, object>. Điều đó làm việc tốt khi các giá trị trong từ điển là các loại đơn giản như int, string hoặc Guid.Dịch vụ WCF trả về một mảng từ điển <string, object>

Tuy nhiên, bây giờ tôi có một kịch bản mà tôi cần một trong các giá trị là một mảng Dictionary<string, object>! Tất cả đều biên dịch tốt và chữ ký của dịch vụ không thay đổi nhưng cuộc gọi dịch vụ hiện không thành công.

Bất kỳ ý tưởng nào về cách khắc phục sự cố? Tôi đã cố gắng chú thích lớp dịch vụ và phương pháp của mình với thuộc tính KnownTypeServiceKnownType nhưng không hoạt động.

Dưới đây là một đoạn mã:

[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" }, 
             } 
           } 
      } 
     }; 
    } 
} 

Cảm ơn bạn đã trả lời của bạn. Tôi đã bật WCF truy tìm và, như nghi ngờ, có một vấn đề trong quá trình serialization. Sự cố không phải là sự tuần tự hóa Dictionary<string, object> nhưng là một trong số Array của Dictionary<string, object>.

Đây là ngoại lệ được ghi bởi dịch vụ WCF.

Đã xảy ra lỗi khi cố gắng sắp xếp tham số: GetObjectResult. Thông điệp InnerException là 'Loại' System.Collections.Generic.Dictionary`2 [[System.String, mscorlib, Phiên bản = 2.0.0.0, Văn hóa = trung lập, PublicKeyToken = b77a5c561934e089], [System.Object, mscorlib, Phiên bản = 2.0. 0.0, Văn hóa = trung lập, PublicKeyToken = b77a5c561934e089]] [] 'với tên hợp đồng dữ liệu' ArrayOfArrayOfKeyValueOfstringanyType: http://schemas.microsoft.com/2003/10/Serialization/Arrays 'không được mong đợi. Thêm bất kỳ loại nào không được biết đến tĩnh vào danh sách các kiểu đã biết - ví dụ, bằng cách sử dụng thuộc tính KnownTypeAttribute hoặc bằng cách thêm chúng vào danh sách các kiểu đã biết được truyền cho DataContractSerializer. '. Vui lòng xem InnerException để biết thêm chi tiết.

Tôi cũng cố gắng xác định lớp DataContract mới với một thành viên dữ liệu duy nhất nhưng dẫn đến lỗi rất giống nhau.

Đây là mã cho điều đó, theo sau là ngoại lệ được ghi nhật ký bằng ghi nhật ký WCF.

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

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

Có lỗi trong khi cố gắng để serialize tham số: GetObjectResult. Thông điệp InnerException là 'Loại' System.Collections.Generic.Dictionary`2 [[System.String, mscorlib, Phiên bản = 2.0.0.0, Văn hóa = trung lập, PublicKeyToken = b77a5c561934e089], [SilverlightApplication7.Web.ObjectHolder, SilverlightApplication7.Web, Phiên bản = 1.0.0.0, Văn hóa = trung lập, PublicKeyToken = null]] [] 'với tên hợp đồng dữ liệu' ArrayOfArrayOfKeyValueOfstringObjectHolderWAwxSTlb: http://schemas.microsoft.com/2003/10/Serialization/Arrays 'không được mong đợi. Thêm bất kỳ loại nào không được biết đến tĩnh vào danh sách các kiểu đã biết - ví dụ, bằng cách sử dụng thuộc tính KnownTypeAttribute hoặc bằng cách thêm chúng vào danh sách các kiểu đã biết được truyền cho DataContractSerializer. '. Vui lòng xem InnerException để biết thêm chi tiết.

Một lần nữa tôi đã chơi với ServiceKnownType cho ObjectHolder, ObjectHolder[] và thậm chí ObjectHolder[][] kể từ khi ngoại lệ đề cập đến một "ArrayOfArrayOfKeyValueOfstringObjectHolder".

Vẫn chưa có giải pháp nào.

+0

Bạn nhận được lỗi nào? –

+0

Đoán của tôi sẽ là WCF có thể gặp khó khăn trong việc nối tiếp đối tượng. Bạn có thể thử làm từ điển của bạn nếu đó là khả thi. – sipwiz

+0

Tôi đồng ý với sipwiz, bạn sẽ gặp trục trặc khi sắp xếp thứ tự từ điển. Bạn nên làm cho từ điển chứa một đối tượng có thể tuần tự hóa (nghĩa là bạn cần thay đổi từ điển của bạn bằng Dictionary srodriguez

Trả lời

0

Hãy thử xác định một lớp có một thuộc tính duy nhất. Thuộc tính đó là một từ điển của chuỗi, đối tượng.

Đánh dấu lớp học bằng DataContract/DataMember. Sau đó, xác định giao diện của bạn bằng cách sử dụng lớp đó.

8

Trước hết, bạn nên configure WCF tracing trong tệp cofig ứng dụng có thể giúp bạn hiểu điều gì sẽ xảy ra dưới sự che chở của truyền thông dịch vụ. Trong trường hợp này, bạn có thể dễ dàng nhận được tất cả các lỗi xảy ra trong quá trình giao tiếp.

Bây giờ, hãy thử giải quyết vấn đề của bạn. Tôi gần như tự tin rằng vấn đề trong các loại được biết đến. Trong thế giới hướng dịch vụ, bạn nên tự xác định tất cả các loại cụ thể có thể tham gia vào hợp đồng dịch vụ, bởi vì DataContractSerializer không cung cấp thông tin như vậy trong các đối tượng được tuần tự hóa.

Trong trường hợp này có nghĩa là, bạn nên làm như sau:

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

Ngoài ra tôi nên bạn không sử dụng đối tượng trong hợp đồng dịch vụ bởi vì nó rất dễ bị lỗi. Xem xét, mà sau này bạn hoặc một trong các đồng nghiệp của bạn sẽ thay đổi một dòng mã:

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

Trong trường hợp này, khi dịch vụ của bạn cố gắng để trở lại từ điển này bạn gặp thất bại thời gian chạy vì DataContractSerializer không mong đợi SomeClass trong hợp đồng này.

Một cách để giải quyết vấn đề này là tạo ra loại riêng biệt:

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

Trong trường hợp này nếu bạn muốn thêm một số loại mới, bạn nên thêm phương pháp nhà máy và KnownTypeAttribute (phương pháp này tiết hơn, nhưng ít dễ bị lỗi).

Tuy nhiên, nếu khách hàng và dịch vụ của bạn được viết trên WCF, bạn có thể hy sinh các nguyên tắc hướng dịch vụ chính và sử dụng NetDataContractSerializer thay vì DataContractSerializer. NetDataContractSerializer được thiết kế để bổ sung DataContractSerializer. Bạn có thể tuần tự hóa một kiểu bằng cách sử dụng NetDataContractSerializer và deserialize với DataContractSerializer. Nhưng NetDataContractSerializer bao gồm thông tin kiểu CLR trong XML được tuần tự hóa, trong khi đó DataContractSerializer thì không. Vì vậy, NetDataContractSerializer có thể được sử dụng trong serialization và deserialization với bất kỳ loại CLR mà không có bất kỳ công cụ KnownTypes.

+0

Đây là câu trả lời hay nhất, bạn có thể cải thiện nó bằng cách chỉ ra rằng nó không phải là Từ điển là loại không xác định, mà là các kiểu đối tượng có trong từ điển.Đó là lý do tại sao thêm [ServiceKnownType (typeof (Dictionary ))] không hỗ trợ, trong khi thêm [ServiceKnownType (typeof (types_which_the_object_might_be)]. –

0

Tuy nhiên, bây giờ tôi có một kịch bản mà tôi cần một trong các giá trị là một mảng từ điển!

Vấn đề là WCF không biết làm thế nào để serializer/deserialize một mảng của các đối tượng mà không được đánh dấu bằng DataMember thuộc tính và/hoặc không được thêm vào ServiceKnownType s.

Ví dụ, nếu có một số phương pháp dịch vụ, mà phải mất một đối tượng tùy ý như một tham số

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

và bạn muốn vượt qua, nói một mảng các số nguyên Integer(), bạn phải thêm một cách rõ ràng mảng này của số nguyên nhập vào các loại dịch vụ đã biết.

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

Sau đó, phương pháp dịch vụ có thể được gọi

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

Bất kỳ ý tưởng làm thế nào để sửa chữa nó?

Hãy thử thêm thuộc tính <ServiceKnownType(GetType(Dictionary(Of String, Object)()))>.

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