2009-08-31 28 views
5

Tôi có một ứng dụng mà khách hàng và máy chủ chia sẻ các loại, và khả năng tương tác không phải là một trong những mối quan tâm của chúng tôi. Tôi đang có kế hoạch để có một kho lưu trữ duy nhất cho tất cả các đối tượng kích hoạt web, và tôi đã suy nghĩ về một giao diện chung cho dịch vụ tiếp xúc của tôi.wcf phơi bày generics

cái gì đó như T GetObject (int id)

nhưng WCF doesnt như nó kể từ khi nó cố gắng để lộ sơ đồ của nó (mà tôi không thực sự quan tâm đến)

là nó có thể làm một điều như vậy với WCF ?, tôi có thể sử dụng bất kỳ loại ràng buộc nào không phải là httpbinding hoặc wsbinding ...

+0

Xem thêm http://stackoverflow.com/questions/6223886/generic-service-interface –

Trả lời

2

Tôi cho rằng điều này là có thể, mặc dù tôi không chắc chắn bạn muốn điều này. Tôi sẽ đi theo cách tiếp cận sau đây (chưa được kiểm tra, không chắc chắn nếu nó hoạt động).Đầu tiên tạo nên cấu trúc dự án sau đây trong giải pháp của bạn:

  • ServiceInterfaces
  • ServiceImplementations (tài liệu tham khảo ServiceInterfacesModelClasses)
  • ModelClasses
  • Host (tài liệu tham khảo ServiceInterfacesServiceImplementations)
  • Client (tài liệu tham khảo ServiceInterfacesModelClasses)

Trong ServiceInterfaces bạn có một giao diện như thế này (tôi bỏ qua không gian tên, vv để làm ví dụ ngắn hơn):

[ServiceContract] 
public interface IMyService<T> 
{ 
    T GetObject(int id); 
} 

Trong ServiceImplementations bạn có một lớp mà thực hiện IMyService<T>:

public class MyService<T> : IMyService<T> 
{ 
    T GetObject(int id) 
    { 
     // Create something of type T and return it. Rather difficult 
     // since you only know the type at runtime. 
    } 
} 

Trong Host bạn có cấu hình chính xác cho dịch vụ của mình trong một tệp App.config (hoặc Web.config) và mã sau để lưu trữ dịch vụ của bạn (do đó là ứng dụng độc lập) :

ServiceHost host = new ServiceHost(typeof(MessageManager.MessageManagerService)) 
host.Open(); 

Và cuối cùng trong Client bạn sử dụng một lớp ChannelFactory<TChannel> để xác định một proxy:

Binding binding = new BasicHttpBinding(); // For the example, could be another binding. 
EndpointAddress address = new EndpointAddress("http://localhost:8000/......"); 
IMyService<string> myService = 
    ChannelFactory<IMyService<string>>.CreateChannel(binding, address); 
string myObject = myService.GetObject(42); 

Một lần nữa, tôi không chắc chắn nếu làm việc này. Bí quyết là chia sẻ các giao diện dịch vụ của bạn (trong ServiceInterfaces) và các đối tượng mô hình miền (trong ModelClasses) giữa máy chủ và máy khách. Trong ví dụ của tôi, tôi sử dụng một chuỗi để trả về từ phương thức dịch vụ nhưng nó có thể là bất kỳ loại hợp đồng dữ liệu nào từ dự án ModelClasses.

+0

tôi có thể tham khảo cùng một hội đồng trên máy khách và sử dụng tab trước của dịch vụ tham chiếu utlity (tôi đoán svcutil) để chia sẻ các loại, hoạt động, nhưng bây giờ tôi muốn làm là trừu tượng, đoán tôi đang tìm kiếm một loại remotint giải pháp, nhưng nên có thể trên wcf ... –

+0

Bạn nên _not_ sử dụng hộp thoại 'Thêm dịch vụ tham khảo' trong Visual Studio cho cách tiếp cận của tôi. Điều đó sẽ không hoạt động. Đó là lý do tại sao tôi sử dụng lớp ChannelFactory . Nó tạo ra một proxy thực hiện giao diện dịch vụ của bạn trên bay, mà không cần siêu dữ liệu. –

+0

