Сериализация между клиентом и сервером с разными ссылочными версиями - PullRequest
2 голосов
/ 09 сентября 2011

У меня есть служба Windows, которая ссылается на сборку, которая содержит следующий класс.

 [Serializable]
 public class User
    {
        public User(string userName)
        {
            UserName = userName;
        }

        public string UserName { get; private set; }
    }

У этой службы есть метод, позволяющий нам создать пользователя:

public User CreateUser(User user)
        {
        //Create and return user
    }

Благодаря удаленному взаимодействию мы можем вызвать этот метод в службе, которая получает объект пользователя от нашегоприложение.Приложение ссылается на ту же сборку, что и служба для класса User, но вызывает определенную версию 1.0.0.0.

CreateUser(User user);

Мы хотели бы изменить существующую сборку, на которую ссылается каждый проект, чтобы добавитьНовое свойство «Телефон» для класса User.

 [Serializable]
 public class User
    {
        public User(string userName)
        {
            UserName = userName;
        }

        public string UserName { get; private set; }
        **public string Phone { get; set; }**
    }

Мы будем увеличивать версию сборки с 1.0.0.0 до 2.0.0.0.Служба Windows будет иметь ссылку на версию сборки 2.0.0.0 в GAC.Поскольку некоторые из наших клиентов медленно обновляются и принудительно устанавливают определенные версии сборки или копируют ее локально, они все равно будут ссылаться на версию 1.0.0.0.

При таком изменении ссылки на сборку службы маршаллер, который десериализует / сериализует объект из службы в приложение, выдает ошибку сериализации.«Средство форматирования выдало исключение при попытке десериализации сообщения: при попытке десериализации параметра произошла ошибка ...»

Внесенное нами изменение должно быть неразрывным, поскольку мы просто добавили дополнительную функцию.Есть ли способ разрешить существующему приложению продолжить работу и использовать версию сборки 1.0.0.0 и сериализовать 2.0.0.0 без нового свойства до них без некоторого запутанного преобразования в службе?

ОБНОВЛЕНИЕ:

Мы используем следующее для подключения к нашему сервису

marshaller = ChannelFactory<T>.CreateChannel(new NetTcpBinding() { MaxReceivedMessageSize = MaxResponseSize }, new EndpointAddress(new Uri(new Uri(servers[serverIndex]), serviceName)));

Внутреннее исключение: http://tempuri.org/:CreateUserResult. Сообщение InnerException было '' EndElement '' CreateUserResult 'из пространства имен' http://tempuri.org/' не ожидается.Ожидается элемент '_someOtherField'. '.Пожалуйста, смотрите InnerException для более подробной информации ... Next inner is null

Ответы [ 2 ]

2 голосов
/ 09 сентября 2011

Как я и подозревал, вот в чем проблема;

NetTcpBinding

(из ваших правок).В основном, WCF включает в себя приятную дружественную поддержку на основе контракта и некоторую не совсем дружественную поддержку на основе типов.

Если вообще возможно, я бы предложилсамый простой вариант здесь - не использовать NetTcp , так как по умолчанию используется NetDataContractSerializer (на основе типа), поэтому будет иметь проблемы с версиями.В качестве альтернативы вы можете использовать другие сериализаторы на транспорте - например, DataContractSerializer из protobuf-net.Однако изменение этого само по себе было бы критическим изменением.

Я понимаю, что можно использовать пользовательское связующее с NetDataContractSerializer - см. Проблема десериализации с NetDataContractSerializer после рефакторинга кода .Если вы можете заставить это работать, это должно сохранить API, но это не следует недооценивать;Я думаю, что это будет бремя обслуживания, если честно.Я бы лучше сократил свои потери, сломал бы API один раз и переключился бы на контрактный сериализатор.

0 голосов
/ 09 сентября 2011

Может быть, атрибут OptionalField вам подходит, в зависимости от форматера, см. http://msdn.microsoft.com/en-us/library/system.runtime.serialization.optionalfieldattribute.aspx.

...