使用Newtonsoft.Json序列化C#对象,分别使用两个不同的JsonConverter。

huangapple go评论67阅读模式
英文:

Serialize C# object with two different JsonConverter using Newtonsoft.Json

问题

Sure, here's the translated content:

我的使用情况需要我为多个客户端序列化/反序列化C#对象,基本上是内部客户端和外部客户端。

我的内部客户端简单地使用对象属性作为JSON数据的命名方案。我的外部客户端具有完全相同的属性,但希望某些属性具有不同的名称。在这种情况下,我的客户端希望将下面的Customer字段重命名为Mandant。但对我来说,仍然必须能够将其序列化为Customer作为字段名。只有在某些情况下,我需要能够为我的外部客户端序列化。我目前正在使用Newtonsoft.Json

我的C#类可能如下所示:

public class MyClass
{
    public string Customer { get; set; }
}

我的期望是,我可以以两种不同的方式进行序列化/反序列化,例如,我的外部客户端希望将字段Customer重命名为Mandant

为内部客户端进行序列化:

{
   "Customer": "MyCustomer"
}

为外部客户端进行序列化:

{
   "Mandant": "MyCustomer"
}
英文:

My use case requires me to serialize/ deserialize c# object for multiple clients, basically an internal client and external client.
My internal client simply uses the objects properties as a naming scheme for the json data. My external client has the exact same properties, but wants to have a different name for some of the properties. In this szenario my client wants the below Customer field to be renamed to Mandant. However it is crucial for me to be still able to serialize to Customer as a field name. Only in certain scenarios I need to be able to serialize for my external client. I am currently using Newtonsoft.Json

My C# class could look something like this:

public class MyClass
{
    public string Customer {get; set;}
}

My expectation would be that I could serialize/ deserialize in two different ways,
e.g. my external client wants the field Customer to be renamed to Mandant.

Serialize for internal client:

{
   "Customer": "MyCustomer"
}

Serialize for external client:

{
   "Mandant": "MyCustomer"
}

答案1

得分: 1

请区分您的内部业务逻辑DTO(或POCO)和您发布到外部系统的数据(无论是客户还是您自己的另一个程序/工具/库都不重要)。

假设您有某种数据源(例如Sql数据库、Cosmos数据库、Redis缓存等)。通常,所使用的数据源都有一些关于如何设计类的约定(Sql通常具有Id属性或遵循某种方案来处理一对多的关系;Cosmos需要一个分区键;Redis需要一些缓存键等)。您应该遵循这些数据源规则,根据给定的数据源规则和您的要求(例如,读优化、写优化等)来建模您的对象。

接下来,定义DTO,以便它们按照其他系统的需求进行呈现。为它们提供客户所需的属性和结构(这也可以是您自己,但是可能是在同一个或另一个解决方案中的另一个项目)。然后编写一个转换器/映射器,将类型A的对象转换为类型B的对象(为此,您可以查看AutoMapper以简化该过程)。还有创建不同的DTO,即使是同一目标类型,但用于不同的操作也是有意义的(例如,创建/更新)。

所有这些步骤都需要一些工作,但从长远来看,它将更容易区分不同的操作和/或客户,并防止您创建试图同时处理多个事情(例如,客户)的大类。

英文:

Please distinguish between your internal business logic DTOs (or POCOs) and the data you publish to external systems (doesn't matter if it is a customer or another program / tool / library of yourself).

So let's assume you have some kind of data source (e.g. Sql DB, Cosmos DB, Redis cache, etc.). The used source normally has some kind of conventions on how the classes must be designed (Sql mostly has an Id property or follows some scheme to handle 1:many relationships; Cosmos needs a partition key; Redis needs some cache key; etc.). You should stick to these data source rules and model your objects to best fit the given source rules and your requirements (e.g. read optimized, write optimized, etc.).

In a next step define the DTOs on how they are presented to the other systems. Give them the properties and structure as required by the customer (this could be you too, but for another project in the same or another solution). Then write a converter / mapper that takes an object of type A and produces an object of type B (for this purpose you could take a look at AutoMapper to simplify the process). Also it makes sense to create different DTOs also for the same target type, but different operations (e.g. create / update).

All these steps need some effort, but in the long run it will be much easier to distinguish between the different operations and/or customers and prevent you from creating god classes which try to handle multiple things (e.g. customers) at once.

答案2

得分: 1

你可以使用自定义的ContractResolver

List<string[]> customerReplaces = new List<string[]> { 
    new string[] { "Customer", "Mandant" } 
};

var json = JsonConvert.SerializeObject(customer,
    Newtonsoft.Json.Formatting.Indented,
    new JsonSerializerSettings
    {
        ContractResolver = new ReplaceNamesContractResolver(customerReplaces)
    });
    
public class ReplaceNamesContractResolver : DefaultContractResolver
{
    private readonly List<string[]> _replaces;

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);

        var newName = _replaces.Where(v => v[0] == property.PropertyName)
                               .FirstOrDefault()?[1];

        if (newName != null) property.PropertyName = newName;

        return property;
    }

    public ReplaceNamesContractResolver(List<string[]> replaces)
    {
        _replaces = replaces;
    }
}
英文:

