2009-08-31 3 views
5

У меня есть приложение, в котором общие и клиентские и серверные типы разделов и взаимодействие не являются одной из наших проблем. Я планирую иметь единый репозиторий для всех объектов с поддержкой сети, и я думал о универсальном интерфейсе для моего открытого сервиса.wcf, отображающий общие файлы

что-то вроде T GetObject (интермедиат ид)

но ФОС не суммируется и не нравится, так как ее пытаются выставить свою схему (который я действительно не заботятся о)

является возможным сделать такую ​​вещь с WCF ?, я могу использовать любой тип привязки, не обязательно должен быть httpbinding или wsbinding ...

+0

См. Также http://stackoverflow.com/questions/6223886/generic-service-interface –

ответ

2

Я полагаю, что это возможно, хотя я не уверен, что вы хотите этого. Я бы взял следующий подход (непроверенный, не уверен, что он работает).Сначала нужно создать следующую структуру проекта в вашем решении:

  • ServiceInterfaces
  • ServiceImplementations (ссылки ServiceInterfaces и ModelClasses)
  • ModelClasses
  • Host (ссылки ServiceInterfaces и ServiceImplementations)
  • Client (ссылки ServiceInterfaces и ModelClasses)

В ServiceInterfaces у вас есть интерфейс, как это (я пропустил пространств имен, и т.д., чтобы сделать пример короче):

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

В ServiceImplementations у вас есть класс, который реализует 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. 
    } 
} 

В Host у вас есть правильная настройка для вашей службы в файле App.config (или Web.config) и следующем коде для размещения вашей службы (учитывая, что это автономное приложение) :

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

И, наконец, в Client вы используете ChannelFactory<TChannel> класс для определения прокси-сервера:

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); 

Опять же, я не уверен, если это работает. Хитрость заключается в обмене вашими интерфейсами обслуживания (в ServiceInterfaces) и объектами модели домена (в ModelClasses) между хостом и клиентом. В моем примере я использую строку для возврата из метода службы, но это может быть любой тип контракта данных из проекта ModelClasses.

+0

Я могу ссылаться на одни и те же сборки на клиенте и использовать вкладку аванса справки service utlity (я угадываю svcutil) для совместного использования типов, которые работают, но теперь я хочу сделать абстрактным, думаю, я ищу тип удаленного типа решение, но должно быть возможно на wcf ... –

+0

Вы не должны использовать диалоговое окно «Добавить служебную ссылку» в Visual Studio для моего подхода. Это не сработает. Вот почему я использую класс ChannelFactory . Он генерирует прокси-реализацию вашего сервисного интерфейса «на лету» без необходимости в метаданных. –

+0

Это, скорее всего, не сработает (я не могу проверить его прямо сейчас), поскольку вы определяете службу с операциями, которые возвращают общий тип «Т», но для правильной работы этот тип «Т» должен быть DataContract, так что стек WCF может сериализовать и десериализовать объекты этого типа. Помните: все, что вы проходите между клиентом и сервером, - это ** сообщения ** - нет ссылки на объект, ссылки на интерфейс или что-либо на основе ссылок! Вы ** должны ** уметь сериализовать ваш запрос в какой-то формат сообщения и десериализовать его обратно на другом конце - это не будет работать с generics :-( –

8

Нет, вы не можете. Независимо от того, хотите ли вы или нет совместимости, самой базовой основой WCF является обмен сообщениями.

Клиент отправляет серверу сообщение и возвращает ответ. Это сообщение - это все, что проходит между клиентом и сервером, и должно быть сериализовано в формате XML или двоичный. Вот почему любые передаваемые данные должны быть атомарными (например, int, string) или DataContract - описание стека служб WCF о том, как сериализовать и десериализовать такие объекты.

Вы не можете передавать какие-либо интерфейсы или другие «обманки» - все, что идет между клиентом и сервером, должно быть выражено в XML-схеме, в основном.

Так что я боюсь, что вы пытаетесь достичь, это совершенно противоречит тому, что предлагает WCF. Мир и парадигмы SOA (сервисно-ориентированные приложения) совершенно разные, и не всегда 100% синхронизируются с идеей и механизмами ООП.

Марк

+0

, так что если кто-то захочет это сделать, какой стек технологий предлагает MS, то он более подходит для удаленного доступа (если он еще жив) ? Ms действительно расширяет поддержку разделяемых типов (netcontractserializer и т. Д.) –

+0

Я не знаю, есть ли какое-либо текущее решение для удаленных объектов - это в основном то, что вы пытаетесь сделать. У этого подхода есть своя доля проблем, которые MS пытается решить с помощью WCF, но для ее решения нужно перейти к полностью основанной на сообщениях модели, которая не очень хорошо работает с интерфейсами и дженериками. Да, он поддерживает совместное использование типов CONCRETE - но определенно не интерфейсы, а не дженерики. –

0

ВЫ МОЖЕТЕ СДЕЛАТЬ, что если вы используете ServiceKnownTypesDiscovery.

Например:

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

где GetKnownTypes может быть объявлен следующим образом:

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

В этом случае все, объявленное с [DataContract] (до тех пор, как они обнаруживаемые на сервере и клиентская сторона) может быть сериализована.

Я надеюсь, что это помогло!

+1

Но ... ваше решение не использует generics –

0

Следуя предыдущему примеру, вы можете объявить DataContract с объектом DataMember. Затем вы можете добавить метод расширения, чтобы получить и установить общий тип в члене данных объекта. Вы могли бы также сделать это внутренним, таким образом, вы должны были бы использовать методы расширения для получения и установки значения.

Конечно, он работает только в том случае, если вы создаете клиента, используя svcutil (или Visual Studio), и ссылаетесь на сборку, содержащую контракт с данными, и класс с методами расширений.

Надеюсь, что это поможет ...

Смежные вопросы