Подтвердить что ты не робот

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, я должен упустить что-то, что сериализатор не может обработать. но я не знаю, что.

4b9b3361

Ответ 1

Хорошо, мне удалось это исправить Проблема, как я вижу, была в этом

Так как я возвращаю интерфейс, а не конкретный класс, WCF не знает, чего ожидать на другом конце. Таким образом, это может быть что угодно. Когда он получает список, он смутился.
Правильный способ сделать это - добавить атрибуты KnownType там, где это необходимо.
Кто должен знать эти типы? реализация сервиса, чтобы сериализовать и десериализовать их правильно. Однако клиент разговаривает с интерфейсом службы, а не с самой реализацией. Вот почему добавление атрибутаKnownType в реализацию службы не сработало
Проблема здесь в том, что интерфейсы не позволяют атрибуты KnownType, но они позволяют атрибуты ServiceKnownType. Решение проблемы состояло в том, чтобы добавить ожидаемый тип в контракт интерфейса службы, и voila, все работает нормально и использует интерфейсы

    [ServiceContract]
    [ServiceKnownType(typeof(Atm))]
    [ServiceKnownType(typeof(List<Atm>))]
    public interface IAtmFinderService
    {

        [OperationContract]
        ICollection<IAtm> GetAtms();

    }