WCF - несколько сервисных контрактов, использующих одинаковые контракты данных
У меня новый вопрос к гуру WCF.
Итак, у меня есть класс User
который близок к представлению "Пользователь" из БД, которое я использую для операций с базой данных. Теперь я хотел бы иметь 2 разных сервисных контракта, которые используют этот класс как контракт данных, но каждый по-своему... Я имею в виду,
public class DBLayer
{
void InsertUsers(List<User> userList)
{
// both 'PropertyVisibleForService1' and 'PropertyVisibleForService2'
// are used HERE to be inserted into their columns
}
}
[DataContract]
public class User
{
[DataMember] public string PropertyVisibleOnlyForService1{...}
[DataMember] public string PropertyVisibleOnlyForService2{...}
}
[ServiceContract]
public interface IService1
{
List<User> GetUsers(); // user with 'PropertyVisibleOnlyForService1' inside
}
[ServiceContract]
public interface IService2
{
List<User> GetUsers(); // user with 'PropertyVisibleOnlyForService2' inside
}
Таким образом, идея заключается в том, что каждый сервис получит своего рода пользователя, подмножество 'User'
, Имея в виду, что я хочу использовать 'User'
как и для операций с БД, что бы я мог достичь? Мне действительно нужно создавать разные контракты на данные или есть другой, более разумный способ?
Лучше всего было бы не только дать мне решение, но и объяснить некоторые передовые методы и альтернативы.
Заранее спасибо.
EDIT1: я добавил фиктивный класс DBLayer здесь для лучшего обзора и почему я думаю, что наследование может быть не очень хорошим в этом случае.
Решение будет иметь другойUserForService1
' а также 'UserForService2
"как контракты данных, которые будут отображаться в конце из / в"User
"Но я хотел, чтобы некоторые другие точки зрения.
РЕДАКТИРОВАТЬ 2: Очень хорошая статья, которая помогла мне в этом случае: http://bloggingabout.net/blogs/vagif/archive/2009/03/29/iextensibledataobject-is-not-only-for-backward-compatibility.aspx
4 ответа
Вы можете создать отдельные DTO для каждого сервиса, но ваш случай будет идеальным для шаблона Decorator:
[DataContract]
public class UserForService1 : User
{
private User mUser;
public UserForService1(User u)
{
mUser = u;
}
//expose only properties you'd like the user of this data contract to see
[DataMember]
public string SomeProperty
{
get
{
//always call into the 'wrapped' object
return mUser.SomeProperty;
}
set
{
mUser.SomeProperty = value;
}
}
// etc...
}
и для Service2 аналогичный код, который показывает только то, что вы заботитесь там...
Как предлагается в комментарии, у вас может быть два класса, производных от базового пользователя, а затем, используя известные типы контрактов данных, вы можете достичь желаемой цели. Смотрите следующие ссылки для большего количества примеров.
http://www.freddes.se/2010/05/19/wcf-knowntype-attribute-example/
Если они предназначены для представления разных типов пользователей, они должны быть разных классов. Я согласен с phoog в комментариях, вы должны получить требуемый тип из общего класса User и добавить определенные свойства сервиса в производные классы.
Почему вы не думаете, что наследование будет хорошо в этом случае? Если вы дадите нам более подробную информацию, мы могли бы попытаться пересмотреть предложения в соответствии с вашей актуальной проблемой.
Если вы не хотите использовать наследование, что-то вроде:
[DataContract]
public class User
{
}
[DataContract]
public class Service1User : User
{
[DataMember] public string PropertyVisibleOnlyForService1{...}
}
[DataContract]
public class Service2User : User
{
[DataMember] public string PropertyVisibleOnlyForService2{...}
}
[ServiceContract]
public interface IService1
{
List<Service1User> GetUsers(); // user with 'PropertyVisibleOnlyForService1' inside
}
[ServiceContract]
public interface IService2
{
List<Service2User> GetUsers(); // user with 'PropertyVisibleOnlyForService2' inside
}
Тогда я не уверен, что ты будешь делать. Ваша сортировка нарушает принципы объявления типов в этот момент. Думайте об этом обычным способом.NET; если вы определяете "Пользователь" в своем приложении, то он везде одинаковый. Некоторые свойства не могут быть скрыты от некоторых других классов или методов.
WCF также собирается упаковать эту информацию о типе в сгенерированный WSDL, и он собирается определить тип User только один раз, поэтому ему нужно знать, какие свойства там есть.
Теперь, если все, что вас волнует, - это собственно созданное сообщение SOAP, и вас не волнует WSDL или то, что увидят все клиенты, сгенерированные из WSDL, то технически вы можете сделать так, чтобы оно не передавало это свойство в сообщение SOAP. когда это нуль, делая:
[DataMember(EmitDefaultValue=false)]
Затем, когда это свойство равно нулю, оно не будет включено в сериализацию. Это не имело бы никакого значения, если бы клиент был сгенерирован из WSDL, так как его тип User по-прежнему должен содержать оба свойства. Было бы просто изменить сериализацию, чтобы вместо отправки клиенту что-то вроде:
<User>
<PropertyVisibleOnlyForService1 nil="true" />
<PropertyVisibleOnlyForService2>something</PropertyVisibleOnlyForService2>
</User>
вместо этого он отправит:
<User>
<PropertyVisibleOnlyForService2>something</PropertyVisibleOnlyForService2>
</User>