WCF передает пользовательский объект клиенту и запускает его методы

#c# #wcf

#c# #wcf

Вопрос:

Это такой же дизайн, как и технический вопрос. Я не уверен, что делаю это правильно…

У меня есть WCF API, который взаимодействует с базой данных и передает обратно объект Person (который определен в отдельной .dll), у которого есть как методы, так и атрибуты. Объект отправляется из WCF вызывающему клиенту.

Я хочу вызвать методы пользователя на клиенте. Я понимаю, что они не могут быть отправлены по потоку из API. Однако, если я ссылаюсь на то же самое.dll, которую использует WCF, должен ли я иметь возможность привести API Person к a .Пользователь dll затем запускает методы?

Надеюсь, понятно, чего я пытаюсь достичь.

Ответ №1:

WCF работает через контракты данных. Это модели данных, которые нужно возвращать, например Person , объект со своими свойствами. Не беспокойтесь о методах во время транспортировки объекта из службы в клиент. Если используется контракт с данными, и вы будете ссылаться на WCF, прокси-класс сгенерирует объект Person .

Если ваша логика более сложная, я полагаю, это зависит от вашей ситуации. Позвольте мне описать в нескольких словах:

  1. Если вы не можете изменить источник класса и хотите вызвать открытый метод, лучше использовать отражение. Итак, вы получаете объект из WCF, устанавливаете свойства Person объекта с возвращенными значениями, а затем вызываете метод.

  2. Если вы можете изменить источники класса, вы можете создать базовый интерфейс IPerson , реализовать этот интерфейс со свойствами объекта Person в классе и вернуть IPerson объект. В этом случае вы сможете выполнить приведение.

Подробнее: Хорошо, позвольте мне предоставить вам более подробную информацию:

  1. В качестве наилучшей практики я рекомендую создавать отдельные классы с интерфейсами. Это должен быть интерфейс контракта данных, который будет описывать ваш объект. Что-то вроде этого:

     [DataContract] 
    public interface IPerson
    {
       [DataMember]
       public int Identifier { get; set; }
    
       [DataMember]
       public string First { get; set; }
    
       [DataMember]
       public string Last { get; set; }
    
       public string GetSomething();
    }
      
  2. Метод в WCF, который вы реализуете, должен возвращать тип IPerson.

  3. В общем классе, пожалуйста, реализуйте интерфейс IPerson для вашего Person объекта.
  4. Ссылайтесь на эту сборку в своих проектах Service и Client.
  5. Добавьте веб-ссылку на службу WCF в свой клиентский проект.
  6. Ваш метод вернет объект типа IPerson , поэтому вы можете использовать свой объект Person из общей библиотеки и использовать все его методы.

Комментарии:

1. Спасибо за быстрый ответ, внешняя dll является моей собственной, поэтому я могу изменить исходный код, не могли бы вы подробнее рассказать о варианте 2. Мне нравится концепция, но я не до конца понимаю.

2. Итак, у вас есть dll, содержащая интерфейсы контракта данных, а также разделяемая dll, содержащая реализацию этих интерфейсов? И я должен ссылаться как на DLL-файлы из проекта службы WCF, так и из проекта клиента? Тогда какой смысл в реализации отдельной библиотеки dll интерфейсов?

3. Я получаю жалобу на то, что «[DataContract]» недопустимо для интерфейса

Ответ №2:

WCF поддерживает возможность повторного использования ссылок, которые уже включены в проект. В этом смысле вы можете создать сборку контрактов (сборку, содержащую ваши тонкие модели домена (например Person , etc), к которым вы можете добавить свою собственную логику.

Затем вы можете добавить сборку как в свою службу WCF, так и в вызывающие клиентские проекты, и дать указание WCF повторно использовать любые существующие ссылки. Таким образом, то, что извлекается из вашей службы, десериализуется в локальную копию a Person , но не a Person , которая была бы сгенерирована как прокси, вы фактически получаете полный экземпляр, на котором вы можете выполнять вызовы методов.

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

Комментарии:

1. Есть ли лучший способ сделать это? возможно, создать объект Person как на сервере, так и на клиенте? Я думал, что таким образом мне нужно будет создать только один объект Person плюс несколько других, которые могут быть разделены между сервисом и клиентом. Я ищу наиболее элегантное решение, это личный проект, над которым я работаю.

2. Я думаю, вы упускаете суть. Вы реализуете только Person один раз. В общей сборке (сборке контрактов). Затем вы ссылаетесь на это в службе и на клиенте.

3. Нет, я понимаю, и по состоянию на 15 минут назад у меня есть рабочее решение. Спасибо! Однако, это лучший способ сделать это в общей сборке? Я новичок в WCF. Предвидите ли вы какие-либо проблемы с этим?

4. Ну, это действительно единственный способ, которым вы можете это сделать. [DataContract] не поддерживает вызовы методов, поэтому в этом смысле совместное использование сборки между несколькими проектами — неплохая идея.

Ответ №3:

Поскольку вы ссылаетесь на одну и ту же dll, а WCF может быть строго типизированным, вы должны иметь возможность вызывать методы для объекта ответа Person без приведения. При определении класса Person убедитесь, что вы используете атрибут DataContract.

В следующем примере класс Person будет сериализован WCF с тремя элементами данных на стороне сервера. WCF на стороне клиента десериализует ответ … создавая класс Person. Итак, на стороне клиента вы можете вызвать FullName(), и он будет работать без приведения.

  [DataContract]
 public class Person
{
   [DataMember]
   public int Identifier { get; set; }
   [DataMember]
   public string First { get; set; }
   [DataMember]
   public string Last { get; set; }
   public string FullName()
   {
      return First   " "   Last;
   }  
}
  

Комментарии:

1. Вот как выглядит мой объект, я могу просматривать int, first и last на стороне клиента, но не могу видеть метод… pService. Person p = API. GetPerson(123);

2. Является ли область действия метода общедоступной?