2013-06-17 32 views
6

Khi tôi gọi một phương thức của dịch vụ Xà phòng WCF của tôi, một lỗi được ném và một lỗi xuất hiện trong các tập tin svlog:Sự cố WCF với các loại?

Loại 'xxx.ActiveDirectoryService.classes.WCF.Message' bằng tên hợp đồng dữ liệu 'Message : http://schemas.datacontract.org/2004/07/xxx.ActiveDirectoryService.classes.WCF 'không được mong đợi. Hãy xem xét sử dụng một DataContractResolver hoặc thêm bất kỳ loại không được biết đến tĩnh danh sách các loại đã 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 loại đã biết được truyền cho DataContractSerializer.

Tôi đã cố gắng sử dụng KnownType tại đây và ở đó nhưng không thành công (Tôi phải thừa nhận rằng mình không chắc mình đã sử dụng 100% quyền).

Dưới đây là giao diện của tôi/classes:

[ServiceContract] 
public interface IActiveDirectory 
{ 
    [OperationContract] 
    [WebGet] 
    void Dummy(); 

    [OperationContract] 
    [WebGet] 
    AbstractMessage Dummy2(); 

    [OperationContract] 
    [WebGet] 
    AbstractMessage Dummy3(); 

    [OperationContract] 
    [WebGet] 
    AbstractMessage SetPassWord(string customer, string customerPassword, string userLogin, string userPassword); 
} 

[DataContract] 
public abstract class AbstractMessage 
{ 
    [DataMember] 
    public virtual bool IsError { get; set; } 

    [DataMember] 
    public virtual string ErrorMessage { get; set; } 

    [DataMember] 
    public virtual string ReturnValue { get; set; } 
} 

public class Message : AbstractMessage 
{ 
<...> 
} 


[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] 
[KnownType(typeof(AbstractMessage))] 
public class ActiveDirectory : IActiveDirectory 
{ 
    public void Dummy() 
    { 
    } 

    public AbstractMessage Dummy2() 
    { 
     return new AbstractMessage(); 
    } 

    public AbstractMessage Dummy3() 
    { 
     return new Message(); 
    } 

    public AbstractMessage SetPassWord(string customer, string customerPassword, string userLogin, string userPassword) 
    { 
    <...> 

     return message; // message is of type Message 
    } 
} 

Edit:12AM35 GMT+1

tôi thêm Dummy() phương pháp.

  • Gọi giả từ khách hàng hoạt động tốt.
  • Gọi Dummy2 từ máy khách hoạt động tốt.
  • Gọi Dummy3 từ máy khách cũng gây ra lỗi tương tự.

Sửa12AM39 GMT+1

Làm các thay đổi sau không giúp đỡ.

[DataContract] 
[KnownType(typeof(AbstractMessage))] 
public class Message : AbstractMessage 

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] 
[KnownType(typeof(AbstractMessage))] 
[KnownType(typeof(Message))] 
public class ActiveDirectory : IActiveDirectory 

Edit:13AM31 GMT+1

Nếu tôi đặt Dummy3 kiểu trả về để nhắn, cuộc gọi đến Dummy3 trong công việc mã khách hàng.
Có điều gì đó kỳ quặc với WCF + Đa ​​hình ...

Trả lời

3

Bạn dịch vụ WCF cần trả lại DTO.Đây không thể là các giao diện và nếu bạn muốn trả về các lớp cơ sở trừu tượng thì bạn sẽ cần phải nói cho serialiser hợp đồng dữ liệu triển khai thực hiện các kiểu mà bạn thực sự có ý định trả về.

Nó đã biết về loại AbstractMessage (như là một phần của hợp đồng hoạt động), nhưng tất cả việc triển khai loại đó không được khai báo rõ ràng trong hợp đồng hoạt động sẽ được khai báo trong các loại đã biết.

thử thêm này:

[ServiceContract] 
[ServiceKnownType(typeof(Message))] 
public interface IActiveDirectory 
{ 
    ... 
} 

Ở đây bạn đang nói hợp đồng serialiser dữ liệu rằng dịch vụ này có thể trở lại (hoặc mong đợi) đối tượng thuộc loại Message làm đối số cho phương thức của nó.

và điều này nên làm việc cũng như:

[DataContract] 
[KnownType(typeof(Message))] 
public abstract class AbstractMessage 
{ 
    ... 
} 

