WCF, тип возврата интерфейса и известные типы
Я создаю службу WCF, и у меня возникают проблемы с некоторыми проблемами сериализации. Возможно, есть только один способ сделать это, но я хотел бы подтвердить это
Здесь мой пример кода:
контракты
public interface IAtm
{
[DataMember]
double Latitude { get; set; }
[DataMember]
double Longitude { get; set; }
}
[ServiceContract]
public interface IAtmFinderService
{
[OperationContract]
ICollection<IAtm> GetAtms();
}
Реализация службы:
[KnownType(typeof(Atm))]
[KnownType(typeof(List<Atm>))]
[ServiceKnownType(typeof(Atm))]
[ServiceKnownType(typeof(List<Atm>))]
public class AtmFinderService : IAtmFinderService
{
public ICollection<IAtm> GetAtms()
{
return new List<IAtm>()
{
new Atm() { Latitude = 1, Longitude = 1 },
new Atm() { Latitude = 2, Longitude = 2 }
};
}
}
Я добавил все атрибуты KnownType и ServiceKnownType, потому что думал, что там что-то отсутствует.
Итак, теперь я делаю несколько тестов. Я попытался создать консольное приложение, используя метод "добавить ссылку на службу", чтобы заставить VS автоматически создавать прокси-сервер. Таким образом, я получаю функцию типа
object[] GetAtms();
При попытке вызвать его, я получаю эту ошибку:
Сообщение InnerException было "Тип" WCFTest.Atm" с именем контракта с данными 'Банкоматы: HTTP://schemas.datacontract.org/2004/07/WCFTest' не ожидается. Рассмотрите возможность использования DataContractResolver или добавить любые типы неизвестно статически в списке известных типов - например, используя атрибут KnownTypeAttribute или добавив их в список известных типов передан в DataContractSerializer. '.
Очень приятно... Итак, я думаю, что VS-автогенерированный код - это дерьмо. Я сделал следующее изменение в моей службе (и всех связанных классах и реализациях):
[OperationContract]
ICollection<Atm> GetAtms();
Итак, теперь я возвращаю конкретный тип. После обновления справки службы он создает копию класса Atm с его членами и т.д.
После вызова службы вызов будет успешным.
Я думал, что это было плохое поведение, связанное с автогенерированным кодом, поэтому я попытался создать очень простое хост-клиентское приложение. Я запустил консольный хост, прослушивающий какой-то порт, а затем создал клиент, который использует класс ClientBase для вызова службы. Такое же поведение... если служба реализована, возвращая тип интерфейса, она терпит неудачу. Если я изменю его, чтобы вернуть конкретный тип, он работает. Я думаю, что у меня есть некоторые проблемы с атрибутами KnownType, я должен упустить что-то, что сериализатор не может обработать. но я не знаю, что.
Ответы
Ответ 1
Хорошо, мне удалось это исправить
Проблема, как я вижу, была в этом
Так как я возвращаю интерфейс, а не конкретный класс, WCF не знает, чего ожидать на другом конце. Таким образом, это может быть что угодно. Когда он получает список, он смутился.
Правильный способ сделать это - добавить атрибуты KnownType там, где это необходимо.
Кто должен знать эти типы? реализация сервиса, чтобы сериализовать и десериализовать их правильно. Однако клиент разговаривает с интерфейсом службы, а не с самой реализацией. Вот почему добавление атрибутаKnownType в реализацию службы не сработало
Проблема здесь в том, что интерфейсы не позволяют атрибуты KnownType, но они позволяют атрибуты ServiceKnownType. Решение проблемы состояло в том, чтобы добавить ожидаемый тип в контракт интерфейса службы, и voila, все работает нормально и использует интерфейсы
[ServiceContract]
[ServiceKnownType(typeof(Atm))]
[ServiceKnownType(typeof(List<Atm>))]
public interface IAtmFinderService
{
[OperationContract]
ICollection<IAtm> GetAtms();
}