you can use a custom ContractResolver

List&lt;string[]&gt; customerReplaces = new List&lt;string[]&gt; { 
                    new string[] { &quot;Customer&quot;, &quot;Mandant&quot; } 
                   };

	var json = JsonConvert.SerializeObject(customer,
				Newtonsoft.Json.Formatting.Indented,
				new JsonSerializerSettings
				{
					ContractResolver = new ReplaceNamesContractResolver(customerReplaces)
				});

public class ReplaceNamesContractResolver : DefaultContractResolver
{
	private readonly List&lt;string[]&gt; _replaces;

	protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
	{

		JsonProperty property = base.CreateProperty(member, memberSerialization);

		var newName = _replaces.Where(v =&gt; v[0] == property.PropertyName)
							   .FirstOrDefault()?[1];

		if (newName != null) property.PropertyName = newName;

		return property;
	}

	public ReplaceNamesContractResolver(List&lt;string[]&gt; replaces)
	{
		_replaces = replaces;
	}
}

</details>



# 答案3
**得分**: 0

```csharp
使用 `Newtonsoft.Json` 中的 `JsonProperty` 属性:

```csharp
using Newtonsoft.Json;

public class MyClass 
{ 
    [JsonProperty("Customer")]
    public string Customer { get; set; }

    [JsonProperty("Mandant")]
    public string Mandant 
    { 
        get { return Customer; } 
        set { Customer = value; } 
    }
}
```

然后像这样使用:

```csharp
var obj = new MyClass { Customer = "MyCustomer" };

var SerializedForInternalClient = JsonConvert.SerializeObject(obj); // 输出: {"Customer":"MyCustomer"}
var SerializedForExternalClient = JsonConvert.SerializeObject(obj); // 输出: {"mandant":"MyCustomer"}

var DeserializedForInternalClient = JsonConvert.DeserializeObject<MyClass>(SerializedForInternalClient); // 输出: "MyCustomer"
var DeserializedForExternalClient = JsonConvert.DeserializeObject<MyClass>(SerializedForExternalClient); // 输出: "MyCustomer"
```

<details>
<summary>英文:</summary>

use the `JsonProperty` attribute from `Newtonsoft.Json` :

    using Newtonsoft.Json;
    
    public class MyClass 
    { 
        [JsonProperty(&quot;Customer&quot;)]
        public string Customer { get; set; }
    
        [JsonProperty(&quot;Mandant&quot;)]
        public string Mandant 
        { 
            get { return Customer; } 
            set { Customer = value; } 
        }
    }

then use it like this:

    var obj = new MyClass { Customer = &quot;MyCustomer&quot; };
    
    var SerializedForInternalClient = JsonConvert.SerializeObject(obj); // Output: {&quot;Customer&quot;:&quot;MyCustomer&quot;}
    var SerializedForExternalClient = JsonConvert.SerializeObject(obj); // Output: {&quot;mandant&quot;:&quot;MyCustomer&quot;}
    
    var DeserializedForInternalClient = JsonConvert.DeserializeObject&lt;MyClass&gt;(SerializedForInternalClient); // Output: &quot;MyCustomer&quot;
    var DeserializedForExternalClient = JsonConvert.DeserializeObject&lt;MyClass&gt;(SerializedForExternalClient); // Output: &quot;MyCustomer&quot;



</details>



huangapple
  • 本文由 发表于 2023年6月12日 17:44:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76455400.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定