在 C# 中,如何在运行时设置、重置或定义 JsonProperty 属性?

In C#, how can I set, reset, or define a JsonProperty attribute at runtime?

我们有一个用 C# 开发的微服务,需要与 Salesforce 集成。

我们正在实施一个新的 Saleforce 实例,出于某些愚蠢的原因,有人决定将一个字段从 My_Field__c 重命名为 MyField__c,他们不希望任何自定义字段包含任何可避免的下划线。愚蠢,但不是我的选择。

现在我需要将微服务的新实例集成到 Salesforce 的新实例中,使解决方案只有一个字符不同,但当然我们需要能够同时维护原始微服务和新微服务.

在理想情况下,我会在 appSettings 中设置一些值并在我的 [JsonProperty(PropertyName = "My_Field__c")] 声明中使用它,但是当然该属性需要一个编译时间常量,所以我们不能这样做简单。

创建一个自定义 serializer/deserializer 或维护一个不同的 git 分支来删除这个角色感觉有点过分了。

有什么方法可以动态设置这个属性吗?

(有人建议 TypeDescriptor 可能提供解决方案,但我找不到有关如何应用此解决方案的详细信息。)

为新旧 属性 名称和一个帮助程序 属性 添加两个单独的属性,其中 returns 已被反序列化:

public class MyModel
{
   [JsonProperty(PropertyName = "My_Field__c")]
   public string MyFieldOld { get; set; }

   [JsonProperty(PropertyName = "MyField__c")]
   public string MyFieldNew { get; set; }

   [JsonIgnore]
   public string MyField => MyFieldOld ?? MyFieldNew;

}

我试图让 TypeDescriptor.AddAttributes() 使用 Type,但这没有用。由于实例在反序列化之前不存在,因此尝试将其与实例一起使用是行不通的。

但是,我想出了如何使用合同解析器来完成这项工作:


public static MyModel FromSerializedMyModel(string content, SalesforceFieldNames salesforceFieldNames) =>
   JsonConvert.DeserializeObject<MyModel>(contents, 
       CreateSettings(salesforceFieldNames));

private static JsonSerializerSettings CreateSettings(SalesforceFieldNames salesforceFieldNames) => new()
        {
            ContractResolver = new MyModelContractResolver(salesforceFieldNames)
        };



class MyModelContractResolver: DefaultContractResolver
    {
        private readonly SalesforceFieldNames _salesforceFieldNames;

        public MyModelContractResolver(SalesforceFieldNames salesforceFieldNames) =>
            _salesforceFieldNames = salesforceFieldNames;

        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
            Dictionary<string, JsonProperty> propertiesByUnderlyingName = properties.ToDictionary(x => x.UnderlyingName, x => x);
            if (propertiesByUnderlyingName.TryGetValue("MyField", out JsonProperty spvTagProperty))
            {
                spvTagProperty.PropertyName = _salesforceFieldNames.MyField;
            }
            return properties;
        }
    }

有点冗长而且难看,但它有效...