C# 如何添加元数据来描述JSON.Net中哪些属性是日期

C# 如何添加元数据来描述JSON.Net中哪些属性是日期,c#,json,date,datetime,json.net,C#,Json,Date,Datetime,Json.net,我想在我的json中添加一个元数据属性,这样客户端就可以知道哪些属性是日期 例如,如果我有这样一个对象: { "notADate": "a value", "aDate": "2017-04-23T18:25:43.511Z", "anotherDate": "2017-04-23T18:25:43.511Z" } { "_date_properties_": ["aDate", "anotherDate"], "notADate": "a value", "aDate

我想在我的json中添加一个元数据属性,这样客户端就可以知道哪些属性是日期

例如,如果我有这样一个对象:

{
  "notADate": "a value",
  "aDate": "2017-04-23T18:25:43.511Z",
  "anotherDate": "2017-04-23T18:25:43.511Z"
}
{
  "_date_properties_": ["aDate", "anotherDate"],
  "notADate": "a value",
  "aDate": "2017-04-23T18:25:43.511Z",
  "anotherDate": "2017-04-23T18:25:43.511Z"
}
我想添加一个元数据属性,告诉消费者哪些属性要作为日期处理,如下所示:

{
  "notADate": "a value",
  "aDate": "2017-04-23T18:25:43.511Z",
  "anotherDate": "2017-04-23T18:25:43.511Z"
}
{
  "_date_properties_": ["aDate", "anotherDate"],
  "notADate": "a value",
  "aDate": "2017-04-23T18:25:43.511Z",
  "anotherDate": "2017-04-23T18:25:43.511Z"
}
任何帮助都会很好,谢谢

您可以创建一个将合成的
“\u date\u properties\uu”
属性插入到每个序列化对象的协定中的

为此,第一个子类允许在应用程序添加的事件处理程序创建契约后,对其进行流畅的自定义:

public class ConfigurableContractResolver : DefaultContractResolver
{
    readonly object contractCreatedPadlock = new object();
    event EventHandler<ContractCreatedEventArgs> contractCreated;
    int contractCount = 0;

    void OnContractCreated(JsonContract contract, Type objectType)
    {
        EventHandler<ContractCreatedEventArgs> created;
        lock (contractCreatedPadlock)
        {
            contractCount++;
            created = contractCreated;
        }
        if (created != null)
        {
            created(this, new ContractCreatedEventArgs(contract, objectType));
        }
    }

    public event EventHandler<ContractCreatedEventArgs> ContractCreated
    {
        add
        {
            lock (contractCreatedPadlock)
            {
                if (contractCount > 0)
                {
                    throw new InvalidOperationException("ContractCreated events cannot be added after the first contract is generated.");
                }
                contractCreated += value;
            }
        }
        remove
        {
            lock (contractCreatedPadlock)
            {
                if (contractCount > 0)
                {
                    throw new InvalidOperationException("ContractCreated events cannot be removed after the first contract is generated.");
                }
                contractCreated -= value;
            }
        }  
    }

    protected override JsonContract CreateContract(Type objectType)
    {
        var contract = base.CreateContract(objectType);
        OnContractCreated(contract, objectType);
        return contract;
    }
}

public class ContractCreatedEventArgs : EventArgs
{
    public JsonContract Contract { get; private set; }
    public Type ObjectType { get; private set; }

    public ContractCreatedEventArgs(JsonContract contract, Type objectType)
    {
        this.Contract = contract;
        this.ObjectType = objectType;
    }
}

public static class ConfigurableContractResolverExtensions
{
    public static ConfigurableContractResolver Configure(this ConfigurableContractResolver resolver, EventHandler<ContractCreatedEventArgs> handler)
    {
        if (resolver == null || handler == null)
            throw new ArgumentNullException();
        resolver.ContractCreated += handler;
        return resolver;
    }
}
最后,按如下方式序列化示例类型:

var settings = new JsonSerializerSettings
{
    ContractResolver = new ConfigurableContractResolver
    {
        // Here I am using CamelCaseNamingStrategy as is shown in your JSON.
        // If you don't want camel case, leave NamingStrategy null.
        NamingStrategy = new CamelCaseNamingStrategy(),
    }.Configure((s, e) => { e.Contract.AddDateProperties(); }),
};

