我有一个引用包含以下类的程序集的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对象的服务中调用此方法。该应用程序引用该服务为User类执行的相同程序集,但它强制使用特定的1.0.0.0版本。
CreateUser(User user);
我们希望更改从每个项目引用的现有程序集,以向User类添加新属性“Phone”。
[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服务将引用GAC中2.0.0.0版本的程序集。由于我们的某些客户端升级速度很慢,并且强制部署的特定版本或将其复制到本地,因此它们仍将引用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''来自命名空间'http://tempuri.org/'的'CreateUserResult'不是预期的。期待元素'_someOtherField'。'。有关更多详细信息,请参阅InnerException ......下一个内部是空的
答案 0 :(得分:2)
我怀疑,这是问题所在;
NetTcpBinding
(来自你的编辑)。基本上,WCF包括一些友好的契约支持,以及一些不太友好的基于类型的支持。
如果可能,我建议最简单的选择是不使用NetTcp ,因为它默认使用NetDataContractSerializer(基于类型),所以将有版本问题。或者,您可以在传输上使用oter序列化程序 - 例如protobuf-net的DataContractSerializer。但是,改变这种情况本身就是一个突破性的变化。
我认为可以在NetDataContractSerializer中使用自定义活页夹 - 请参阅Problem deserializing with NetDataContractSerializer after refactoring code。如果你可以使用它,它应该保留API,但不应低估;我认为这将是一种维护负担,说实话。我宁愿减少损失,打破API 一次并切换到基于合同的序列化程序。
答案 1 :(得分:0)
也许OptionalField属性适合您,具体取决于格式化程序,请参阅http://msdn.microsoft.com/en-us/library/system.runtime.serialization.optionalfieldattribute.aspx。