<PackageReference Include="NJsonSchema" Version="10.1.21" />

JsonSchemaGenerator

public class JsonSchemaGenerator
Generates a JsonSchema object for a given type.
using Namotion.Reflection; 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; 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 JsonSchema Generate(Type type) { JsonSchema jsonSchema = new JsonSchema(); JsonSchemaResolver schemaResolver = new JsonSchemaResolver(jsonSchema, Settings); Generate(jsonSchema, ContextualTypeExtensions.ToContextualType(type), schemaResolver); return jsonSchema; } public JsonSchema Generate(Type type, JsonSchemaResolver schemaResolver) { return Generate<JsonSchema>(type, schemaResolver); } public TSchemaType Generate<TSchemaType>(Type type, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new { return Generate<TSchemaType>(ContextualTypeExtensions.ToContextualType(type), schemaResolver); } public JsonSchema Generate(ContextualType contextualType, JsonSchemaResolver schemaResolver) { return Generate<JsonSchema>(contextualType, schemaResolver); } public TSchemaType Generate<TSchemaType>(ContextualType contextualType, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new { TSchemaType val = new TSchemaType(); Generate(val, contextualType, schemaResolver); return val; } public void Generate<TSchemaType>(TSchemaType schema, Type type, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new { Generate(schema, ContextualTypeExtensions.ToContextualType(type), schemaResolver); } public virtual void Generate<TSchemaType>(TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new { JsonTypeDescription description = Settings.ReflectionService.GetDescription(contextualType, Settings); ApplyTypeExtensionDataAttributes(schema, contextualType); if (TryHandleSpecialTypes(schema, description.ContextualType, schemaResolver)) ApplySchemaProcessors(schema, description.ContextualType, schemaResolver); else { if (schemaResolver.RootObject == schema) schema.Title = Settings.SchemaNameGenerator.Generate(description.ContextualType.get_OriginalType()); if (description.Type.HasFlag(JsonObjectType.Object)) { if (description.IsDictionary) GenerateDictionary(schema, description, schemaResolver); else if (schemaResolver.HasSchema(description.ContextualType.get_OriginalType(), false)) { ((JsonReferenceBase<JsonSchema>)schema).Reference = schemaResolver.GetSchema(description.ContextualType.get_OriginalType(), false); } else if (schema.GetType() == typeof(JsonSchema)) { GenerateObject(schema, description, schemaResolver); } else { ((JsonReferenceBase<JsonSchema>)schema).Reference = Generate(description.ContextualType, schemaResolver); } } else if (description.IsEnum) { GenerateEnum(schema, description, schemaResolver); } else if (description.Type.HasFlag(JsonObjectType.Array)) { GenerateArray(schema, description, schemaResolver); } else { description.ApplyType(schema); } if ((object)contextualType != (object)description.ContextualType) ApplySchemaProcessors(schema, description.ContextualType, schemaResolver); ApplySchemaProcessors(schema, contextualType, schemaResolver); } } public TSchemaType GenerateWithReference<TSchemaType>(ContextualType contextualType, JsonSchemaResolver schemaResolver, Action<TSchemaType, JsonSchema> transformation = null) where TSchemaType : JsonSchema, new { return GenerateWithReferenceAndNullability(contextualType, false, schemaResolver, transformation); } public TSchemaType GenerateWithReferenceAndNullability<TSchemaType>(ContextualType contextualType, JsonSchemaResolver schemaResolver, Action<TSchemaType, JsonSchema> transformation = null) where TSchemaType : JsonSchema, new { JsonTypeDescription description = Settings.ReflectionService.GetDescription(contextualType, Settings); return GenerateWithReferenceAndNullability(contextualType, description.IsNullable, schemaResolver, transformation); } public virtual TSchemaType GenerateWithReferenceAndNullability<TSchemaType>(ContextualType contextualType, bool isNullable, JsonSchemaResolver schemaResolver, Action<TSchemaType, JsonSchema> transformation = null) where TSchemaType : JsonSchema, new { JsonTypeDescription description = Settings.ReflectionService.GetDescription(contextualType, Settings); JsonSchema jsonSchema; if (!description.RequiresSchemaReference(Settings.TypeMappers)) { TSchemaType val = Generate<TSchemaType>(description.ContextualType, schemaResolver); if (!val.HasReference) { transformation?.Invoke(val, (JsonSchema)val); if (isNullable) { if (Settings.SchemaType == SchemaType.JsonSchema) { if (val.Type == JsonObjectType.None) { val.OneOf.Add(new JsonSchema { Type = JsonObjectType.None }); val.OneOf.Add(new JsonSchema { Type = JsonObjectType.Null }); } else val.Type |= JsonObjectType.Null; } else if (Settings.SchemaType == SchemaType.OpenApi3 || Settings.GenerateCustomNullableProperties) { val.IsNullableRaw = isNullable; } } return val; } jsonSchema = val.ActualSchema; } else jsonSchema = Generate<JsonSchema>(description.ContextualType, schemaResolver); TSchemaType val2 = new TSchemaType(); transformation?.Invoke(val2, jsonSchema); if (isNullable) { if (Settings.SchemaType == SchemaType.JsonSchema) val2.OneOf.Add(new JsonSchema { Type = JsonObjectType.Null }); else if (Settings.SchemaType == SchemaType.OpenApi3 || Settings.GenerateCustomNullableProperties) { val2.IsNullableRaw = true; } } if ((Settings.AllowReferencesWithProperties || !JsonConvert.DeserializeObject<JObject>(JsonConvert.SerializeObject(val2)).Properties().Any()) && val2.OneOf.Count == 0) ((JsonReferenceBase<JsonSchema>)val2).Reference = jsonSchema.ActualSchema; else if (Settings.SchemaType != SchemaType.Swagger2) { val2.OneOf.Add(new JsonSchema { Reference = jsonSchema.ActualSchema }); } else { val2.AllOf.Add(new JsonSchema { Reference = jsonSchema.ActualSchema }); } return val2; } public virtual string GetPropertyName(JsonProperty jsonProperty, ContextualMemberInfo contextualMember) { if (jsonProperty == null || jsonProperty.PropertyName == null) try { string name = ContextualTypeExtensions.GetContextualPropertiesAndFields(contextualMember.get_MemberInfo().DeclaringType).First((ContextualMemberInfo p) => p.get_Name() == contextualMember.get_Name()).GetName(); DefaultContractResolver defaultContractResolver = Settings.ActualContractResolver as DefaultContractResolver; return (defaultContractResolver != null) ? defaultContractResolver.GetResolvedPropertyName(name) : name; } catch (Exception innerException) { string[] obj = new string[5] { "Could not get JSON property name of property '", (contextualMember != null) ? contextualMember.get_Name() : "n/a", "' and type '", null, null }; ContextualMemberInfo obj2 = contextualMember; obj[3] = ((((obj2 == null) ? null : obj2.get_MemberInfo()?.DeclaringType) != (Type)null) ? contextualMember.get_MemberInfo().DeclaringType.FullName : "n/a"); obj[4] = "'."; throw new InvalidOperationException(string.Concat(obj), innerException); } return jsonProperty.PropertyName; } public virtual void ApplyDataAnnotations(JsonSchema schema, JsonTypeDescription typeDescription) { ContextualType contextualType = typeDescription.ContextualType; dynamic val = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)contextualType.get_ContextAttributes(), "System.ComponentModel.DataAnnotations.DisplayAttribute", 1); dynamic val2 = val != null; if ((val2 ? false : true) ? val2 : (val2 & (val.Name != null))) schema.Title = (string)val.Name; dynamic val3 = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)contextualType.get_ContextAttributes(), "System.ComponentModel.DefaultValueAttribute", 1); 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 = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)contextualType.get_ContextAttributes(), "System.ComponentModel.DataAnnotations.RegularExpressionAttribute", 1); 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, contextualType.get_ContextAttributes()); MultipleOfAttribute multipleOfAttribute = contextualType.get_ContextAttributes().OfType<MultipleOfAttribute>().SingleOrDefault(); if (multipleOfAttribute != null) schema.MultipleOf = multipleOfAttribute.MultipleOf; } dynamic val5 = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)contextualType.get_ContextAttributes(), "System.ComponentModel.DataAnnotations.MinLengthAttribute", 1); 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 = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)contextualType.get_ContextAttributes(), "System.ComponentModel.DataAnnotations.MaxLengthAttribute", 1); 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 = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)contextualType.get_ContextAttributes(), "System.ComponentModel.DataAnnotations.StringLengthAttribute", 1); if ((val7 != null) && typeDescription.Type == JsonObjectType.String) { schema.MinLength = (int?)val7.MinimumLength; schema.MaxLength = (int?)val7.MaximumLength; } dynamic val8 = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)contextualType.get_ContextAttributes(), "System.ComponentModel.DataAnnotations.DataTypeAttribute", 1); if (val8 != null) { dynamic val9 = val8.DataType.ToString(); if (DataTypeFormats.ContainsKey(val9)) schema.Format = (string)DataTypeFormats[val9]; } } public virtual object ConvertDefaultValue(ContextualType type, object defaultValue) { if (defaultValue != null && defaultValue.GetType().GetTypeInfo().IsEnum) { if (Settings.ReflectionService.IsStringEnum(type, Settings.ActualSerializerSettings)) return defaultValue.ToString(); return (int)defaultValue; } return defaultValue; } public virtual object GenerateExample(ContextualType type) { if (Settings.GenerateExamples) try { ContextualMemberInfo val = type as ContextualMemberInfo; string value = (val != null) ? XmlDocsExtensions.GetXmlDocsTag(val, "example") : XmlDocsExtensions.GetXmlDocsTag(type, "example"); return (!string.IsNullOrEmpty(value)) ? JsonConvert.DeserializeObject<JToken>(value) : null; } catch { return null; } return null; } protected virtual void GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver) { Type type = typeDescription.ContextualType.get_Type(); schemaResolver.AddSchema(type, false, schema); JsonSchema schema2 = schema; JsonSchema jsonSchema = GenerateInheritance(type, schema, schemaResolver); if (jsonSchema != null) schema = jsonSchema; else { GenerateProperties(type, schema, schemaResolver); ApplyAdditionalProperties(schema, type, schemaResolver); } if (!schema.Type.HasFlag(JsonObjectType.Array)) typeDescription.ApplyType(schema); schema.Description = ContextualTypeExtensions.ToCachedType(type).GetDescription(DescriptionAttributeType.Context); schema.Example = GenerateExample(ContextualTypeExtensions.ToContextualType(type)); if (Settings.GetActualGenerateAbstractSchema(type)) schema.IsAbstract = type.GetTypeInfo().IsAbstract; GenerateInheritanceDiscriminator(type, schema2, schema); GenerateKnownTypes(type, schemaResolver); if (Settings.GenerateXmlObjects) schema.GenerateXmlObjectForType(type); } protected virtual string[] GetTypeProperties(Type type) { if (type == typeof(Exception)) return new string[4] { "InnerException", "Message", "Source", "StackTrace" }; return null; } protected virtual void GenerateArray<TSchemaType>(TSchemaType schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new { ContextualType contextualType = typeDescription.ContextualType; typeDescription.ApplyType(schema); Type type = contextualType.GetTypeAttribute<JsonSchemaAttribute>()?.ArrayItem ?? TypeExtensions.GetEnumerableItemType(contextualType.get_OriginalType()); if (type != (Type)null) { ContextualType contextualItemType = ContextualTypeExtensions.ToContextualType(type); bool isNullable = contextualType.GetContextAttribute<ItemsCanBeNullAttribute>() != null || (int)contextualItemType.get_Nullability() == 2; schema.Item = GenerateWithReferenceAndNullability(contextualItemType, isNullable, schemaResolver, delegate(JsonSchema itemSchema, JsonSchema typeSchema) { if (Settings.GenerateXmlObjects) itemSchema.GenerateXmlObjectForItemType(contextualItemType); }); if (Settings.GenerateXmlObjects) schema.GenerateXmlObjectForArrayType(); } else schema.Item = JsonSchema.CreateAnySchema(); dynamic val = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)contextualType.get_ContextAttributes(), "MinLengthAttribute", 0); dynamic val2 = val != null; if ((val2 ? false : true) ? val2 : (val2 & ObjectExtensions.HasProperty(val, "Length"))) schema.MinItems = (int)val.Length; dynamic val3 = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)contextualType.get_ContextAttributes(), "MaxLengthAttribute", 0); val2 = (val3 != null); if ((val2 ? false : true) ? val2 : (val2 & ObjectExtensions.HasProperty(val3, "Length"))) schema.MaxItems = (int)val3.Length; } protected virtual void GenerateDictionary<TSchemaType>(TSchemaType schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new { ContextualType contextualType = typeDescription.ContextualType; typeDescription.ApplyType(schema); ContextualType[] genericArguments = contextualType.get_GenericArguments(); ContextualType val = (genericArguments.Length == 2) ? ((object)genericArguments[0]) : ((object)ContextualTypeExtensions.ToContextualType(typeof(string))); if (val.get_OriginalType().GetTypeInfo().IsEnum) schema.DictionaryKey = GenerateWithReference<JsonSchema>(val, schemaResolver, null); ContextualType val2 = (genericArguments.Length == 2) ? ((object)genericArguments[1]) : ((object)ContextualTypeExtensions.ToContextualType(typeof(object))); IEnumerable<JsonSchemaPatternPropertiesAttribute> enumerable = contextualType.get_ContextAttributes().OfType<JsonSchemaPatternPropertiesAttribute>(); if (enumerable.Any()) { schema.AllowAdditionalProperties = false; foreach (JsonSchemaPatternPropertiesAttribute item in enumerable) { Type type = item.Type; JsonSchemaProperty value = GenerateDictionaryValueSchema<JsonSchemaProperty>(schemaResolver, ((object)(((object)type != null) ? ContextualTypeExtensions.ToContextualType(type) : null)) ?? ((object)val2)); schema.PatternProperties.Add(item.RegularExpression, value); } } else { schema.AdditionalPropertiesSchema = GenerateDictionaryValueSchema<JsonSchema>(schemaResolver, val2); schema.AllowAdditionalProperties = true; } dynamic val3 = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)contextualType.get_ContextAttributes(), "MinLengthAttribute", 0); dynamic val4 = val3 != null; if ((val4 ? false : true) ? val4 : (val4 & ObjectExtensions.HasProperty(val3, "Length"))) schema.MinProperties = (int)val3.Length; dynamic val5 = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)contextualType.get_ContextAttributes(), "MaxLengthAttribute", 0); val4 = (val5 != null); if ((val4 ? false : true) ? val4 : (val4 & ObjectExtensions.HasProperty(val5, "Length"))) schema.MaxProperties = (int)val5.Length; } protected virtual void GenerateEnum(JsonSchema schema, JsonTypeDescription typeDescription) { ContextualType contextualType = typeDescription.ContextualType; schema.Type = typeDescription.Type; schema.Enumeration.Clear(); schema.EnumerationNames.Clear(); schema.IsFlagEnumerable = (contextualType.GetTypeAttribute<FlagsAttribute>() != null); Type underlyingType = Enum.GetUnderlyingType(contextualType.get_Type()); List<JsonConverter> list = Settings.ActualSerializerSettings.Converters.ToList(); if (!list.OfType<StringEnumConverter>().Any()) list.Add(new StringEnumConverter()); string[] names = Enum.GetNames(contextualType.get_Type()); foreach (string text in names) { if (typeDescription.Type == JsonObjectType.Integer) { object item = Convert.ChangeType(Enum.Parse(contextualType.get_Type(), text), underlyingType); schema.Enumeration.Add(item); } else { dynamic val = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>(contextualType.get_TypeInfo().GetDeclaredField(text).GetCustomAttributes(), "System.Runtime.Serialization.EnumMemberAttribute", 1); 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(contextualType.get_Type(), text), Formatting.None, list.ToArray()); schema.Enumeration.Add(JsonConvert.DeserializeObject<string>(value)); } } schema.EnumerationNames.Add(text); } if (typeDescription.Type == JsonObjectType.Integer && Settings.GenerateEnumMappingDescription) schema.Description = (schema.Description + "\n\n" + string.Join("\n", schema.Enumeration.Select((object e, int i) => e + " = " + schema.EnumerationNames[i]))).Trim(); } private TSchema GenerateDictionaryValueSchema<TSchema>(JsonSchemaResolver schemaResolver, ContextualType valueType) where TSchema : JsonSchema, new { if (valueType.get_OriginalType() == typeof(object)) { TSchema val = new TSchema(); if (Settings.SchemaType == SchemaType.Swagger2) val.AllowAdditionalProperties = false; return val; } JsonTypeDescription description = Settings.ReflectionService.GetDescription(valueType, Settings.DefaultDictionaryValueReferenceTypeNullHandling, Settings); bool isNullable = valueType.GetContextAttribute<ItemsCanBeNullAttribute>() != null || description.IsNullable; return GenerateWithReferenceAndNullability<TSchema>(valueType, isNullable, schemaResolver, null); } private void ApplyAdditionalProperties<TSchemaType>(TSchemaType schema, Type type, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new { ContextualPropertyInfo val = ((IEnumerable<ContextualPropertyInfo>)ContextualTypeExtensions.GetContextualProperties(type)).FirstOrDefault((Func<ContextualPropertyInfo, bool>)((ContextualPropertyInfo p) => p.GetContextAttribute<JsonExtensionDataAttribute>() != null)); if (val != null) { ContextualType[] genericArguments = val.get_GenericArguments(); ContextualType contextualType = (genericArguments.Length == 2) ? ((object)genericArguments[1]) : ((object)ContextualTypeExtensions.ToContextualType(typeof(object))); schema.AdditionalPropertiesSchema = GenerateWithReferenceAndNullability<JsonSchema>(contextualType, schemaResolver, null); } else schema.AllowAdditionalProperties = Settings.AlwaysAllowAdditionalObjectProperties; } private void ApplySchemaProcessors(JsonSchema schema, ContextualType contextualType, JsonSchemaResolver schemaResolver) { SchemaProcessorContext schemaProcessorContext = new SchemaProcessorContext(contextualType.get_OriginalType(), schema, schemaResolver, this, Settings); foreach (ISchemaProcessor schemaProcessor in Settings.SchemaProcessors) { schemaProcessor.Process(schemaProcessorContext); } foreach (dynamic item in EnumerableExtensions.GetAssignableToTypeName<Attribute>((IEnumerable<Attribute>)contextualType.get_TypeAttributes(), "JsonSchemaProcessorAttribute", 0)) { dynamic val = Activator.CreateInstance(item.Type, item.Parameters); val.Process(schemaProcessorContext); } } private bool TryHandleSpecialTypes<TSchemaType>(TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new { ITypeMapper typeMapper = Settings.TypeMappers.FirstOrDefault((ITypeMapper m) => m.MappedType == contextualType.get_OriginalType()); if (typeMapper == null && contextualType.get_OriginalType().GetTypeInfo().IsGenericType) { Type genericType = contextualType.get_OriginalType().GetGenericTypeDefinition(); typeMapper = Settings.TypeMappers.FirstOrDefault((ITypeMapper m) => m.MappedType == genericType); } if (typeMapper != null) { TypeMapperContext context = new TypeMapperContext(contextualType.get_OriginalType(), this, schemaResolver, contextualType.get_ContextAttributes()); typeMapper.GenerateSchema(schema, context); return true; } if (!TypeExtensions.IsAssignableToTypeName(contextualType.get_OriginalType(), "JArray", 0) && (TypeExtensions.IsAssignableToTypeName(contextualType.get_OriginalType(), "JToken", 0) || contextualType.get_OriginalType() == typeof(object))) { if (Settings.SchemaType == SchemaType.Swagger2) schema.AllowAdditionalProperties = false; return true; } return false; } private void GenerateEnum<TSchemaType>(TSchemaType schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver) where TSchemaType : JsonSchema, new { Type type = typeDescription.ContextualType.get_Type(); bool isIntegerEnumeration = typeDescription.Type == JsonObjectType.Integer; if (schemaResolver.HasSchema(type, isIntegerEnumeration)) ((JsonReferenceBase<JsonSchema>)schema).Reference = schemaResolver.GetSchema(type, isIntegerEnumeration); else if (schema.GetType() == typeof(JsonSchema)) { typeDescription.ApplyType(schema); schema.Description = XmlDocsExtensions.GetXmlDocsSummary(type); GenerateEnum(schema, typeDescription); schemaResolver.AddSchema(type, isIntegerEnumeration, schema); } else { ((JsonReferenceBase<JsonSchema>)schema).Reference = Generate(typeDescription.ContextualType, schemaResolver); } } private void GenerateProperties(Type type, JsonSchema schema, JsonSchemaResolver schemaResolver) { IEnumerable<ContextualMemberInfo> source = from m in (IEnumerable<MemberInfo>)type.GetTypeInfo().DeclaredFields.Where(delegate(FieldInfo f) { if (!f.IsPrivate) return !f.IsStatic; return false; }).OfType<MemberInfo>().Concat(type.GetTypeInfo().DeclaredProperties.Where(delegate(PropertyInfo p) { MethodInfo getMethod = p.GetMethod; if ((object)getMethod == null || !getMethod.IsPrivate) { MethodInfo getMethod2 = p.GetMethod; if ((object)getMethod2 != null && !getMethod2.IsStatic) return true; } MethodInfo setMethod = p.SetMethod; if ((object)setMethod == null || !setMethod.IsPrivate) { MethodInfo setMethod2 = p.SetMethod; if ((object)setMethod2 == null) return false; return !setMethod2.IsStatic; } return false; })) .ToList() select ContextualTypeExtensions.ToContextualMember(m); JsonContract jsonContract = Settings.ResolveContract(type); string[] allowedProperties = GetTypeProperties(type); JsonObjectContract jsonObjectContract = jsonContract as JsonObjectContract; if (jsonObjectContract != null && allowedProperties == null) { foreach (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) { ContextualMemberInfo val = source.FirstOrDefault((Func<ContextualMemberInfo, bool>)((ContextualMemberInfo p) => p.get_Name() == item.UnderlyingName)); if (val != null && (Settings.GenerateAbstractProperties || !IsAbstractProperty(val))) LoadPropertyOrField(item, val, type, schema, schemaResolver); } } } else { foreach (ContextualMemberInfo item2 in source.Where(delegate(ContextualMemberInfo m) { if (allowedProperties != null) return allowedProperties.Contains(m.get_Name()); return true; })) { JsonPropertyAttribute contextAttribute = item2.GetContextAttribute<JsonPropertyAttribute>(); object obj2 = (object)(item2 as ContextualPropertyInfo); object obj3 = (obj2 != null) ? obj2.get_PropertyInfo().PropertyType : null; if (obj3 == null) { object obj4 = (object)(item2 as ContextualFieldInfo); obj3 = ((obj4 != null) ? obj4.get_FieldInfo().FieldType : null); } Type propertyType = (Type)obj3; JsonProperty jsonProperty2 = new JsonProperty { AttributeProvider = new ReflectionAttributeProvider(item2), PropertyType = propertyType, Ignored = IsPropertyIgnored(item2, type) }; if (contextAttribute != null) { jsonProperty2.PropertyName = (contextAttribute.PropertyName ?? item2.get_Name()); jsonProperty2.Required = contextAttribute.Required; jsonProperty2.DefaultValueHandling = contextAttribute.DefaultValueHandling; jsonProperty2.TypeNameHandling = contextAttribute.TypeNameHandling; jsonProperty2.NullValueHandling = contextAttribute.NullValueHandling; jsonProperty2.TypeNameHandling = contextAttribute.TypeNameHandling; } else jsonProperty2.PropertyName = item2.get_Name(); LoadPropertyOrField(jsonProperty2, item2, type, schema, schemaResolver); } } } private bool IsAbstractProperty(ContextualMemberInfo memberInfo) { ContextualPropertyInfo val = memberInfo as ContextualPropertyInfo; if (val != null && !val.get_PropertyInfo().DeclaringType.GetTypeInfo().IsInterface) { if (!(val.get_PropertyInfo().GetMethod?.IsAbstract ?? false)) return val.get_PropertyInfo().SetMethod?.IsAbstract ?? false; return true; } return false; } private void GenerateKnownTypes(Type type, JsonSchemaResolver schemaResolver) { object[] customAttributes = type.GetTypeInfo().GetCustomAttributes(Settings.GetActualFlattenInheritanceHierarchy(type)); if (Settings.GenerateKnownTypes) { foreach (dynamic item in EnumerableExtensions.GetAssignableToTypeName<object>((IEnumerable<object>)customAttributes, "KnownTypeAttribute", 0).OfType<Attribute>()) { if (item.Type != null) this.AddKnownType(item.Type, schemaResolver); 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> enumerable = runtimeMethod.Invoke(null, null) as IEnumerable<Type>; if (enumerable != null) { foreach (Type item2 in enumerable) { AddKnownType(item2, schemaResolver); } } } } } } foreach (object item3 in EnumerableExtensions.GetAssignableToTypeName<object>((IEnumerable<object>)customAttributes, "JsonInheritanceAttribute", 0)) { Type type2 = ObjectExtensions.TryGetPropertyValue<Type>(item3, "Type", (Type)null); if (type2 != (Type)null) AddKnownType(type2, schemaResolver); } } private void AddKnownType(Type type, JsonSchemaResolver schemaResolver) { bool isIntegerEnumeration = Settings.ReflectionService.GetDescription(ContextualTypeExtensions.ToContextualType(type), Settings).Type == JsonObjectType.Integer; if (!schemaResolver.HasSchema(type, isIntegerEnumeration)) Generate(type, schemaResolver); } private JsonSchema GenerateInheritance(Type type, JsonSchema schema, JsonSchemaResolver schemaResolver) { Type baseType = type.GetTypeInfo().BaseType; if (baseType != (Type)null && baseType != typeof(object) && baseType != typeof(ValueType) && EnumerableExtensions.FirstAssignableToTypeNameOrDefault<object>((IEnumerable<object>)baseType.GetTypeInfo().GetCustomAttributes(false), "JsonSchemaIgnoreAttribute", 0) == null && EnumerableExtensions.FirstAssignableToTypeNameOrDefault<object>((IEnumerable<object>)baseType.GetTypeInfo().GetCustomAttributes(false), "SwaggerIgnoreAttribute", 0) == null) { string[] excludedTypeNames = Settings.ExcludedTypeNames; if (excludedTypeNames == null || !excludedTypeNames.Contains(baseType.FullName)) { if (!Settings.GetActualFlattenInheritanceHierarchy(type)) { JsonSchema jsonSchema = new JsonSchema(); GenerateProperties(type, jsonSchema, schemaResolver); ApplyAdditionalProperties(jsonSchema, type, schemaResolver); bool flag = Settings.ReflectionService.GetDescription(ContextualTypeExtensions.ToContextualType(baseType), Settings).RequiresSchemaReference(Settings.TypeMappers); if (jsonSchema.Properties.Any() | flag) { JsonSchema jsonSchema2 = Generate(baseType, schemaResolver); if (flag) { if (schemaResolver.RootObject != jsonSchema2.ActualSchema) schemaResolver.AppendSchema(jsonSchema2.ActualSchema, Settings.SchemaNameGenerator.Generate(baseType)); schema.AllOf.Add(new JsonSchema { Reference = jsonSchema2.ActualSchema }); } else schema.AllOf.Add(jsonSchema2); schema.AllOf.Add(jsonSchema); return jsonSchema; } Generate(schema, ContextualTypeExtensions.ToContextualType(baseType), schemaResolver); return schema; } if (!Settings.ReflectionService.GetDescription(ContextualTypeExtensions.ToContextualType(baseType), Settings).IsDictionary && !type.IsArray) { GenerateProperties(baseType, schema, schemaResolver); JsonSchema jsonSchema3 = GenerateInheritance(baseType, schema, schemaResolver); GenerateInheritanceDiscriminator(baseType, schema, jsonSchema3 ?? schema); } } } if (Settings.GetActualFlattenInheritanceHierarchy(type) && Settings.GenerateAbstractProperties) { foreach (Type implementedInterface in type.GetTypeInfo().ImplementedInterfaces) { if (!Settings.ReflectionService.GetDescription(ContextualTypeExtensions.ToContextualType(implementedInterface), Settings).IsDictionary && !type.IsArray && !typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(implementedInterface.GetTypeInfo())) { GenerateProperties(implementedInterface, schema, schemaResolver); JsonSchema jsonSchema4 = GenerateInheritance(implementedInterface, schema, schemaResolver); GenerateInheritanceDiscriminator(implementedInterface, schema, jsonSchema4 ?? schema); } } } return null; } private void GenerateInheritanceDiscriminator(Type type, JsonSchema schema, JsonSchema typeSchema) { if (!Settings.GetActualFlattenInheritanceHierarchy(type)) { object obj = TryGetInheritanceDiscriminatorConverter(type); if (obj != null) { string text = TryGetInheritanceDiscriminatorName(obj); if (typeSchema.Properties.TryGetValue(text, out JsonSchemaProperty 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 JsonSchemaProperty { Type = JsonObjectType.String, IsRequired = true }; } else (schema.ResponsibleDiscriminatorObject ?? schema.ActualTypeSchema.ResponsibleDiscriminatorObject)?.AddMapping(type, schema); } } private object TryGetInheritanceDiscriminatorConverter(Type type) { dynamic val = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>(type.GetTypeInfo().GetCustomAttributes(false).OfType<Attribute>(), "JsonConverterAttribute", 0); if ((val != null) && TypeExtensions.IsAssignableToTypeName((Type)val.ConverterType, "JsonInheritanceConverter", 0)) { 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 (ObjectExtensions.HasProperty(jsonInheritanceConverter, "DiscriminatorName")) return (string)jsonInheritanceConverter.DiscriminatorName; return JsonInheritanceConverter.DefaultDiscriminatorName; } private void LoadPropertyOrField(JsonProperty jsonProperty, ContextualMemberInfo memberInfo, Type parentType, JsonSchema parentSchema, JsonSchemaResolver schemaResolver) { JsonTypeDescription propertyTypeDescription = Settings.ReflectionService.GetDescription(memberInfo, Settings); if (!jsonProperty.Ignored && !IsPropertyIgnoredBySettings(memberInfo)) { string propertyName = GetPropertyName(jsonProperty, memberInfo); if (parentSchema.Properties.ContainsKey(propertyName)) { if (!Settings.GetActualFlattenInheritanceHierarchy(parentType)) throw new InvalidOperationException("The JSON property '" + propertyName + "' is defined multiple times on type '" + parentType.FullName + "'."); parentSchema.Properties.Remove(propertyName); } Attribute requiredAttribute = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)memberInfo.get_ContextAttributes(), "System.ComponentModel.DataAnnotations.RequiredAttribute", 1); bool flag = jsonProperty.Required == Required.Always || jsonProperty.Required == Required.AllowNull; dynamic val = GetDataMemberAttribute(memberInfo, parentType)?.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 && (jsonProperty.Required == Required.Default || jsonProperty.Required == Required.AllowNull); Action<JsonSchemaProperty, JsonSchema> transformation = delegate(JsonSchemaProperty propertySchema, JsonSchema typeSchema) { if (Settings.GenerateXmlObjects) propertySchema.GenerateXmlObjectForProperty(memberInfo, propertyName); if (hasRequiredAttribute && !propertyTypeDescription.IsEnum && propertyTypeDescription.Type == JsonObjectType.String && !ObjectExtensions.TryGetPropertyValue<bool>((object)requiredAttribute, "AllowEmptyStrings", false)) propertySchema.MinLength = 1; if (!isNullable && Settings.SchemaType == SchemaType.Swagger2 && !parentSchema.RequiredProperties.Contains(propertyName)) parentSchema.RequiredProperties.Add(propertyName); object obj = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)memberInfo.get_ContextAttributes(), "System.ComponentModel.ReadOnlyAttribute", 1); if ((dynamic)obj != null) propertySchema.IsReadOnly = ((byte)((dynamic)obj).IsReadOnly != 0); if (propertySchema.Description == null) propertySchema.Description = memberInfo.GetDescription(DescriptionAttributeType.Context); if (propertySchema.Example == null) propertySchema.Example = GenerateExample(memberInfo); propertySchema.Default = ConvertDefaultValue(memberInfo, jsonProperty.DefaultValue); ApplyDataAnnotations(propertySchema, propertyTypeDescription); ApplyPropertyExtensionDataAttributes(memberInfo, propertySchema); }; JsonSchemaProperty value = GenerateWithReferenceAndNullability(memberInfo, isNullable, schemaResolver, transformation); parentSchema.Properties.Add(propertyName, value); } } private bool IsPropertyIgnored(ContextualMemberInfo property, Type parentType) { if (property.GetContextAttribute<JsonIgnoreAttribute>() != null) return true; bool flag = property.GetContextAttribute<JsonPropertyAttribute>() == null && HasDataContractAttribute(parentType); if ((!flag) ? ((object)flag) : (flag & (GetDataMemberAttribute(property, parentType) == null))) return true; return IsPropertyIgnoredBySettings(property); } private bool IsPropertyIgnoredBySettings(ContextualMemberInfo property) { if (Settings.IgnoreObsoleteProperties && property.GetContextAttribute<ObsoleteAttribute>() != null) return true; if (property.GetContextAttribute<JsonSchemaIgnoreAttribute>() != null) return true; return false; } private dynamic GetDataMemberAttribute(ContextualMemberInfo property, Type parentType) { if (!HasDataContractAttribute(parentType)) return null; return EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)property.get_ContextAttributes(), "DataMemberAttribute", 0); } private bool HasDataContractAttribute(Type parentType) { return EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>((IEnumerable<Attribute>)ContextualTypeExtensions.ToCachedType(parentType).get_TypeAttributes(), "DataContractAttribute", 0) != null; } private void ApplyRangeAttribute(JsonSchema schema, IEnumerable<Attribute> parentAttributes) { dynamic val = EnumerableExtensions.FirstAssignableToTypeNameOrDefault<Attribute>(parentAttributes, "System.ComponentModel.DataAnnotations.RangeAttribute", 1); 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 void ApplyTypeExtensionDataAttributes<TSchemaType>(TSchemaType schema, ContextualType contextualType) where TSchemaType : JsonSchema, new { JsonSchemaExtensionDataAttribute[] source = contextualType.get_OriginalType().GetTypeInfo().GetCustomAttributes<JsonSchemaExtensionDataAttribute>() .ToArray(); if (source.Any()) schema.ExtensionData = source.ToDictionary((JsonSchemaExtensionDataAttribute a) => a.Key, (JsonSchemaExtensionDataAttribute a) => a.Value); } private void ApplyPropertyExtensionDataAttributes(ContextualMemberInfo memberInfo, JsonSchemaProperty propertySchema) { JsonSchemaExtensionDataAttribute[] source = memberInfo.GetContextAttributes<JsonSchemaExtensionDataAttribute>().ToArray(); if (source.Any()) propertySchema.ExtensionData = source.ToDictionary((JsonSchemaExtensionDataAttribute a) => a.Key, (JsonSchemaExtensionDataAttribute a) => a.Value); } } }