wcf выставляя дженерики - PullRequest
       8

wcf выставляя дженерики

5 голосов
/ 31 августа 2009

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

что-то вроде T GetObject (int id)

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

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

Ответы [ 4 ]

8 голосов
/ 31 августа 2009

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

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

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

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

Марк

2 голосов
/ 01 сентября 2009

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

  • 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 голосов
/ 24 марта 2015

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

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

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

0 голосов
/ 06 декабря 2011

ЭТО МОЖЕТ СДЕЛАТЬ, если вы используете 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] (если их можно обнаружить на сервере и на стороне клиента), можно сериализовать.

Надеюсь, это помогло!

...