Điều này rất có thể sẽ không hoạt động (tôi không thể kiểm tra ngay bây giờ), vì bạn xác định một dịch vụ có các hoạt động trả về loại "T" chung nhưng để hoạt động đúng, loại "T" đó phải là DataContract, để ngăn xếp WCF có thể tuần tự hóa và deserialize đối tượng của loại đó. Hãy nhớ rằng: tất cả các bạn chuyển giữa máy khách và máy chủ là ** tin nhắn ** - không có tham chiếu đối tượng hoặc tham chiếu giao diện hoặc bất kỳ thứ gì dựa trên tham chiếu! Bạn ** phải ** có thể serialize yêu cầu của bạn vào một số định dạng tin nhắn, và deserialize nó trở lại vào đầu kia - mà sẽ không làm việc với generics :-( –

8

Không, bạn không thể. Dù bạn muốn hay cần sự tương tác, nền tảng cơ bản nhất của WCF là trao đổi tin nhắn.

Máy khách gửi tin nhắn cho máy chủ và nhận phản hồi. Thông điệp đó là tất cả thông qua giữa máy khách và máy chủ, và cần phải được tuần tự hóa thành một định dạng XML hoặc nhị phân. Đó là lý do tại sao bất kỳ dữ liệu nào được truyền xung quanh phải là nguyên tử (như int, string) hoặc DataContract - một mô tả cho ngăn xếp dịch vụ WCF về cách serialize và deserialize các đối tượng đó.

Bạn không thể vượt qua bất kỳ giao diện nào hoặc "mẹo nhỏ" khác - tất cả những gì xảy ra giữa máy khách và máy chủ phải được thể hiện trong lược đồ XML, về cơ bản.

Vì vậy, tôi sợ những gì bạn đang cố gắng đạt được hoàn toàn trái ngược với những gì WCF cung cấp. Thế giới và các mô hình của SOA (Các ứng dụng hướng dịch vụ) khá khác nhau và không phải lúc nào cũng đồng bộ 100% với ý tưởng và cơ chế của OOP.

Marc

+0

vì vậy nếu ai đó muốn làm điều này, ngăn xếp công nghệ nào MS cung cấp, nó có phù hợp hơn để truy cập từ xa (nếu vẫn còn sống) ? Ms không mở rộng hỗ trợ cho các loại chia sẻ (netcontractserializer etc) –

+0

Tôi không biết nếu có bất kỳ giải pháp hiện tại cho remoting đối tượng - đó là cơ bản những gì bạn đang cố gắng để làm. Cách tiếp cận này có chia sẻ các vấn đề, mà MS cố gắng giải quyết với WCF - nhưng để giải quyết nó, người ta phải đi đến một mô hình hoàn toàn dựa trên thông điệp, cái mà không làm việc tốt với các giao diện và generics. Có, nó hỗ trợ chia sẻ các loại BÊ TÔNG - nhưng chắc chắn không phải là giao diện, và không thực sự là generics. –

0

Bạn CÓ THỂ LÀM điều đó nếu bạn sử dụng ServiceKnownTypesDiscovery.

Ví dụ:

[ServiceKnownType("GetKnownTypes", typeof(ServiceKnownTypesDiscovery))] 
public interface ISomeService 
{ 
    [OperationContract] 
    object Request(IRequestBase parameters); 
} 

nơi GetKnownTypes có thể được khai báo như sau:

public static class ServiceKnownTypesDiscovery 
{ 
    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider) 
    { 
     var types = new List<Type>(); 

     foreach (var asmFile in Directory.GetFiles(AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory, "*.dll")) 
     { 
      Assembly asm = Assembly.LoadFrom(asmFile); 
      types.AddRange(asm.GetTypes().Where(p=> Attribute.IsDefined(p,typeof(DataContractAttribute)))); 
     } 

     return types; 
    } 
} 

Trong trường hợp này tất cả những gì đã tuyên bố với [DataContract] (miễn là họ có thể phát hiện trên máy chủ VÀ phía máy khách) có thể được tuần tự hóa.

Tôi hy vọng điều này sẽ hữu ích!

+1

Nhưng ... giải pháp của bạn không sử dụng Generics –

0

Làm theo ví dụ trước, bạn có thể khai báo DataContract với đối tượng là DataMember. Sau đó, bạn có thể thêm một phương thức mở rộng để nhận và thiết lập một kiểu generic trên thành phần dữ liệu đối tượng. Bạn cũng có thể làm cho nội bộ này, theo cách này bạn sẽ có nghĩa vụ phải sử dụng các phương thức mở rộng để nhận và đặt giá trị.

Tất nhiên, nó chỉ hoạt động nếu bạn tạo máy khách bằng cách sử dụng svcutil (hoặc Visual Studio) và tham chiếu assembly có chứa hợp đồng dữ liệu và lớp với phương thức mở rộng.

Hy vọng điều này sẽ giúp ...

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