var json = JsonConvert.SerializeObject(example, Formatting.Indented, settings);
此解决方案仅处理静态类型的
DateTime
DateTime?
属性。如果您有
对象
值的属性,这些属性有时有
日期时间
值,或者有
字典
,或者包含
日期时间
值,则需要更复杂的解决方案

(作为替代实现,您可以使用
JsonContractExtensions.AddDateProperties()对所需的属性进行子类化和硬编码。)
,但我认为创建一个通用的、可流畅配置的契约解析器会更有趣,以防以后需要插入不同的定制。)

您可能希望获得最佳性能

示例。

您可以创建一个将合成的
“\u date\u properties\uu”
属性插入到序列化的每个对象的契约中的

为此,第一个子类允许在应用程序添加的事件处理程序创建契约后,对其进行流畅的自定义:

public class ConfigurableContractResolver : DefaultContractResolver
{
    readonly object contractCreatedPadlock = new object();
    event EventHandler<ContractCreatedEventArgs> contractCreated;
    int contractCount = 0;

    void OnContractCreated(JsonContract contract, Type objectType)
    {
        EventHandler<ContractCreatedEventArgs> created;
        lock (contractCreatedPadlock)
        {
            contractCount++;
            created = contractCreated;
        }
        if (created != null)
        {
            created(this, new ContractCreatedEventArgs(contract, objectType));
        }
    }

    public event EventHandler<ContractCreatedEventArgs> ContractCreated
    {
        add
        {
            lock (contractCreatedPadlock)
            {
                if (contractCount > 0)
                {
                    throw new InvalidOperationException("ContractCreated events cannot be added after the first contract is generated.");
                }
                contractCreated += value;
            }
        }
        remove
        {
            lock (contractCreatedPadlock)
            {
                if (contractCount > 0)
                {
                    throw new InvalidOperationException("ContractCreated events cannot be removed after the first contract is generated.");
                }
                contractCreated -= value;
            }
        }  
    }

    protected override JsonContract CreateContract(Type objectType)
    {
        var contract = base.CreateContract(objectType);
        OnContractCreated(contract, objectType);
        return contract;
    }
}

public class ContractCreatedEventArgs : EventArgs
{
    public JsonContract Contract { get; private set; }
    public Type ObjectType { get; private set; }

    public ContractCreatedEventArgs(JsonContract contract, Type objectType)
    {
        this.Contract = contract;
        this.ObjectType = objectType;
    }
}

public static class ConfigurableContractResolverExtensions
{
    public static ConfigurableContractResolver Configure(this ConfigurableContractResolver resolver, EventHandler<ContractCreatedEventArgs> handler)
    {
        if (resolver == null || handler == null)
            throw new ArgumentNullException();
        resolver.ContractCreated += handler;
        return resolver;
    }
}
最后,按如下方式序列化示例类型:

var settings = new JsonSerializerSettings
{
    ContractResolver = new ConfigurableContractResolver
    {
        // Here I am using CamelCaseNamingStrategy as is shown in your JSON.
        // If you don't want camel case, leave NamingStrategy null.
        NamingStrategy = new CamelCaseNamingStrategy(),
    }.Configure((s, e) => { e.Contract.AddDateProperties(); }),
};

var json = JsonConvert.SerializeObject(example, Formatting.Indented, settings);
此解决方案仅处理静态类型的
DateTime
DateTime?
属性。如果您有
对象
值的属性,这些属性有时有
日期时间
值,或者有
字典
,或者包含
日期时间
值,则需要更复杂的解决方案

(作为替代实现,您可以使用
JsonContractExtensions.AddDateProperties()对所需的属性进行子类化和硬编码。)
,但我认为创建一个通用的、可流畅配置的契约解析器会更有趣,以防以后需要插入不同的定制。)

您可能希望获得最佳性能


示例。

您是否考虑过使用约定,而不是像这样添加配置信息。例如,所有日期属性都以“日期”结尾。那么,除了命名、使数组保持最新等之外,您在服务器上不需要任何特殊考虑。很难记住使用约定并避免意外使用它们。例如,
DateTime StartTime
将“失败”,而
boolean HasDate
将“通过”,而不是像这样添加配置信息,您是否考虑过使用约定。例如,所有日期属性都以“日期”结尾。那么,除了命名、使数组保持最新等之外,您在服务器上不需要任何特殊考虑。很难记住使用约定并避免意外使用它们。即,
DateTime StartTime
将“失败”,而
boolean HasDate
将“通过”