如何解决Service Fabric:将枚举类移至其他项目
最近,为了解决循环依赖问题,我们需要将枚举类移到其他名称空间下的其他项目中。有一些参与者和有状态的服务将这个枚举值的实例保持在可靠状态。
枚举类是这样的:
namespace com.libA
{
public enum Foo
{
None = 0,Foo1 = 1,Foo2 = 2,}
}
我们希望将其移动到名称空间为com.libB
的另一个项目中。这些枚举值存储在参与者和有状态服务内部的可靠状态中,并按以下方式获取:
Foo foo = await this.StateManager.GetStateAsync<Foo>("FooKey").ConfigureAwait(false);
存储Foo
值的actor服务之一是寿命很长的actor。从理论上讲,它可以在快乐的路径中生存到无穷远,并且如果从不从外部调用delete,则它永不停止。我们尝试了简单的重构>移动,并在非产品环境中进行了尝试。这开始在我们的非产品环境中引起SerializationException
。错误消息显示:
Expecting element 'Foo' from namespace 'http://schemas.datacontract.org/2004/07/com.libB'.. Encountered 'Element' with name 'Foo',namespace 'http://schemas.datacontract.org/2004/07/com.libA'.
这些异常即将出现在较早的参与者中获取Foo
的值之前。
我的问题是:
- 如何将
Foo
移至命名空间com.libB
?两阶段升级对您有帮助吗? - 是否有可能做到这一点而又不会造成数据丢失/损坏?
解决方法
您可以将DataContract
属性和名称空间添加到您的类型中。
由于您已经在生产环境中运行,因此可以使用错误中的名称空间来解决问题。
示例:
[DataContract(Name = "Foo",Namespace = "http://schemas.datacontract.org/2004/07/com.libA")]
public enum Foo
{
// ...
}
更好的方法可能是制定升级计划。
- 让这两种类型共存
- 检索状态时,请尝试使用机制,并使用旧类型进行检索,如果由于序列化异常而失败,请尝试使用新类型。
- 在保留状态时,将状态转换为旧类型时,将其转换为新名称空间中的新类型。 (添加一些日志记录,以便您可以验证转换是否发生)
- 部署进行测试,看看是否可行,是否可以部署到生产环境
- 删除旧类型,删除转换代码
- 如果可以正常部署到生产环境,请进行测试以进行测试。
一种选择是为使用DataContractSerializer
的所有类型创建custom serializer wrapping Foo
,在反序列化期间修复/忽略名称空间。
IReliableStateManager.TryAddStateSerializer用于注册一个 给定类型T的自定义序列化程序。此注册应 发生在StatefulServiceBase的构建中,以确保 在恢复开始之前,所有可靠集合都可以访问 相关的序列化程序以读取其持久数据。
- 在
IStateSerializer<OrderKey>.Read(BinaryReader reader)
中,以XML格式读取序列化的数据 - 在需要的地方更改XML名称空间
- 将XML馈送到
DataContractSerializer
以创建对象 - 返回对象
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。