2010-07-26 31 views
6

Tôi đang cố triển khai hợp đồng dịch vụ chứa phương thức có giao diện chung và giao diện chung chung đó được cung cấp thông số giao diện. Tôi đã được trang trí giao diện dịch vụ với ServiceKnownType, tôi đã trang trí thực hiện dịch vụ với KnownType thường xuyên, và tôi đã được trang trí thi DataContract với KnownType thường xuyên:WCF: Tuần tự hóa của một giao diện chung có thể không?

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallbacks))] 
[ServiceKnownType(typeof(Batch<object>))] 
[ServiceKnownType(typeof(Command))] 
public interface IActions 
{ 
    [OperationContract] 
    IResponse TakeAction(IBatch<ICommand> commands); 
} 

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)] 
[KnownType(typeof(Batch<object>))] 
[KnownType(typeof(Command))] 
internal class Actions : IActions 
{ 
} 

[DataContract] 
[KnownType(typeof(Command))] 
public class Batch<T> : IBatch<T> 
{ 
} 

Đối với hồ sơ, tôi có hàng loạt ở đó vì có vẻ như bạn chỉ có thể thể hiện một kiểu biết cho một kiểu generic một lần - nó xuất hiện để phát ra BatchOfanyType, nhưng tôi không chắc chắn cách xử lý này.

Ngoại lệ tôi nhận được là "Thêm bất kỳ loại nào không được biết đến tĩnh vào 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 thêm chúng vào danh sách các loại đã biết được chuyển đến DataContractSerializer."

Có điều gì hiển nhiên tôi đang làm sai không? Giao diện chung của giao diện có được hỗ trợ không? Đối với hồ sơ tôi đang trên C# 2.0 và .NET 3.0 cho dự án này.

Trả lời

12

Bạn có thể sử dụng giao diện trong định nghĩa hợp đồng dịch vụ nếu bạn thực sự muốn, miễn là bạn bao gồm các loại đã biết như bạn đang làm (với điều chỉnh nhỏ, xem bên dưới).

Dường như, việc sử dụng giao diện làm thông số loại chung sẽ lấy nó là cây cầu quá xa đối với C# 3.0. Tôi đã thay đổi thuộc tính type đã biết thành

[ServiceKnownType(typeof(Batch<Command>))] 
public interface IActions 
{ 
} 

Làm cho nó hoạt động, đến một điểm. Serialization và deserialization bản thân sẽ làm việc, nhưng sau đó bạn đang phải đối mặt với ngoại lệ này:

Không thể cast đối tượng của loại 'Batch`1 [lệnh] để gõ 'IBatch`1 [ICommand]'.

Để dàn diễn viên đó hoạt động, bạn cần hỗ trợ ngôn ngữ cho hiệp phương sai loại chung, thứ được giới thiệu trong C# 4.0. Đối với nó để làm việc trong C# 4.0 mặc dù, bạn sẽ cần phải thêm một sửa đổi phương sai:

public interface IBatch<out T> 
{ 
} 

Sau đó, nó hoạt động hoàn hảo ... tiếc là bạn không sử dụng C# 4.0. Một điều cuối cùng về việc sử dụng giao diện trong hợp đồng dịch vụ của bạn: nếu bạn đang tạo tham chiếu dịch vụ từ họ, nó sẽ nhập tất cả các tham số giao diện là object, vì loại giao diện gốc không phải là một phần của siêu dữ liệu. Bạn có thể chia sẻ các hợp đồng thông qua một tham chiếu assembly, hoặc refactor bằng tay proxy đã tạo để sửa nó, nhưng tất cả trong tất cả, sử dụng giao diện với WCF có lẽ là rắc rối nhiều hơn giá trị của nó.

+0

Vâng, tôi đã chỉnh sửa trên nền tảng tôi đang sử dụng khi tôi nghĩ về hiệp phương sai trong C# 4.0. Oh, để nâng cấp. – bwerks

2

WCF là một hệ thống dựa trên thông điệp SOA - nó có thể gửi bất kỳ thứ gì qua dây theo định dạng XML được tuần tự hóa có thể được biểu diễn trong lược đồ XML.

Thật không may, lược đồ XML không biết gì cả về giao diện cũng như generics, vì vậy không - bạn không thể sắp xếp theo thứ tự những thứ đó - bạn cần sử dụng các loại cụ thể.

+0

WCF hiểu thấu đáo đủ để tuần tự hóa chúng (tôi đã thực hiện nó)). Điểm của bạn trên Giao diện là chính xác. – RQDQ

+0

@RQDQ bạn có một nơi để thể hiện điều đó không? Blog, bài viết CodeProject hay gì đó? Thích thấy điều đó! –

+1

@RQDQ: Thực ra, nó không hoàn toàn chính xác, imo. Mặc dù bản thân giao diện không thể được tuần tự hóa, loại bê tông được sử dụng * có thể *. Phần 'khó khăn' là deserialization, bởi vì nó cần phải biết loại bê tông để nhanh chóng. Tuy nhiên, đủ thông tin được bao gồm trong dữ liệu được tuần tự hóa để thực hiện chính xác điều đó. – Thorarin

1

Bạn không thể tuần tự hóa giao diện. Một giao diện chỉ định nghĩa hợp đồng chứ không phải đối tượng. Tôi đoán rằng một ngoại lệ cho điều này là giao diện ISerializable.

+1

Khi bạn đang "serialize" ISerializable' ", bạn không, thực sự. 'ISerializable' là một giao diện được sử dụng để sắp xếp thứ tự khác. –

+0

@John. Bạn nói đúng. Bạn vẫn không thực sự serializing giao diện, chỉ cần đồng ý về một hợp đồng được sử dụng để serialize các đối tượng thực hiện ISerializable. Tôi chỉ cần thêm điều này cho đầy đủ. – Mike

1

Generics có thể được đăng, nhưng với một số giới hạn nhất định.Ví dụ, với các hợp đồng dữ liệu:

[DataContract] 
public class Foo<T> 
{ 
    [DataMember] 
    public T Value { get; set; } 
} 

Và hợp đồng dịch vụ:

[ServiceContract] 
public interface IService1 
{ 
    [OperationContract] 
    Foo<String> GetData(); 
} 

Và việc thực hiện dịch vụ:

public class Service1 : IService1 
{ 
    public Foo<string> GetData() 
    { 
     return new Foo<string>() { Value = "My test string" }; 
    } 
} 

Sau khi thiết lập một tham khảo dịch vụ với dịch vụ trên, này mã có thể chạy:

ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(); 

ServiceReference1.FooOfstring temp = client.GetData(); 

MessageBox.Show(temp.Value); 

Và hộp tin nhắn với "Chuỗi thử nghiệm của tôi" được hiển thị.

Lưu ý rằng bản thân dịch vụ không phải là chung chung, nhưng hợp đồng dữ liệu được sử dụng là. Hơn nữa, hợp đồng dữ liệu được tạo ra ở phía máy khách không phải là chung chung, mà đúng hơn là một lớp "phẳng" có giá trị thuộc tính của chuỗi kiểu:

[System.Runtime.Serialization.DataMemberAttribute()] 
public string Value 
{ 
    get {...} 
    set {...} 
} 
Các vấn đề liên quan