Я гуглил и читал часами, и я не могу найти никого, кто занимается моим конкретным сценарием...
Я хочу использовать интерфейсы в своих сервисных контрактах WCF, чтобы слабо связать сервис с классами, используемыми на каждом конце провода. Это позволит нам иметь низкоуровневую сборку, содержащую только контракты службы и данных (только интерфейсы), которую мы можем передать консультанту. На своем конце провода они могут создавать экземпляры своих классов данных, которые реализуют наш интерфейс контракта данных, отправлять его нам по сети, а наша служба WCF будет затем переводить/преобразовывать/любые входящие данные в наш версия класса данных, которая реализует тот же интерфейс.
Вот пример. IDataContract
содержит голую информацию, которую я хочу передать по сети. Конечные точки и другая конфигурация, специфичная для WCF, — это все по умолчанию (мои проблемы могут заключаться в этом, поэтому я могу включить больше, если мне нужно что-то изменить).
РЕДАКТИРОВАНИЕ: я добавил больше кода и переименовал пару классов, чтобы было меньше путаницы. Дополнения Name & Namespace к DataContractAttributes, а также два раздела в файлах конфигурации являются новыми дополнениями, основанными на информации из этот пост в блоге. Если я переключусь на абстрактный базовый класс вместо интерфейса, это сработает. Однако я бы хотел, чтобы это работало с интерфейсом, если это возможно.
Общая библиотека (мой код, общий с авторами клиента):
public interface IDataContract
{
string MyProperty { get; set; }
}
[ServiceContract]
public interface ITestService
{
[OperationContract]
IDataContract TestSharedInterface(IDataContract clientData);
}
Код клиента (их):
[DataContract(Name = "IDataContract", Namespace = "http://services.sliderhouserules.com")]
public class ClientDataClass : IDataContract
{
[DataMember]
public string MyProperty { get; set; }
}
private static void CallTestSharedInterface()
{
EndpointAddress address = new EndpointAddress("http://localhost/ServiceContractsTest.WcfService/TestService.svc");
ChannelFactory<ITestService> factory = new ChannelFactory<ITestService>("ITestService", address);
ITestService proxy = factory.CreateChannel();
((IClientChannel)proxy).Open();
IDataContract clientData = new ClientDataClass() { MyProperty = "client data" };
IDataContract serverData = proxy.TestSharedInterface(clientData);
MessageBox.Show(serverData.MyProperty);
}
Конфигурация клиента:
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="ServiceContractsTest.Contracts.DataContracts.IDataContract, ServiceContractsTest.Contracts">
<knownType type="ServiceContractsTest.WcfClient.ClientDataClass, ServiceContractsTest.WcfClient"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
Код сервера (мой):
public class TestService : ITestService
{
public IDataContract TestSharedInterface(IDataContract clientData)
{
ServerDataClass convertedClientData = (ServerDataClass)clientData;
IDataContract serverData = new ServerDataClass() { MyProperty = convertedClientData.MyProperty + " + server data added" };
return serverData;
}
}
[DataContract(Name = "IDataContract", Namespace = "http://services.sliderhouserules.com")]
public class ServerDataClass : IDataContract
{
[DataMember]
public string MyProperty { get; set; }
}
Конфигурация сервера:
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="ServiceContractsTest.Contracts.DataContracts.IDataContract, ServiceContractsTest.Contracts">
<knownType type="ServiceContractsTest.WcfService.ServerDataClass, ServiceContractsTest.WcfService"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
Я получаю сообщение об ошибке сериализации при вызове клиента, жалующемся на известные типы. Мне просто не хватает разметки метаданных в этом клиентском классе? Я в недоумении, откуда вообще знать, что проблема лежит, поскольку я перепробовал все поиски, которые только мог придумать, и, похоже, никто не имел дело с этим конкретным сценарием.
По сути, я хочу, чтобы ClientDataClass
сериализовался в <IDataContract><MyProperty>client data</MyProperty></IDataContract>
, а затем имел возможность десериализовать его в экземпляр ServerDataClass
. Кажется, это должно быть возможно.