Я работаю над службой WCF и пытаюсь очистить код. Проблема, с которой я сталкиваюсь, заключается в том, что у меня есть базовый тип данных, который я хочу отправить в качестве результатов от службы клиенту; однако в самом служебном коде в основном используются классы, производные от базы, с дополнительными свойствами для обработки. У клиента вообще нет причин знать об этом.
Прямо сейчас я могу заставить это работать, но только если я определю производные классы в общей библиотеке. Я не хочу, чтобы они там были, поскольку они предназначены исключительно для службы.
Ниже приведен пример, показывающий проблему. Все три файла находятся в разных проектах в одном решении.
Common.IPersonService.cs
using System.ServiceModel;
using System.Runtime.Serialization;
namespace Common
{
[ServiceContract]
public interface IPersonService
{
[OperationContract(Name = "GetPersonById")]
Person GetPersonById(int id);
}
[DataContract(Name = "Person")]
public class Person
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
}
}
WcfClient.Program.cs
using System;
using System.ServiceModel;
using Common;
namespace WcfClient
{
class Program
{
static void Main(string[] args)
{
var binding = new NetTcpBinding();
var endpoint = new EndpointAddress("net.tcp://localhost:8001/WcfTest/");
var factory = new ChannelFactory<IPersonService>(binding, endpoint);
IPersonService service = null;
try
{
service = factory.CreateChannel();
Person result = service.GetPersonById(5);
Console.WriteLine(result.Name);
((ICommunicationObject)service).Close();
Console.ReadLine();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}
}
WcfService.Program.cs
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using Common;
namespace WcfService
{
[DataContract(Name = "Person")]
public class Contact : Person
{
public string Address { get; set; }
}
class Program
{
static void Main(string[] args)
{
using (ServiceHost serviceHost = new ServiceHost(typeof(PersonService)))
{
serviceHost.Open();
Console.WriteLine("Service started");
Console.ReadLine();
}
}
}
public class PersonService : IPersonService
{
private Dictionary<int, Contact> _testData = new Dictionary<int, Contact>();
public PersonService()
{
Random rnd = new Random();
for (int i = 0; i < 100; i++)
{
_testData.Add(i + 1, new Contact()
{
Id = i + 1,
Name = Guid.NewGuid().ToString(),
Address = Guid.NewGuid().ToString()
});
}
}
public static void Configure(ServiceConfiguration config)
{
config.AddServiceEndpoint(typeof(IPersonService), new NetTcpBinding(), "net.tcp://localhost:8001/WcfTest/");
config.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
}
public Person GetPersonById(int id)
{
return _testData[id];
}
public Person GetValueByKey(string key)
{
return null;
}
}
}
Получено следующее исключение:
The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:59.9780000'.
Теперь, если я перенесу класс Contact из проекта WcfService и помещу его в общий проект, он заработает. Как уже было сказано, я бы предпочел не засорять общую библиотеку элементами, специфичными для реализации службы.
Спасибо!
@KBO Непонятная часть состоит в том, что класс «Контакт» в моей реальной программе содержит только данные и функции, которые необходимы самому процессу сервера, и не должны передаваться через службу клиенту. Так что добавление класса, о котором клиент никогда не должен знать, в разделяемую библиотеку - непонятно. Класс «Контакт» просто естественным образом расширился на базовый класс, поэтому его было целесообразно наследовать. На данный момент я избавился от наследования и просто сделал Person членом Contact, чтобы его можно было отправлять самостоятельно.
Включите ведение журнала сообщений wcf docs.microsoft.com/en-us/dotnet/framework/wcf/diagnostics/…. Без сомнения, будет больше подробностей об исключении.
Вам необходимо иметь класс
Contact
в разделяемой библиотеке, потому что и сервер, и клиент должны знать, как сериализовать и десериализовать переданные данные. Общая библиотека содержит КОНТРАКТЫ между сервером и клиентом, операции И контракты данных. Это не «мутно».