như bạn muốn nói với các serialiser hợp đồng dữ liệu mà Message là một loại tiếng của AbstractMessage

Tôi tin rằng những thay đổi của bạn không làm việc như bạn sử dụng KnownTypes trên dịch vụ thay vì ServiceKnownTypes và bạn đã cố gắng áp dụng kiểu đã biết trên lớp dẫn xuất chứ không phải lớp cha, đó là những gì bạn thường làm trong ngôn ngữ (Message là AbstractMessage) nhưng trong WCF bạn phải lật nó hơn và đặt các triển khai có nguồn gốc trên lớp cha (AbstractMessage h như Thông báo triển khai) có thể bị hạn chế.

bạn nói: There 's something odd with WCF + Polymorphism...

tin tưởng tôi, nó tốt hơn để không nghĩ về WCF như hỗ trợ polymophism, vì nó không. Bạn chỉ cần trả lại DTO và nếu bạn muốn thử và thực hiện các đa hình này, bạn sẽ gặp phải rất nhiều vấn đề. Đa hình được thực hiện bằng cách sử dụng giao diện và bạn không thể sử dụng giao diện trong WCF. Nếu bạn sử dụng các lớp trừu tượng thì do thiếu nhiều thừa kế trong C# bạn sẽ sớm nhận ra rằng DTO chỉ có thể biểu diễn một khung nhìn duy nhất của đối tượng của bạn và bạn không thể tạo DTO đại diện cho nhiều giao diện của một lớp mô hình miền. (Xem this question về đề tài này)

Xem answer here tôi để biết chi tiết về cách bạn có thể vượt qua trên những kiến ​​thức của các loại được biết đến, hoặc thông qua KnownTypes, ServiceKnownTypes hoặc cấu hình.

+0

[KnownType (typeof (Message))] hoạt động tốt nhưng tôi đã phải cập nhật tài liệu tham khảo của khách hàng (mà tôi đã không làm cho đến một vài phút trước). – Serge

0

Tôi đã gặp vấn đề đó một lần. Trong trường hợp của tôi, và như xa như tôi đã có thể tìm hiểu, wcf-serializers yêu cầu các loại không trừu tượng để làm việc propery. Vì vậy, trong trường hợp của tôi, chuyển từ các lớp trừu tượng và các giao diện sang các đối tượng bình thường làm cho nó hoạt động.

+0

Tôi đã thử những gì bạn nói nhưng không giúp ích gì. – Serge

3
[KnownType(typeof(AbstractMessage))] 

Trình biên dịch đã nhận ra rằng bạn trả về AbstractMessage. Những gì nó không thể tìm ra từ các mô tả là những trường hợp có nguồn gốc từ AbstractMessage. Đó là những loại mà bạn cần phải biết. Bất kỳ loại nào bạn bắt nguồn từ AbstractMessage và bạn quay lại ở đó cần phải là một loại đã biết và điều này cần được khai báo trên AbstractMessage chính nó.

[KnownType(typeof(DerivedMessage1))] 
[KnownType(typeof(DerivedMessage2))] 
[KnownType(typeof(DerivedMessage3))] 

Trong trường hợp của bạn, bạn cần thuộc tính để nói với serializer hợp đồng dữ liệu: "hey, như bạn có thể thấy tôi sẽ trả về một AbstractMessage, nhưng những gì bạn không thể nào biết: trong thực tế, đó là một Message":

[ServiceBehavior(...)] 
[KnownType(typeof(Message))] 
public class ActiveDirectory : IActiveDirectory 
{ 
    public AbstractMessage Dummy3() 
    { 
     return new Message(); 
    } 
} 
+0

Bạn có thể kiểm tra chỉnh sửa 12:39 của tôi không vì tôi phản ánh những gì tôi đã hiểu về câu trả lời của bạn. – Serge

+0

Có vẻ ổn. Bạn sẽ không bao giờ cần AbstractMessage như kiểu đã biết vì loại đó có thể được suy ra từ chữ ký phương thức. Bạn chỉ cần thuộc tính KnownType trên lớp dịch vụ khi nó xử lý các kiểu không được bao gồm trong vùng tên hệ thống hoặc trong chính chữ ký của phương thức đó. – nvoigt

+0

Nó không hoạt động. – Serge