在 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;
}
}
有点冗长而且难看,但它有效...
我们有一个用 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;
}
}
有点冗长而且难看,但它有效...