JsonSchemaGenerator
Generates a JsonSchema4 object for a given type.
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using NJsonSchema.Annotations;
using NJsonSchema.Converters;
using NJsonSchema.Generation.TypeMappers;
using NJsonSchema.Infrastructure;
using NJsonSchema.References;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace NJsonSchema.Generation
{
public class JsonSchemaGenerator
{
private static readonly Dictionary<string, string> DataTypeFormats = new Dictionary<string, string> {
{
"DateTime",
"date-time"
},
{
"Date",
"date"
},
{
"Time",
"time"
},
{
"EmailAddress",
"email"
},
{
"PhoneNumber",
"phone"
},
{
"Url",
"uri"
}
};
public JsonSchemaGeneratorSettings Settings { get; }
public JsonSchemaGenerator(JsonSchemaGeneratorSettings settings)
{
Settings = settings;
}
public async Task<JsonSchema4> GenerateAsync(Type type)
{
JsonSchema4 schema = new JsonSchema4();
JsonSchemaResolver schemaResolver = new JsonSchemaResolver(schema, Settings);
await GenerateAsync(type, null, schema, schemaResolver).ConfigureAwait(false);
return schema;
}
public Task<JsonSchema4> GenerateAsync(Type type, JsonSchemaResolver schemaResolver)
{
return GenerateAsync<JsonSchema4>(type, schemaResolver);
}
public Task<TSchemaType> GenerateAsync<TSchemaType>(Type type, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
return GenerateAsync<TSchemaType>(type, null, schemaResolver);
}
public async Task<JsonSchema4> GenerateAsync(Type type, IEnumerable<Attribute> parentAttributes, JsonSchemaResolver schemaResolver)
{
return await GenerateAsync<JsonSchema4>(type, parentAttributes, schemaResolver).ConfigureAwait(false);
}
public async Task<TSchemaType> GenerateAsync<TSchemaType>(Type type, IEnumerable<Attribute> parentAttributes, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
TSchemaType schema = new TSchemaType();
await this.GenerateAsync<TSchemaType>(type, parentAttributes, schema, schemaResolver).ConfigureAwait(false);
return schema;
}
public virtual async Task GenerateAsync<TSchemaType>(Type type, IEnumerable<Attribute> parentAttributes, TSchemaType schema, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
JsonSchemaTypeAttribute jsonSchemaTypeAttribute = CustomAttributeExtensions.GetCustomAttribute<JsonSchemaTypeAttribute>((MemberInfo)type.GetTypeInfo()) ?? ((parentAttributes != null) ? Enumerable.SingleOrDefault<JsonSchemaTypeAttribute>(Enumerable.OfType<JsonSchemaTypeAttribute>((IEnumerable)parentAttributes)) : null);
if (jsonSchemaTypeAttribute != null)
type = jsonSchemaTypeAttribute.Type;
this.ApplyExtensionDataAttributes<TSchemaType>(type, schema, parentAttributes);
if (await this.TryHandleSpecialTypesAsync<TSchemaType>(type, schema, schemaResolver, parentAttributes).ConfigureAwait(false))
await ApplySchemaProcessorsAsync(type, schema, schemaResolver).ConfigureAwait(false);
else {
if (schemaResolver.RootObject == schema)
schema.Title = Settings.SchemaNameGenerator.Generate(type);
JsonTypeDescription description = Settings.ReflectionService.GetDescription(type, parentAttributes, Settings);
if (description.Type.HasFlag(JsonObjectType.Object)) {
if (description.IsDictionary) {
description.ApplyType(schema);
await this.GenerateDictionaryAsync<TSchemaType>(schema, type, schemaResolver).ConfigureAwait(false);
} else if (schemaResolver.HasSchema(type, false)) {
((JsonReferenceBase<JsonSchema4>)schema).Reference = schemaResolver.GetSchema(type, false);
} else if (schema.GetType() == typeof(JsonSchema4)) {
await GenerateObjectAsync(type, description, schema, schemaResolver).ConfigureAwait(false);
} else {
((JsonReferenceBase<JsonSchema4>)schema).Reference = await GenerateAsync(type, parentAttributes, schemaResolver).ConfigureAwait(false);
}
} else if (description.IsEnum) {
await this.GenerateEnum<TSchemaType>(schema, type, parentAttributes, description, schemaResolver).ConfigureAwait(false);
} else if (description.Type.HasFlag(JsonObjectType.Array)) {
await this.GenerateArray<TSchemaType>(schema, type, description, schemaResolver).ConfigureAwait(false);
} else {
description.ApplyType(schema);
}
await ApplySchemaProcessorsAsync(type, schema, schemaResolver).ConfigureAwait(false);
}
}
public async Task<TSchemaType> GenerateWithReferenceAsync<TSchemaType>(Type type, IEnumerable<Attribute> parentAttributes, JsonSchemaResolver schemaResolver, Func<TSchemaType, JsonSchema4, Task> transformation = null) where TSchemaType : JsonSchema4, new
{
return await this.GenerateWithReferenceAndNullabilityAsync<TSchemaType>(type, parentAttributes, false, schemaResolver, transformation).ConfigureAwait(false);
}
public async Task<TSchemaType> GenerateWithReferenceAndNullabilityAsync<TSchemaType>(Type type, IEnumerable<Attribute> parentAttributes, JsonSchemaResolver schemaResolver, Func<TSchemaType, JsonSchema4, Task> transformation = null) where TSchemaType : JsonSchema4, new
{
JsonTypeDescription description = Settings.ReflectionService.GetDescription(type, parentAttributes, Settings);
return await this.GenerateWithReferenceAndNullabilityAsync<TSchemaType>(type, parentAttributes, description.IsNullable, schemaResolver, transformation).ConfigureAwait(false);
}
public virtual async Task<TSchemaType> GenerateWithReferenceAndNullabilityAsync<TSchemaType>(Type type, IEnumerable<Attribute> parentAttributes, bool isNullable, JsonSchemaResolver schemaResolver, Func<TSchemaType, JsonSchema4, Task> transformation = null) where TSchemaType : JsonSchema4, new
{
JsonSchema4 referencedSchema;
if (!Settings.ReflectionService.GetDescription(type, parentAttributes, Settings).RequiresSchemaReference(Settings.TypeMappers)) {
TSchemaType schema = await this.GenerateAsync<TSchemaType>(type, parentAttributes, schemaResolver).ConfigureAwait(false);
if (!schema.HasReference) {
if (transformation != null)
await transformation(schema, schema).ConfigureAwait(false);
if (isNullable) {
if (Settings.SchemaType == SchemaType.JsonSchema) {
if (schema.Type == JsonObjectType.None) {
schema.OneOf.Add(new JsonSchema4 {
Type = JsonObjectType.None
});
schema.OneOf.Add(new JsonSchema4 {
Type = JsonObjectType.Null
});
} else
schema.Type |= JsonObjectType.Null;
} else if (Settings.SchemaType == SchemaType.OpenApi3) {
schema.IsNullableRaw = isNullable;
}
}
return schema;
}
referencedSchema = schema.ActualSchema;
} else
referencedSchema = await this.GenerateAsync<JsonSchema4>(type, parentAttributes, schemaResolver).ConfigureAwait(false);
TSchemaType referencingSchema = new TSchemaType();
if (transformation != null)
await transformation(referencingSchema, referencedSchema).ConfigureAwait(false);
if (isNullable) {
if (Settings.SchemaType == SchemaType.JsonSchema)
referencingSchema.OneOf.Add(new JsonSchema4 {
Type = JsonObjectType.Null
});
else if (Settings.SchemaType == SchemaType.OpenApi3) {
referencingSchema.IsNullableRaw = true;
}
}
if ((Settings.AllowReferencesWithProperties || !Enumerable.Any<JProperty>(JsonConvert.DeserializeObject<JObject>(JsonConvert.SerializeObject(referencingSchema)).Properties())) && referencingSchema.OneOf.Count == 0)
((JsonReferenceBase<JsonSchema4>)referencingSchema).Reference = referencedSchema.ActualSchema;
else if (Settings.SchemaType != SchemaType.Swagger2) {
referencingSchema.OneOf.Add(new JsonSchema4 {
Reference = referencedSchema.ActualSchema
});
} else {
referencingSchema.AllOf.Add(new JsonSchema4 {
Reference = referencedSchema.ActualSchema
});
}
return referencingSchema;
}
public virtual string GetPropertyName(Newtonsoft.Json.Serialization.JsonProperty property, MemberInfo memberInfo)
{
try {
string text = (memberInfo != (MemberInfo)null) ? ReflectionCache.GetPropertiesAndFields(memberInfo.DeclaringType).First((ReflectionCache.PropertyOrField p) => p.MemberInfo.Name == memberInfo.Name).GetName() : property.PropertyName;
DefaultContractResolver defaultContractResolver = Settings.ActualContractResolver as DefaultContractResolver;
return (defaultContractResolver != null) ? defaultContractResolver.GetResolvedPropertyName(text) : text;
} catch (Exception innerException) {
throw new InvalidOperationException("Could not get JSON property name of property '" + ((memberInfo != (MemberInfo)null) ? memberInfo.Name : "n/a") + "' and type '" + ((memberInfo?.DeclaringType != (Type)null) ? memberInfo.DeclaringType.FullName : "n/a") + "'.", innerException);
}
}
protected virtual async Task GenerateObjectAsync(Type type, JsonTypeDescription typeDescription, JsonSchema4 schema, JsonSchemaResolver schemaResolver)
{
schemaResolver.AddSchema(type, false, schema);
JsonSchema4 rootSchema = schema;
JsonSchema4 jsonSchema = await GenerateInheritanceAsync(type, schema, schemaResolver).ConfigureAwait(false);
if (jsonSchema == null) {
await GeneratePropertiesAsync(type, schema, schemaResolver).ConfigureAwait(false);
await ApplyAdditionalPropertiesAsync(type, schema, schemaResolver).ConfigureAwait(false);
} else
schema = jsonSchema;
typeDescription.ApplyType(schema);
JsonSchema4 jsonSchema2 = schema;
jsonSchema2.Description = await type.GetTypeInfo().GetDescriptionAsync(type.GetTypeInfo().GetCustomAttributes()).ConfigureAwait(false);
schema.IsAbstract = type.GetTypeInfo().IsAbstract;
GenerateInheritanceDiscriminator(type, rootSchema, schema);
await GenerateKnownTypesAsync(type, schemaResolver).ConfigureAwait(false);
if (Settings.GenerateXmlObjects)
schema.GenerateXmlObjectForType(type);
}
private async Task ApplyAdditionalPropertiesAsync<TSchemaType>(Type type, TSchemaType schema, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
PropertyInfo propertyInfo = Enumerable.FirstOrDefault<PropertyInfo>(type.GetRuntimeProperties(), (Func<PropertyInfo, bool>)((PropertyInfo p) => Enumerable.Any<object>((IEnumerable<object>)p.GetCustomAttributes(false), (Func<object, bool>)((object a) => a.GetType().IsAssignableTo("JsonExtensionDataAttribute", TypeNameStyle.Name)))));
if (propertyInfo != (PropertyInfo)null) {
Type[] genericTypeArguments = propertyInfo.PropertyType.GetGenericTypeArguments();
Type type2 = (genericTypeArguments.Length == 2) ? genericTypeArguments[1] : typeof(object);
schema.AdditionalPropertiesSchema = await this.GenerateWithReferenceAndNullabilityAsync<JsonSchema4>(type2, (IEnumerable<Attribute>)null, schemaResolver, (Func<JsonSchema4, JsonSchema4, Task>)null).ConfigureAwait(false);
} else
schema.AllowAdditionalProperties = false;
}
private unsafe async Task ApplySchemaProcessorsAsync(Type type, JsonSchema4 schema, JsonSchemaResolver schemaResolver)
{
SchemaProcessorContext context = new SchemaProcessorContext(type, schema, schemaResolver, this, Settings);
foreach (ISchemaProcessor schemaProcessor in Settings.SchemaProcessors) {
await schemaProcessor.ProcessAsync(context).ConfigureAwait(false);
}
IEnumerable<Attribute> enumerable = from a in type.GetTypeInfo().GetCustomAttributes()
where a.GetType().IsAssignableTo("JsonSchemaProcessorAttribute", TypeNameStyle.Name)
select a;
foreach (dynamic item in enumerable) {
dynamic val = Activator.CreateInstance(item.Type, item.Parameters).ProcessAsync(context).ConfigureAwait(false)
.GetAwaiter();
if (!((byte)val.IsCompleted != 0)) {
ICriticalNotifyCompletion awaiter = val as ICriticalNotifyCompletion;
AsyncTaskMethodBuilder asyncTaskMethodBuilder;
if (awaiter == null) {
INotifyCompletion awaiter2 = (INotifyCompletion)val;
asyncTaskMethodBuilder.AwaitOnCompleted(ref awaiter2, ref *(<ApplySchemaProcessorsAsync>d__17*));
awaiter2 = null;
} else
asyncTaskMethodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref *(<ApplySchemaProcessorsAsync>d__17*));
awaiter = null;
;
}
val.GetResult();
}
}
private void ApplyExtensionDataAttributes<TSchemaType>(Type type, TSchemaType schema, IEnumerable<Attribute> parentAttributes) where TSchemaType : JsonSchema4, new
{
if (parentAttributes == null) {
JsonSchemaExtensionDataAttribute[] source = type.GetTypeInfo().GetCustomAttributes<JsonSchemaExtensionDataAttribute>().ToArray();
if (source.Any())
schema.ExtensionData = source.ToDictionary((JsonSchemaExtensionDataAttribute a) => a.Key, (JsonSchemaExtensionDataAttribute a) => a.Value);
} else {
JsonSchemaExtensionDataAttribute[] source2 = parentAttributes.OfType<JsonSchemaExtensionDataAttribute>().ToArray();
if (source2.Any())
schema.ExtensionData = source2.ToDictionary((JsonSchemaExtensionDataAttribute a) => a.Key, (JsonSchemaExtensionDataAttribute a) => a.Value);
}
}
private async Task<bool> TryHandleSpecialTypesAsync<TSchemaType>(Type type, TSchemaType schema, JsonSchemaResolver schemaResolver, IEnumerable<Attribute> parentAttributes) where TSchemaType : JsonSchema4, new
{
ITypeMapper typeMapper = Enumerable.FirstOrDefault<ITypeMapper>((IEnumerable<ITypeMapper>)Settings.TypeMappers, (Func<ITypeMapper, bool>)((ITypeMapper m) => m.MappedType == type));
if (typeMapper == null && type.GetTypeInfo().IsGenericType) {
Type genericType = type.GetGenericTypeDefinition();
typeMapper = Enumerable.FirstOrDefault<ITypeMapper>((IEnumerable<ITypeMapper>)Settings.TypeMappers, (Func<ITypeMapper, bool>)((ITypeMapper m) => m.MappedType == genericType));
}
if (typeMapper != null) {
TypeMapperContext context = new TypeMapperContext(type, this, schemaResolver, parentAttributes);
await typeMapper.GenerateSchemaAsync(schema, context).ConfigureAwait(false);
return true;
}
if (!type.IsAssignableTo("JArray", TypeNameStyle.Name) && (type.IsAssignableTo("JToken", TypeNameStyle.Name) || type == typeof(object)))
return true;
return false;
}
private async Task GenerateArray<TSchemaType>(TSchemaType schema, Type type, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
typeDescription.ApplyType(schema);
Type itemType = type.GetEnumerableItemType();
if (itemType != (Type)null) {
<>c__DisplayClass20_0<TSchemaType> <>4__this;
schema.Item = await this.GenerateWithReferenceAndNullabilityAsync<JsonSchema4>(itemType, (IEnumerable<Attribute>)null, false, schemaResolver, (Func<JsonSchema4, JsonSchema4, Task>)delegate(JsonSchema4 s, JsonSchema4 r) {
<>c__DisplayClass20_0<TSchemaType>.<<GenerateArray>b__0>d stateMachine = default(<>c__DisplayClass20_0<TSchemaType>.<<GenerateArray>b__0>d);
stateMachine.<>4__this = <>4__this;
stateMachine.s = s;
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start<<>c__DisplayClass20_0<TSchemaType>.<<GenerateArray>b__0>d>(ref stateMachine);
return stateMachine.<>t__builder.Task;
}).ConfigureAwait(false);
if (Settings.GenerateXmlObjects)
schema.GenerateXmlObjectForArrayType(type);
} else
schema.Item = JsonSchema4.CreateAnySchema();
}
private async Task GenerateEnum<TSchemaType>(TSchemaType schema, Type type, IEnumerable<Attribute> parentAttributes, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
if (type.Name == "Nullable`1")
type = type.GenericTypeArguments[0];
bool isIntegerEnumeration = typeDescription.Type == JsonObjectType.Integer;
if (schemaResolver.HasSchema(type, isIntegerEnumeration))
((JsonReferenceBase<JsonSchema4>)schema).Reference = schemaResolver.GetSchema(type, isIntegerEnumeration);
else if (schema.GetType() == typeof(JsonSchema4)) {
LoadEnumerations(type, schema, typeDescription);
typeDescription.ApplyType(schema);
schema.Description = await type.GetXmlSummaryAsync().ConfigureAwait(false);
schemaResolver.AddSchema(type, isIntegerEnumeration, schema);
} else {
((JsonReferenceBase<JsonSchema4>)schema).Reference = await GenerateAsync(type, parentAttributes, schemaResolver).ConfigureAwait(false);
}
}
private async Task GenerateDictionaryAsync<TSchemaType>(TSchemaType schema, Type type, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
Type[] genericTypeArguments = type.GetGenericTypeArguments();
Type keyType = (genericTypeArguments.Length == 2) ? genericTypeArguments[0] : typeof(string);
if (keyType.GetTypeInfo().IsEnum) {
JsonSchema4 jsonSchema = await GenerateAsync(keyType, schemaResolver).ConfigureAwait(false);
if (Settings.ReflectionService.GetDescription(keyType, null, Settings).RequiresSchemaReference(Settings.TypeMappers))
schema.DictionaryKey = new JsonSchema4 {
Reference = jsonSchema
};
else
schema.DictionaryKey = jsonSchema;
}
Type valueType = (genericTypeArguments.Length == 2) ? genericTypeArguments[1] : typeof(object);
if (valueType == typeof(object))
schema.AdditionalPropertiesSchema = JsonSchema4.CreateAnySchema();
else {
JsonSchema4 jsonSchema2 = await GenerateAsync(valueType, schemaResolver).ConfigureAwait(false);
if (Settings.ReflectionService.GetDescription(valueType, null, Settings).RequiresSchemaReference(Settings.TypeMappers))
schema.AdditionalPropertiesSchema = new JsonSchema4 {
Reference = jsonSchema2
};
else
schema.AdditionalPropertiesSchema = jsonSchema2;
}
schema.AllowAdditionalProperties = true;
}
private async Task GeneratePropertiesAsync(Type type, JsonSchema4 schema, JsonSchemaResolver schemaResolver)
{
List<MemberInfo> propertiesAndFields = type.GetTypeInfo().DeclaredFields.Where(delegate(FieldInfo f) {
if (f.IsPublic)
return !f.IsStatic;
return false;
}).OfType<MemberInfo>().Concat(type.GetTypeInfo().DeclaredProperties.Where(delegate(PropertyInfo p) {
if (p.GetMethod?.IsPublic ?? false) {
MethodInfo getMethod2 = p.GetMethod;
if ((object)getMethod2 != null && !getMethod2.IsStatic)
return true;
}
if (p.SetMethod?.IsPublic ?? false) {
MethodInfo setMethod2 = p.SetMethod;
if ((object)setMethod2 == null)
return false;
return !setMethod2.IsStatic;
}
return false;
}))
.ToList();
JsonContract jsonContract = Settings.ResolveContract(type);
string[] allowedProperties = GetTypeProperties(type);
JsonObjectContract jsonObjectContract = jsonContract as JsonObjectContract;
if (jsonObjectContract != null && allowedProperties == null) {
foreach (Newtonsoft.Json.Serialization.JsonProperty item in from p in jsonObjectContract.Properties
where p.DeclaringType == type
select p) {
bool flag;
try {
flag = (item.ShouldSerialize?.Invoke(null) ?? true);
} catch {
flag = true;
}
if (flag) {
MemberInfo memberInfo = propertiesAndFields.FirstOrDefault((MemberInfo p) => p.Name == item.UnderlyingName);
PropertyInfo propertyInfo = memberInfo as PropertyInfo;
if (!Settings.GenerateAbstractProperties && !(propertyInfo == (PropertyInfo)null)) {
MethodInfo getMethod = propertyInfo.GetMethod;
if ((object)getMethod != null && getMethod.IsAbstract)
continue;
MethodInfo setMethod = propertyInfo.SetMethod;
if ((object)setMethod != null && setMethod.IsAbstract)
continue;
}
await LoadPropertyOrFieldAsync(item, memberInfo, type, schema, schemaResolver).ConfigureAwait(false);
}
}
} else {
foreach (MemberInfo item2 in propertiesAndFields.Where(delegate(MemberInfo m) {
if (allowedProperties != null)
return allowedProperties.Contains(m.Name);
return true;
})) {
JsonPropertyAttribute jsonPropertyAttribute = item2.GetCustomAttributes(true).OfType<JsonPropertyAttribute>().SingleOrDefault();
Type propertyType = (item2 as PropertyInfo)?.PropertyType ?? ((FieldInfo)item2).FieldType;
Newtonsoft.Json.Serialization.JsonProperty obj2 = new Newtonsoft.Json.Serialization.JsonProperty {
AttributeProvider = new ReflectionAttributeProvider(item2),
PropertyType = propertyType,
Ignored = IsPropertyIgnored(propertyType, type, item2.GetCustomAttributes(true).OfType<Attribute>().ToArray())
};
if (jsonPropertyAttribute != null) {
obj2.PropertyName = (jsonPropertyAttribute.PropertyName ?? item2.Name);
obj2.Required = jsonPropertyAttribute.Required;
obj2.DefaultValueHandling = jsonPropertyAttribute.DefaultValueHandling;
obj2.TypeNameHandling = jsonPropertyAttribute.TypeNameHandling;
obj2.NullValueHandling = jsonPropertyAttribute.NullValueHandling;
obj2.TypeNameHandling = jsonPropertyAttribute.TypeNameHandling;
} else
obj2.PropertyName = item2.Name;
await LoadPropertyOrFieldAsync(obj2, item2, type, schema, schemaResolver).ConfigureAwait(false);
}
}
}
protected virtual string[] GetTypeProperties(Type type)
{
if (type == typeof(Exception))
return new string[4] {
"InnerException",
"Message",
"Source",
"StackTrace"
};
return null;
}
private unsafe async Task GenerateKnownTypesAsync(Type type, JsonSchemaResolver schemaResolver)
{
object[] attributes = type.GetTypeInfo().GetCustomAttributes(Settings.GetActualFlattenInheritanceHierarchy(type));
if (Settings.GenerateKnownTypes) {
IEnumerable<Attribute> enumerable = (from a in attributes
where a.GetType().IsAssignableTo("KnownTypeAttribute", TypeNameStyle.Name)
select a).OfType<Attribute>();
foreach (dynamic item in enumerable) {
if (item.Type != null) {
dynamic val = this.AddKnownTypeAsync(item.Type, schemaResolver).ConfigureAwait(false).GetAwaiter();
if (!((byte)val.IsCompleted != 0)) {
ICriticalNotifyCompletion awaiter = val as ICriticalNotifyCompletion;
AsyncTaskMethodBuilder asyncTaskMethodBuilder;
if (awaiter == null) {
INotifyCompletion awaiter2 = (INotifyCompletion)val;
asyncTaskMethodBuilder.AwaitOnCompleted(ref awaiter2, ref *(<GenerateKnownTypesAsync>d__25*));
awaiter2 = null;
} else
asyncTaskMethodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref *(<GenerateKnownTypesAsync>d__25*));
awaiter = null;
;
}
val.GetResult();
} else {
if (!((item.MethodName != null) ? true : false))
throw new ArgumentException("A KnownType attribute on " + type.FullName + " does not specify a type or a method name.", "type");
MethodInfo runtimeMethod = type.GetRuntimeMethod((string)item.MethodName, new Type[0]);
if (runtimeMethod != (MethodInfo)null) {
IEnumerable<Type> enumerable2 = runtimeMethod.Invoke(null, null) as IEnumerable<Type>;
if (enumerable2 != null) {
foreach (Type item2 in enumerable2) {
await AddKnownTypeAsync(item2, schemaResolver).ConfigureAwait(false);
}
}
}
}
}
}
foreach (object item3 in from a in attributes
where a.GetType().IsAssignableTo("JsonInheritanceAttribute", TypeNameStyle.Name)
select a) {
Type type2 = item3.TryGetPropertyValue<Type>("Type", null);
if (type2 != (Type)null)
await AddKnownTypeAsync(type2, schemaResolver).ConfigureAwait(false);
}
}
private async Task AddKnownTypeAsync(Type type, JsonSchemaResolver schemaResolver)
{
bool isIntegerEnumeration = Settings.ReflectionService.GetDescription(type, null, Settings).Type == JsonObjectType.Integer;
if (!schemaResolver.HasSchema(type, isIntegerEnumeration))
await GenerateAsync(type, schemaResolver).ConfigureAwait(false);
}
private async Task<JsonSchema4> GenerateInheritanceAsync(Type type, JsonSchema4 schema, JsonSchemaResolver schemaResolver)
{
Type baseType = type.GetTypeInfo().BaseType;
if (baseType != (Type)null && baseType != typeof(object) && baseType != typeof(ValueType) && baseType.GetTypeInfo().GetCustomAttributes(false).TryGetIfAssignableTo("JsonSchemaIgnoreAttribute", TypeNameStyle.Name) == null && baseType.GetTypeInfo().GetCustomAttributes(false).TryGetIfAssignableTo("SwaggerIgnoreAttribute", TypeNameStyle.Name) == null) {
string[] excludedTypeNames = Settings.ExcludedTypeNames;
if (excludedTypeNames == null || !excludedTypeNames.Contains(baseType.FullName)) {
if (!Settings.GetActualFlattenInheritanceHierarchy(type)) {
JsonSchema4 actualSchema = new JsonSchema4();
await GeneratePropertiesAsync(type, actualSchema, schemaResolver).ConfigureAwait(false);
await ApplyAdditionalPropertiesAsync(type, actualSchema, schemaResolver).ConfigureAwait(false);
bool requiresSchemaReference = Settings.ReflectionService.GetDescription(baseType, null, Settings).RequiresSchemaReference(Settings.TypeMappers);
if (actualSchema.Properties.Any() | requiresSchemaReference) {
JsonSchema4 jsonSchema = await GenerateAsync(baseType, schemaResolver).ConfigureAwait(false);
if (requiresSchemaReference) {
if (schemaResolver.RootObject != jsonSchema.ActualSchema)
schemaResolver.AppendSchema(jsonSchema.ActualSchema, Settings.SchemaNameGenerator.Generate(baseType));
schema.AllOf.Add(new JsonSchema4 {
Reference = jsonSchema.ActualSchema
});
} else
schema.AllOf.Add(jsonSchema);
schema.AllOf.Add(actualSchema);
return actualSchema;
}
await GenerateAsync(baseType, null, schema, schemaResolver).ConfigureAwait(false);
return schema;
}
if (!Settings.ReflectionService.GetDescription(baseType, null, Settings).IsDictionary && !type.IsArray) {
await GeneratePropertiesAsync(baseType, schema, schemaResolver).ConfigureAwait(false);
GenerateInheritanceDiscriminator(baseType, schema, (await GenerateInheritanceAsync(baseType, schema, schemaResolver).ConfigureAwait(false)) ?? schema);
}
}
}
if (Settings.GetActualFlattenInheritanceHierarchy(type) && Settings.GenerateAbstractProperties) {
foreach (Type implementedInterface in type.GetTypeInfo().ImplementedInterfaces) {
if (!Settings.ReflectionService.GetDescription(implementedInterface, null, Settings).IsDictionary && !type.IsArray && !IntrospectionExtensions.GetTypeInfo(typeof(IEnumerable)).IsAssignableFrom(implementedInterface.GetTypeInfo())) {
await GeneratePropertiesAsync(implementedInterface, schema, schemaResolver).ConfigureAwait(false);
GenerateInheritanceDiscriminator(implementedInterface, schema, (await GenerateInheritanceAsync(implementedInterface, schema, schemaResolver).ConfigureAwait(false)) ?? schema);
}
}
}
return null;
}
private void GenerateInheritanceDiscriminator(Type type, JsonSchema4 schema, JsonSchema4 typeSchema)
{
if (!Settings.GetActualFlattenInheritanceHierarchy(type)) {
object obj = TryGetInheritanceDiscriminatorConverter(type);
if (obj != null) {
string text = TryGetInheritanceDiscriminatorName(obj);
if (typeSchema.Properties.TryGetValue(text, out JsonProperty value) && (value.Type & JsonObjectType.String) == JsonObjectType.None)
throw new InvalidOperationException("The JSON discriminator property '" + text + "' must be a string property on type '" + type.FullName + "' (it is recommended to not implement the discriminator property at all).");
OpenApiDiscriminator openApiDiscriminator2 = typeSchema.DiscriminatorObject = new OpenApiDiscriminator {
JsonInheritanceConverter = obj,
PropertyName = text
};
typeSchema.Properties[text] = new JsonProperty {
Type = JsonObjectType.String,
IsRequired = true
};
} else
(schema.ResponsibleDiscriminatorObject ?? schema.ActualTypeSchema.ResponsibleDiscriminatorObject)?.AddMapping(type, schema);
}
}
private object TryGetInheritanceDiscriminatorConverter(Type type)
{
dynamic val = type.GetTypeInfo().GetCustomAttributes(false).OfType<Attribute>()
.TryGetIfAssignableTo("JsonConverterAttribute", TypeNameStyle.Name);
if ((val != null) && ((Type)val.ConverterType).IsAssignableTo("JsonInheritanceConverter", TypeNameStyle.Name)) {
dynamic val2 = val.ConverterParameters != null;
if (!(((val2 ? false : true) ? val2 : (val2 & (val.ConverterParameters.Length > 0))) ? true : false))
return Activator.CreateInstance(val.ConverterType);
return Activator.CreateInstance(val.ConverterType, val.ConverterParameters);
}
return null;
}
private string TryGetInheritanceDiscriminatorName(dynamic jsonInheritanceConverter)
{
if (ReflectionExtensions.HasProperty(jsonInheritanceConverter, "DiscriminatorName"))
return (string)jsonInheritanceConverter.DiscriminatorName;
return JsonInheritanceConverter.DefaultDiscriminatorName;
}
private void LoadEnumerations(Type type, JsonSchema4 schema, JsonTypeDescription typeDescription)
{
schema.Type = typeDescription.Type;
schema.Enumeration.Clear();
schema.EnumerationNames.Clear();
schema.IsFlagEnumerable = (type.GetTypeInfo().GetCustomAttribute<FlagsAttribute>() != null);
Type underlyingType = Enum.GetUnderlyingType(type);
List<JsonConverter> list = Settings.ActualSerializerSettings.Converters.ToList();
if (!list.OfType<StringEnumConverter>().Any())
list.Add(new StringEnumConverter());
string[] names = Enum.GetNames(type);
foreach (string text in names) {
if (typeDescription.Type == JsonObjectType.Integer) {
object item = Convert.ChangeType(Enum.Parse(type, text), underlyingType);
schema.Enumeration.Add(item);
} else {
dynamic val = type.GetTypeInfo().GetDeclaredField(text).GetCustomAttributes()
.TryGetIfAssignableTo("System.Runtime.Serialization.EnumMemberAttribute", TypeNameStyle.FullName);
dynamic val2 = val != null;
if ((val2 ? false : true) ? val2 : (val2 & !string.IsNullOrEmpty(val.Value)))
schema.Enumeration.Add((string)val.Value);
else {
string value = JsonConvert.SerializeObject(Enum.Parse(type, text), Formatting.None, list.ToArray());
schema.Enumeration.Add(JsonConvert.DeserializeObject<string>(value));
}
}
schema.EnumerationNames.Add(text);
}
}
private async Task LoadPropertyOrFieldAsync(Newtonsoft.Json.Serialization.JsonProperty property, MemberInfo propertyInfo, Type parentType, JsonSchema4 parentSchema, JsonSchemaResolver schemaResolver)
{
Type propertyType = property.PropertyType;
Attribute[] propertyAttributes = property.AttributeProvider.GetAttributes(true).ToArray();
JsonTypeDescription propertyTypeDescription = Settings.ReflectionService.GetDescription(propertyType, propertyAttributes, Settings);
if (!property.Ignored && !IsPropertyIgnoredBySettings(propertyType, parentType, propertyAttributes)) {
if (propertyType.Name == "Nullable`1")
propertyType = propertyType.GenericTypeArguments[0];
string propertyName = GetPropertyName(property, propertyInfo);
if (parentSchema.Properties.ContainsKey(propertyName))
throw new InvalidOperationException("The JSON property '" + propertyName + "' is defined multiple times on type '" + parentType.FullName + "'.");
Attribute requiredAttribute = propertyAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.RequiredAttribute", TypeNameStyle.FullName);
bool flag = property.Required == Required.Always || property.Required == Required.AllowNull;
dynamic val = GetDataMemberAttribute(parentType, propertyAttributes)?.IsRequired == true;
bool hasRequiredAttribute = requiredAttribute != null;
dynamic val2 = hasRequiredAttribute ? ((object)hasRequiredAttribute) : (hasRequiredAttribute | val);
if ((val2) || ((val2 | flag) ? true : false))
parentSchema.RequiredProperties.Add(propertyName);
bool isNullable = propertyTypeDescription.IsNullable && !hasRequiredAttribute && !((byte)val != 0) && (property.Required == Required.Default || property.Required == Required.AllowNull);
JsonProperty value = await GenerateWithReferenceAndNullabilityAsync(propertyType, propertyAttributes, isNullable, schemaResolver, async delegate(JsonProperty p, JsonSchema4 s) {
if (Settings.GenerateXmlObjects)
p.GenerateXmlObjectForProperty(propertyType, propertyName, propertyAttributes);
if (hasRequiredAttribute && propertyTypeDescription.Type == JsonObjectType.String && !requiredAttribute.TryGetPropertyValue("AllowEmptyStrings", false))
p.MinLength = 1;
if (!isNullable && Settings.SchemaType == SchemaType.Swagger2 && !parentSchema.RequiredProperties.Contains(propertyName))
parentSchema.RequiredProperties.Add(propertyName);
object obj = propertyAttributes.TryGetIfAssignableTo("System.ComponentModel.ReadOnlyAttribute", TypeNameStyle.FullName);
if ((dynamic)obj != null)
p.IsReadOnly = ((byte)((dynamic)obj).IsReadOnly != 0);
if (p.Description == null)
p.Description = await propertyInfo.GetDescriptionAsync(propertyAttributes).ConfigureAwait(false);
p.Default = ConvertDefaultValue(property);
ApplyDataAnnotations(p, propertyTypeDescription, propertyAttributes);
}).ConfigureAwait(false);
parentSchema.Properties.Add(propertyName, value);
}
}
private bool IsPropertyIgnored(Type propertyType, Type parentType, Attribute[] propertyAttributes)
{
if (propertyAttributes.Any((Attribute a) => a is JsonIgnoreAttribute))
return true;
bool flag = HasDataContractAttribute(parentType);
dynamic val = (!flag) ? ((object)flag) : (flag & (GetDataMemberAttribute(parentType, propertyAttributes) == null));
if ((val ? false : true) ? val : (val & !propertyAttributes.Any((Attribute a) => a is JsonPropertyAttribute)))
return true;
return IsPropertyIgnoredBySettings(propertyType, parentType, propertyAttributes);
}
private bool IsPropertyIgnoredBySettings(Type propertyType, Type parentType, Attribute[] propertyAttributes)
{
if (Settings.IgnoreObsoleteProperties && propertyAttributes.Any((Attribute a) => a is ObsoleteAttribute))
return true;
return false;
}
private static dynamic GetDataMemberAttribute(Type parentType, Attribute[] propertyAttributes)
{
if (!HasDataContractAttribute(parentType))
return null;
return propertyAttributes.TryGetIfAssignableTo("DataMemberAttribute", TypeNameStyle.Name);
}
private static bool HasDataContractAttribute(Type parentType)
{
return parentType.GetTypeInfo().GetCustomAttributes().TryGetIfAssignableTo("DataContractAttribute", TypeNameStyle.Name) != null;
}
public virtual void ApplyDataAnnotations(JsonSchema4 schema, JsonTypeDescription typeDescription, IEnumerable<Attribute> parentAttributes)
{
dynamic val = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.DisplayAttribute", TypeNameStyle.FullName);
dynamic val2 = val != null;
if ((val2 ? false : true) ? val2 : (val2 & (val.Name != null)))
schema.Title = (string)val.Name;
dynamic val3 = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DefaultValueAttribute", TypeNameStyle.FullName);
if (val3 != null) {
if (typeDescription.IsEnum && typeDescription.Type.HasFlag(JsonObjectType.String))
schema.Default = (object)val3.Value?.ToString();
else
schema.Default = (object)val3.Value;
}
dynamic val4 = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.RegularExpressionAttribute", TypeNameStyle.FullName);
if (val4 != null) {
if (typeDescription.IsDictionary)
schema.AdditionalPropertiesSchema.Pattern = (string)val4.Pattern;
else
schema.Pattern = (string)val4.Pattern;
}
if (typeDescription.Type == JsonObjectType.Number || typeDescription.Type == JsonObjectType.Integer) {
ApplyRangeAttribute(schema, parentAttributes);
MultipleOfAttribute multipleOfAttribute = parentAttributes.OfType<MultipleOfAttribute>().SingleOrDefault();
if (multipleOfAttribute != null)
schema.MultipleOf = multipleOfAttribute.MultipleOf;
}
dynamic val5 = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.MinLengthAttribute", TypeNameStyle.FullName);
val2 = (val5 != null);
if ((val2 ? false : true) ? val2 : (val2 & (val5.Length != null))) {
if (typeDescription.Type == JsonObjectType.String)
schema.MinLength = (int?)val5.Length;
else if (typeDescription.Type == JsonObjectType.Array) {
schema.MinItems = (int)val5.Length;
}
}
dynamic val6 = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.MaxLengthAttribute", TypeNameStyle.FullName);
val2 = (val6 != null);
if ((val2 ? false : true) ? val2 : (val2 & (val6.Length != null))) {
if (typeDescription.Type == JsonObjectType.String)
schema.MaxLength = (int?)val6.Length;
else if (typeDescription.Type == JsonObjectType.Array) {
schema.MaxItems = (int)val6.Length;
}
}
dynamic val7 = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.StringLengthAttribute", TypeNameStyle.FullName);
if ((val7 != null) && typeDescription.Type == JsonObjectType.String) {
schema.MinLength = (int?)val7.MinimumLength;
schema.MaxLength = (int?)val7.MaximumLength;
}
dynamic val8 = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.DataTypeAttribute", TypeNameStyle.FullName);
if (val8 != null) {
dynamic val9 = val8.DataType.ToString();
if (DataTypeFormats.ContainsKey(val9))
schema.Format = (string)DataTypeFormats[val9];
}
}
private void ApplyRangeAttribute(JsonSchema4 schema, IEnumerable<Attribute> parentAttributes)
{
dynamic val = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.RangeAttribute", TypeNameStyle.FullName);
if (val != null) {
if (val.Minimum != null) {
if (val.OperandType == typeof(double)) {
double num = (double)Convert.ChangeType(val.Minimum, typeof(double));
if (num > -1.7976931348623157E+308)
schema.Minimum = (decimal)num;
} else {
decimal num2 = (decimal)Convert.ChangeType(val.Minimum, typeof(decimal));
if (num2 > decimal.MinValue)
schema.Minimum = num2;
}
}
if (val.Maximum != null) {
if (val.OperandType == typeof(double)) {
double num3 = (double)Convert.ChangeType(val.Maximum, typeof(double));
if (num3 < 1.7976931348623157E+308)
schema.Maximum = (decimal)num3;
} else {
decimal num4 = (decimal)Convert.ChangeType(val.Maximum, typeof(decimal));
if (num4 < decimal.MaxValue)
schema.Maximum = num4;
}
}
}
}
private object ConvertDefaultValue(Newtonsoft.Json.Serialization.JsonProperty property)
{
if (property.DefaultValue != null && property.DefaultValue.GetType().GetTypeInfo().IsEnum) {
TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(typeof(StringEnumConverter));
JsonConverter converter = property.Converter;
if (typeInfo.IsAssignableFrom((converter != null) ? converter.GetType().GetTypeInfo() : null))
return property.DefaultValue.ToString();
return (int)property.DefaultValue;
}
return property.DefaultValue;
}
}
}