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的值之前。

我的问题是:

  1. 如何将Foo移至命名空间com.libB?两阶段升级对您有帮助吗?
  2. 是否有可能做到这一点而又不会造成数据丢失/损坏?

解决方法

您可以将DataContract属性和名称空间添加到您的类型中。 由于您已经在生产环境中运行,因此可以使用错误中的名称空间来解决问题。

示例:

[DataContract(Name = "Foo",Namespace = "http://schemas.datacontract.org/2004/07/com.libA")]
public enum Foo
{
   // ...
}

更好的方法可能是制定升级计划。

  1. 让这两种类型共存
  2. 检索状态时,请尝试使用机制,并使用旧类型进行检索,如果由于序列化异常而失败,请尝试使用新类型。
  3. 在保留状态时,将状态转换为旧类型时,将其转换为新名称空间中的新类型。 (添加一些日志记录,以便您可以验证转换是否发生)
  4. 部署进行测试,看看是否可行,是否可以部署到生产环境
  5. 删除旧类型,删除转换代码
  6. 如果可以正常部署到生产环境,请进行测试以进行测试。
,

一种选择是为使用DataContractSerializer的所有类型创建custom serializer wrapping Foo,在反序列化期间修复/忽略名称空间。

IReliableStateManager.TryAddStateSerializer用于注册一个 给定类型T的自定义序列化程序。此注册应 发生在StatefulServiceBase的构建中,以确保 在恢复开始之前,所有可靠集合都可以访问 相关的序列化程序以读取其持久数据。

  • IStateSerializer<OrderKey>.Read(BinaryReader reader)中,以XML格式读取序列化的数据
  • 在需要的地方更改XML名称空间
  • 将XML馈送到DataContractSerializer以创建对象
  • 返回对象

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...