JSON.NET部分更新REST API客户端客户端、部分、NET、JSON

2023-09-05 03:31:39 作者:权心权意只爱你

我建立一个C#/。NET 4.5客户端使用JSON.NET一个REST API。该API支持部分更新;因此presence或缺乏上更新了JSON的属性有意义。如果该属性是在JSON,服务器将设置相应的价值;该属性不通过服务器将不会更新。这也适用于空值。我有.NET类为每个模型;为每个JSON属性(pretty的标准)的属性。

作为一个例子可以说我有这个帐户对象(名字,备注)已经在服务器上存在:

  {
   名:克雷格',
   注:这些笔记
}
 

如果我通过在此JSON的更新,将更新名称,但会留下设为这些笔记的说明:

  VAR账户= api.GetAccount();
account.Name =鲍勃;
api.UpdateAccount(账户);

{
   名:鲍勃
}
 

如果我通过这个JSON中的更新,它将设置的名称和说明,以空服务器上:

  VAR账户= api.GetAccount();
account.Name =鲍勃;
account.Notes = NULL;
api.UpdateAccount(账户);

{
   '名':'鲍勃',
   注意:空
}
 
5款好用的 REST API 工具,推荐给你

所有好了这一点。

我的问题是如何在你JSON.NET很好地一起玩这个。 JSON.NET允许控制NullValueHandling基本上说,如果空值应被序列化与否。然而这是不够的在这种情况下。我需要能够确定是否调用code明确设置为空值。有没有推荐的方式来处理呢?

香港专业教育学院试图用一个字典内到我的模型来存储通过JSON被序列化的属性。这让我告诉如果属性已通过在字典中的关键presence被设置为任何(包括null)。我发现,这种方法有一定的困难,我最终改写了大量的code标配为JSON.NET(型号系列化,泛型,nullables,枚举...)。

注:我的确意识到上面的例子是有点做作。在现实中,帐户对象返回从服务器返回的将有两个名称和说明填充,并且当更新发生,将同时发送回来。

在这里适用的另一种情况是创建对象和处理生成的服务器默认期间。例如,假设服务器默认帐户的说明,以把笔记这里的帐户创建时。如果我通过在Notes属性与空值时,服务器会认为客户希望将其设置为null。现实的情况是,虽然客户端是不是要设置注释为空,在这种情况下会希望默认设置。

  VAR帐户=新帐户();
account.Name =鲍勃;
api.CreateAccount(账户);

{
   '名':'鲍勃',
   注意:空
}
 

由JSON.NET ...

pssed解决方案

我总是IM $ P $

下面是我结束了。我用了一个ContractResolver,该ShouldSerialize predicate和NullValueHandling属性的组合。这链接是非常有用的。的属性存储在在一个基类ApiModel一个字典;这code是直截了当的。

帐户型号

  [JsonProperty(名称)]
公共字符串名称
{
    {返回this.GetAttributeValue<字符串>(姓名); }
    集合{this.SetAttributeValue<字符串>(名,值); }
}
 

JSON序列化

  ApiModel.JsonSerializerSettings =新Newtonsoft.Json.JsonSerializerSettings();
ApiModel.JsonSerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Include;
ApiModel.JsonSerializerSettings.ContractResolver = ApiModel.JsonContractResolver;

内部类ApiModelContractResolver:Newtonsoft.Json.Serialization.DefaultContractResolver
{
    保护覆盖Newtonsoft.Json.Serialization.JsonProperty CreateProperty(System.Reflection.MemberInfo成员,Newtonsoft.Json.MemberSerialization memberSerialization)
    {
        VAR属性= base.CreateProperty(成员,memberSerialization);

        property.ShouldSerialize =
            例如=>
            {
                VAR apiModel =实例作为ApiModel;

                VAR hasAttribute = apiModel.HasAttribute(property.PropertyName);

                property.NullValueHandling = hasAttribute? Newtonsoft.Json.NullValueHandling.Include:Newtonsoft.Json.NullValueHandling.Ignore;

                返回hasAttribute;
            };

        返回财产;
    }
}
 

I am building a C#/.NET 4.5 client for a REST API using JSON.NET. The API supports partial updates; therefore the presence or lack of an attribute in the json on an update has meaning. If the attribute is in the json, the server will set the value accordingly; the the attribute is not passed the server will not update it. This also applies to null values. I have .NET classes for each model; with properties for each JSON attribute (pretty standard).

As an example lets say I have this account object (name, notes) that already exists on the server:

{
   'name':'craig',
   'notes:'these are notes'
}

If I pass in this json for an update it will update the name, but will leave the notes set to 'these are notes':

var account = api.GetAccount();
account.Name = "bob";
api.UpdateAccount(account);

{
   'name':'bob'
}

If I pass this json in for an update, it will set the name and the notes to null on the server:

var account = api.GetAccount();
account.Name = "bob";
account.Notes = null;
api.UpdateAccount(account);

{
   'name':'bob',
   'notes':null
}

All good up to this point.

My question is how to you get JSON.NET to play along nicely with this. JSON.NET allows control the NullValueHandling which basically says if null values should be serialized or not. However that is not enough in this case. I need to be able to determine if the calling code explicitly set the value to null. Is there a recommended way to handle this?

Ive tried using a Dictionary internal to my models to store the attributes to be serialized via JSON. This allows me to tell if the attribute has been set to anything (including null) via the presence of the key in the dictionary. I found that this approach has some difficulties and I end up rewriting a lot of code that comes standard to JSON.NET (type serialization, generics, nullables, enums...).

Note: I do realize the above example is a bit contrived. In reality the account object returned back from the server would have both name and notes populated, and that when the update happened it would send both back.

The other case where this applies is during creating objects and handling server generated default. For example, lets say the server defaults the account's notes to 'put notes here' when the account is created. If I pass in the Notes attribute with a null value, the server will think the client wants to set it to null. The reality though is the client is not trying to set the Notes to null, and in this case would want the default to be set.

var account = new Account();
account.Name = "bob";
api.CreateAccount(account);

{
   'name':'bob',
   'notes':null
}

解决方案

Im always impressed by JSON.NET...

Here is what I ended up with. I used a combination of a ContractResolver, the ShouldSerialize predicate and the NullValueHandling property. This link was very useful. The properties are stored in a Dictionary in a base class ApiModel; that code is straightforward.

Account Model

[JsonProperty("name")]
public string Name
{
    get { return this.GetAttributeValue<string>("name"); }
    set { this.SetAttributeValue<string>("name", value); }
}

Json Serialization

ApiModel.JsonSerializerSettings = new Newtonsoft.Json.JsonSerializerSettings();
ApiModel.JsonSerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Include;
ApiModel.JsonSerializerSettings.ContractResolver = ApiModel.JsonContractResolver;

internal class ApiModelContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
    protected override Newtonsoft.Json.Serialization.JsonProperty CreateProperty(System.Reflection.MemberInfo member, Newtonsoft.Json.MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);

        property.ShouldSerialize =
            instance =>
            {
                var apiModel = instance as ApiModel;

                var hasAttribute = apiModel.HasAttribute(property.PropertyName);

                property.NullValueHandling = hasAttribute ? Newtonsoft.Json.NullValueHandling.Include : Newtonsoft.Json.NullValueHandling.Ignore;

                return hasAttribute;
            };

        return property;
    }
}