使用 JSchemaGenerator 在生成 json 架构时添加选项 属性
Adding options property while generating json schema using JSchemaGenerator
我正在使用 Newtonsoft 的 Json.NET Schema 模式生成器,我想生成一个 JSON 模式并隐藏几个字段。我知道使用 options
属性 是可能的。这是使用此 属性.
的示例模式
{
"title": "Person",
"type": "object",
"properties": {
"name": {
"type": "string",
"options": { "hidden": true },
"description": "First and Last name",
"minLength": 4,
"default": "Jeremy Dorn"
}
}
}
我有一个 class 作为模式的基础,我决定对我想在模式生成期间隐藏的属性使用自定义属性。然后使用自定义 GenerationProvider 我想检查该字段是否具有该属性,如果有则添加 "options": { "hidden": true },
位。
问题是 JSchema
class 没有 Hidden
属性(就像之前的 JsonSchema
class)也不是 Options
属性.
注意:我不想使用 [JsonIgnore]
,因为我需要在某些地方序列化这些属性,但我只想在创建模式时隐藏它们。
有什么实现方法吗?
我不知道 Newtonsoft,但是 JsonSchema.Net.Generation 可以使用内置的 [JsonIgnore]
属性轻松地做到这一点。这个模式库建立在 System.Text.Json
.
之上
我显然需要证明这是特别受支持的,但这里是 docs for the library. I do have a test (line 168) 确认它有效的其余部分。
关键字 "options": { "hidden": true }
甚至 "hidden": true
似乎不在 validation keywords for the current JSON Schema specification -- or any earlier version as far as I can tell. The only keywords that seem related are readOnly
and writeOnly
. From the docs:
中
New in draft 7 The boolean keywords readOnly
and writeOnly
are typically used in an API context. readOnly
indicates that a value should not be modified. It could be used to indicate that a PUT
request that changes a value would result in a 400 Bad Request
response. writeOnly
indicates that a value may be set, but will remain hidden. In could be used to indicate you can set a value with a PUT
request, but it would not be included when retrieving that record with a GET
request.
{
"title": "Match anything",
"description": "This is a schema that matches anything.",
"default": "Default value",
"examples": [
"Anything",
4035
],
"readOnly": true,
"writeOnly": false
}
因此,"options": { "hidden": true }
似乎是对 JSON 架构标准的某种自定义或第三方扩展。 Json.NET 架构通过 JSchema.ExtensionData
property. To set your hidden option in this extension data during automatic schema generation, define the following JSchemaGenerationProvider
:
支持此类自定义验证关键字
[System.AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class HiddenAttribute : System.Attribute
{
}
public class HiddenOptionProvider : CustomizedProviderBase
{
public override JSchema GetSchema(JSchemaTypeGenerationContext context)
{
var schema = base.GetSchema(context);
// Get the JsonObjectContract for this type.
var contract = (JsonObjectContract)context.Generator.ContractResolver.ResolveContract(context.ObjectType);
foreach (var propertySchema in schema.Properties)
{
// Find the corresponding JsonProperty from the contract resolver.
var jProperty = contract.Properties[propertySchema.Key];
// Check to see if the member has HiddenAttribute set.
if (jProperty.AttributeProvider.GetAttributes(typeof(HiddenAttribute), true).Any())
// If so add "options": { "hidden": true }
propertySchema.Value.ExtensionData["options"] = new JObject(new JProperty("hidden", true));
}
return schema;
}
public override bool CanGenerateSchema(JSchemaTypeGenerationContext context) =>
base.CanGenerateSchema(context) && context.Generator.ContractResolver.ResolveContract(context.ObjectType) is JsonObjectContract;
}
public abstract class CustomizedProviderBase : JSchemaGenerationProvider
{
// Base class that allows generation of a default schema which may then be subsequently customized.
// Note this class contains state information and so is not thread safe.
readonly Stack<Type> currentTypes = new ();
public override JSchema GetSchema(JSchemaTypeGenerationContext context)
{
if (CanGenerateSchema(context))
{
var currentType = context.ObjectType;
try
{
currentTypes.Push(currentType);
return context.Generator.Generate(currentType);
}
finally
{
currentTypes.Pop();
}
}
else
throw new NotImplementedException();
}
public override bool CanGenerateSchema(JSchemaTypeGenerationContext context) =>
!currentTypes.TryPeek(out var t) || t != context.ObjectType;
}
然后按如下方式定义您的 Person
类型:
[DisplayName("Person")]
public class Person
{
[JsonProperty("name", Required = Required.DisallowNull)]
[DefaultValue("Jeremy Dorn"), MinLength(4), System.ComponentModel.DescriptionAttribute("First and Last name")]
[Hidden] // Your custom attribute
public string Name { get; set; } = "Jeremy Dorn";
}
并生成如下模式:
var generator = new JSchemaGenerator();
generator.GenerationProviders.Add(new HiddenOptionProvider());
var schema = generator.Generate(typeof(Person));
您将根据需要获得以下架构:
{
"title": "Person",
"type": "object",
"properties": {
"name": {
"description": "First and Last name",
"options": {
"hidden": true
},
"type": "string",
"default": "Jeremy Dorn",
"minLength": 4
}
}
}
演示 fiddle here.
这是对@dbc 的相当长的回复,它帮助我完成了这项工作。由于我为其创建架构的 classes 非常大,并且其中包含不同类型的负载,因此我无法使用此解决方案。我在这里注意到的几件事。我正在使用 "Newtonsoft.Json.Schema" Version="3.0.14"
并在自定义提供程序中使用行
var contract = (JsonObjectContract)context.Generator.ContractResolver.ResolveContract(context.ObjectType);
抛出异常,因为 JsonObjectContrac
的转换是不可能的,因为 context.Generator.ContractResolver.ResolveContract(context.ObjectType);
正在返回 JsonPrimitiveContract
。我不想花太多时间解决这个问题,因此我继续编写代码并尝试执行类似 dbc 在此代码中执行的操作:
foreach (var propertySchema in schema.Properties)
{
// Find the corresponding JsonProperty from the contract resolver.
var jProperty = contract.Properties[propertySchema.Key];
// Check to see if the member has HiddenAttribute set.
if (jProperty.AttributeProvider.GetAttributes(typeof(HiddenAttribute), true).Any())
// If so add "options": { "hidden": true }
propertySchema.Value.ExtensionData["options"] = new JObject(new JProperty("hidden", true));
}
另一个问题出现了,因为在大多数情况下 schema.Properties
是空的。我注意到这个自定义提供程序不仅被调用一次,而且每个 属性 都被调用,这是我的基础 class 的一部分,用于架构,一次为基础 class 本身(基本上这个提供者被调用了数百次)。所以我最终只是在 class 中创建了模式,然后应用了 ExtensionData
。因此,我的提供者除了执行一些其他逻辑外,它还有 CheckIsHidden(JSchemaTypeGenerationContext context, JSchema schema)
方法来完成这项工作:
public static void CheckIsHidden(JSchemaTypeGenerationContext context, JSchema schema)
{
var hiddenAttribute = context.MemberProperty?.AttributeProvider?.GetAttributes(true)
?.FirstOrDefault(a => a.GetType().Name == nameof(JsonConfigIgnoreAttribute));
if (hiddenAttribute != null)
{
schema.ExtensionData["options"] = new JObject(new JProperty("hidden", true));
}
}
评论确实帮助我实现了这一点,因为我主要是在寻找这一行 schema.ExtensionData["options"] = new JObject(new JProperty("hidden", true));
。非常感谢!
我正在使用 Newtonsoft 的 Json.NET Schema 模式生成器,我想生成一个 JSON 模式并隐藏几个字段。我知道使用 options
属性 是可能的。这是使用此 属性.
{
"title": "Person",
"type": "object",
"properties": {
"name": {
"type": "string",
"options": { "hidden": true },
"description": "First and Last name",
"minLength": 4,
"default": "Jeremy Dorn"
}
}
}
我有一个 class 作为模式的基础,我决定对我想在模式生成期间隐藏的属性使用自定义属性。然后使用自定义 GenerationProvider 我想检查该字段是否具有该属性,如果有则添加 "options": { "hidden": true },
位。
问题是 JSchema
class 没有 Hidden
属性(就像之前的 JsonSchema
class)也不是 Options
属性.
注意:我不想使用 [JsonIgnore]
,因为我需要在某些地方序列化这些属性,但我只想在创建模式时隐藏它们。
有什么实现方法吗?
我不知道 Newtonsoft,但是 JsonSchema.Net.Generation 可以使用内置的 [JsonIgnore]
属性轻松地做到这一点。这个模式库建立在 System.Text.Json
.
我显然需要证明这是特别受支持的,但这里是 docs for the library. I do have a test (line 168) 确认它有效的其余部分。
关键字 "options": { "hidden": true }
甚至 "hidden": true
似乎不在 validation keywords for the current JSON Schema specification -- or any earlier version as far as I can tell. The only keywords that seem related are readOnly
and writeOnly
. From the docs:
New in draft 7 The boolean keywords
readOnly
andwriteOnly
are typically used in an API context.readOnly
indicates that a value should not be modified. It could be used to indicate that aPUT
request that changes a value would result in a400 Bad Request
response.writeOnly
indicates that a value may be set, but will remain hidden. In could be used to indicate you can set a value with aPUT
request, but it would not be included when retrieving that record with aGET
request.{ "title": "Match anything", "description": "This is a schema that matches anything.", "default": "Default value", "examples": [ "Anything", 4035 ], "readOnly": true, "writeOnly": false }
因此,"options": { "hidden": true }
似乎是对 JSON 架构标准的某种自定义或第三方扩展。 Json.NET 架构通过 JSchema.ExtensionData
property. To set your hidden option in this extension data during automatic schema generation, define the following JSchemaGenerationProvider
:
[System.AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class HiddenAttribute : System.Attribute
{
}
public class HiddenOptionProvider : CustomizedProviderBase
{
public override JSchema GetSchema(JSchemaTypeGenerationContext context)
{
var schema = base.GetSchema(context);
// Get the JsonObjectContract for this type.
var contract = (JsonObjectContract)context.Generator.ContractResolver.ResolveContract(context.ObjectType);
foreach (var propertySchema in schema.Properties)
{
// Find the corresponding JsonProperty from the contract resolver.
var jProperty = contract.Properties[propertySchema.Key];
// Check to see if the member has HiddenAttribute set.
if (jProperty.AttributeProvider.GetAttributes(typeof(HiddenAttribute), true).Any())
// If so add "options": { "hidden": true }
propertySchema.Value.ExtensionData["options"] = new JObject(new JProperty("hidden", true));
}
return schema;
}
public override bool CanGenerateSchema(JSchemaTypeGenerationContext context) =>
base.CanGenerateSchema(context) && context.Generator.ContractResolver.ResolveContract(context.ObjectType) is JsonObjectContract;
}
public abstract class CustomizedProviderBase : JSchemaGenerationProvider
{
// Base class that allows generation of a default schema which may then be subsequently customized.
// Note this class contains state information and so is not thread safe.
readonly Stack<Type> currentTypes = new ();
public override JSchema GetSchema(JSchemaTypeGenerationContext context)
{
if (CanGenerateSchema(context))
{
var currentType = context.ObjectType;
try
{
currentTypes.Push(currentType);
return context.Generator.Generate(currentType);
}
finally
{
currentTypes.Pop();
}
}
else
throw new NotImplementedException();
}
public override bool CanGenerateSchema(JSchemaTypeGenerationContext context) =>
!currentTypes.TryPeek(out var t) || t != context.ObjectType;
}
然后按如下方式定义您的 Person
类型:
[DisplayName("Person")]
public class Person
{
[JsonProperty("name", Required = Required.DisallowNull)]
[DefaultValue("Jeremy Dorn"), MinLength(4), System.ComponentModel.DescriptionAttribute("First and Last name")]
[Hidden] // Your custom attribute
public string Name { get; set; } = "Jeremy Dorn";
}
并生成如下模式:
var generator = new JSchemaGenerator();
generator.GenerationProviders.Add(new HiddenOptionProvider());
var schema = generator.Generate(typeof(Person));
您将根据需要获得以下架构:
{
"title": "Person",
"type": "object",
"properties": {
"name": {
"description": "First and Last name",
"options": {
"hidden": true
},
"type": "string",
"default": "Jeremy Dorn",
"minLength": 4
}
}
}
演示 fiddle here.
这是对@dbc 的相当长的回复,它帮助我完成了这项工作。由于我为其创建架构的 classes 非常大,并且其中包含不同类型的负载,因此我无法使用此解决方案。我在这里注意到的几件事。我正在使用 "Newtonsoft.Json.Schema" Version="3.0.14"
并在自定义提供程序中使用行
var contract = (JsonObjectContract)context.Generator.ContractResolver.ResolveContract(context.ObjectType);
抛出异常,因为 JsonObjectContrac
的转换是不可能的,因为 context.Generator.ContractResolver.ResolveContract(context.ObjectType);
正在返回 JsonPrimitiveContract
。我不想花太多时间解决这个问题,因此我继续编写代码并尝试执行类似 dbc 在此代码中执行的操作:
foreach (var propertySchema in schema.Properties)
{
// Find the corresponding JsonProperty from the contract resolver.
var jProperty = contract.Properties[propertySchema.Key];
// Check to see if the member has HiddenAttribute set.
if (jProperty.AttributeProvider.GetAttributes(typeof(HiddenAttribute), true).Any())
// If so add "options": { "hidden": true }
propertySchema.Value.ExtensionData["options"] = new JObject(new JProperty("hidden", true));
}
另一个问题出现了,因为在大多数情况下 schema.Properties
是空的。我注意到这个自定义提供程序不仅被调用一次,而且每个 属性 都被调用,这是我的基础 class 的一部分,用于架构,一次为基础 class 本身(基本上这个提供者被调用了数百次)。所以我最终只是在 class 中创建了模式,然后应用了 ExtensionData
。因此,我的提供者除了执行一些其他逻辑外,它还有 CheckIsHidden(JSchemaTypeGenerationContext context, JSchema schema)
方法来完成这项工作:
public static void CheckIsHidden(JSchemaTypeGenerationContext context, JSchema schema)
{
var hiddenAttribute = context.MemberProperty?.AttributeProvider?.GetAttributes(true)
?.FirstOrDefault(a => a.GetType().Name == nameof(JsonConfigIgnoreAttribute));
if (hiddenAttribute != null)
{
schema.ExtensionData["options"] = new JObject(new JProperty("hidden", true));
}
}
评论确实帮助我实现了这一点,因为我主要是在寻找这一行 schema.ExtensionData["options"] = new JObject(new JProperty("hidden", true));
。非常感谢!