WCF, тип возврата интерфейса и KnownTypes - PullRequest
18 голосов
/ 24 мая 2011

Я создаю службу WCF, и у меня много проблем с некоторыми проблемами сериализации. Возможно, есть только 1 способ сделать это, но я хотел бы подтвердить это Вот мой пример кода:

Контракты

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 Ответ

36 голосов
/ 24 мая 2011

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

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

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

        [OperationContract]
        ICollection<IAtm> GetAtms();

    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...