private void LoadDefaultReturnType(SwaggerOperation operation, MethodInfo method, string xmlDescription, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { var returnType = method.ReturnType; if (returnType == typeof(Task)) { returnType = typeof(void); } else if (returnType.Name == "Task`1") { returnType = returnType.GenericTypeArguments[0]; } if (IsVoidResponse(returnType)) { operation.Responses["204"] = new SwaggerResponse { Description = xmlDescription ?? string.Empty, }; } else { var typeDescription = JsonObjectTypeDescription.FromType(returnType, method.ReturnParameter?.GetCustomAttributes(), Settings.DefaultEnumHandling); operation.Responses["200"] = new SwaggerResponse { Description = xmlDescription ?? string.Empty, IsNullableRaw = typeDescription.IsNullable, Schema = CreateAndAddSchema(returnType, typeDescription.IsNullable, null, schemaResolver, schemaDefinitionAppender) }; } }
/// <summary>Initializes a new instance of the <see cref="SwaggerGenerator"/> class.</summary> /// <param name="schemaGenerator">The schema generator.</param> /// <param name="schemaGeneratorSettings">The schema generator settings.</param> /// <param name="schemaResolver">The schema resolver.</param> /// <param name="schemaDefinitionAppender">The schema definition appender.</param> public SwaggerGenerator(JsonSchemaGenerator schemaGenerator, JsonSchemaGeneratorSettings schemaGeneratorSettings, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { _schemaGenerator = schemaGenerator; _schemaResolver = schemaResolver; _schemaDefinitionAppender = schemaDefinitionAppender; _settings = schemaGeneratorSettings; }
private void AddPrimitiveParameter(string name, SwaggerOperation operation, ParameterInfo parameter, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { var operationParameter = CreatePrimitiveParameter(name, parameter, schemaResolver, schemaDefinitionAppender); operationParameter.Kind = SwaggerParameterKind.Query; operationParameter.IsRequired = operationParameter.IsRequired || parameter.HasDefaultValue == false; operation.Parameters.Add(operationParameter); }
/// <exception cref="InvalidOperationException">The operation has more than one body parameter.</exception> private void GenerateForController(SwaggerService service, Type controllerType, string excludedMethodName, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { var hasIgnoreAttribute = controllerType.GetTypeInfo().GetCustomAttributes() .Any(a => a.GetType().Name == "SwaggerIgnoreAttribute"); if (!hasIgnoreAttribute) { var operations = new List <Tuple <SwaggerOperationDescription, MethodInfo> >(); foreach (var method in GetActionMethods(controllerType, excludedMethodName)) { var httpPaths = GetHttpPaths(controllerType, method); var httpMethods = GetSupportedHttpMethods(method).ToList(); foreach (var httpPath in httpPaths) { foreach (var httpMethod in httpMethods) { var operation = new SwaggerOperation { IsDeprecated = method.GetCustomAttribute <ObsoleteAttribute>() != null }; var parameters = method.GetParameters().ToList(); LoadParameters(operation, parameters, httpPath, schemaResolver, schemaDefinitionAppender); LoadReturnType(operation, method, schemaResolver, schemaDefinitionAppender); LoadMetaData(operation, method); LoadOperationTags(method, operation, controllerType); var operationDescription = new SwaggerOperationDescription { Path = Regex.Replace(httpPath, "{(.*?)(:(.*?))?}", match => { if (operation.ActualParameters.Any(p => p.Kind == SwaggerParameterKind.Path && match.Groups[1].Value == p.Name)) { return("{" + match.Groups[1].Value + "}"); } return(string.Empty); }).TrimEnd('/'), Method = httpMethod, Operation = operation }; operationDescription.Operation.OperationId = GetOperationId(service, controllerType.Name, method); operations.Add(new Tuple <SwaggerOperationDescription, MethodInfo>(operationDescription, method)); } } } AddOperationDescriptionsToDocument(service, operations, schemaResolver); } AppendRequiredSchemasToDefinitions(service, schemaResolver); }
private void AddFileParameter(ParameterInfo parameter, bool isFileArray, SwaggerOperation operation, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { var attributes = parameter.GetCustomAttributes().ToList(); // TODO: Check if there is a way to control the property name var operationParameter = CreatePrimitiveParameter(parameter.Name, parameter.GetXmlDocumentation(), parameter.ParameterType, attributes, schemaResolver, schemaDefinitionAppender); InitializeFileParameter(operationParameter, isFileArray); operation.Parameters.Add(operationParameter); }
/// <summary>Generates the properties for the given type and schema.</summary> /// <typeparam name="TSchemaType">The type of the schema type.</typeparam> /// <param name="type">The types.</param> /// <param name="schema">The properties</param> /// <param name="rootSchema">The root schema.</param> /// <param name="schemaDefinitionAppender"></param> /// <param name="schemaResolver">The schema resolver.</param> protected virtual void GenerateObject <TSchemaType>(Type type, TSchemaType schema, JsonSchema4 rootSchema, ISchemaDefinitionAppender schemaDefinitionAppender, ISchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new() { schemaResolver.AddSchema(type, false, schema); schema.AllowAdditionalProperties = false; GeneratePropertiesAndInheritance(type, schema, rootSchema, schemaDefinitionAppender, schemaResolver); if (Settings.GenerateKnownTypes) { GenerateKnownTypes(type, rootSchema, schemaDefinitionAppender, schemaResolver); } }
private bool TryAddFileParameter(JsonObjectTypeDescription info, SwaggerOperation operation, ParameterInfo parameter, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { var isFileArray = IsFileArray(parameter.ParameterType, info); if (info.Type == JsonObjectType.File || isFileArray) { AddFileParameter(parameter, isFileArray, operation, schemaResolver, schemaDefinitionAppender); return(true); } return(false); }
private void GenerateKnownTypes(Type type, JsonSchema4 rootSchema, ISchemaDefinitionAppender schemaDefinitionAppender, ISchemaResolver schemaResolver) { foreach (var knownTypeAttribute in type.GetTypeInfo().GetCustomAttributes <KnownTypeAttribute>()) { var typeDescription = JsonObjectTypeDescription.FromType(knownTypeAttribute.Type, null, Settings.DefaultEnumHandling); var isIntegerEnum = typeDescription.Type == JsonObjectType.Integer; if (!schemaResolver.HasSchema(knownTypeAttribute.Type, isIntegerEnum)) { var knownSchema = Generate(knownTypeAttribute.Type, rootSchema, null, schemaDefinitionAppender, schemaResolver); schemaDefinitionAppender.Append(rootSchema, knownSchema.ActualSchema); } } }
private void GenerateKnownTypes(Type type, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { foreach (dynamic knownTypeAttribute in type.GetTypeInfo().GetCustomAttributes().Where(a => a.GetType().Name == "KnownTypeAttribute")) { var typeDescription = JsonObjectTypeDescription.FromType(knownTypeAttribute.Type, null, Settings.DefaultEnumHandling); var isIntegerEnum = typeDescription.Type == JsonObjectType.Integer; if (!schemaResolver.HasSchema(knownTypeAttribute.Type, isIntegerEnum)) { var knownSchema = Generate(knownTypeAttribute.Type, schemaResolver, schemaDefinitionAppender); schemaDefinitionAppender.Append(knownSchema.ActualSchema); } } }
/// <summary>Gets the JSON path of the given object.</summary> /// <param name="root">The root object.</param> /// <param name="objectToSearch">The object to search.</param> /// <param name="schemaDefinitionAppender">Appends the <paramref name="objectToSearch"/> to the 'definitions' if it could not be found.</param> /// <returns>The path or <c>null</c> when the object could not be found.</returns> /// <exception cref="InvalidOperationException">Could not find the JSON path of a child object.</exception> public static string GetJsonPath(object root, object objectToSearch, ISchemaDefinitionAppender schemaDefinitionAppender = null) { var path = GetJsonPath(root, objectToSearch, "#", new HashSet<object>()); if (path == null) { if (schemaDefinitionAppender != null && objectToSearch is JsonSchema4) { schemaDefinitionAppender.Append(root, (JsonSchema4)objectToSearch); return GetJsonPath(root, objectToSearch, schemaDefinitionAppender); } else throw new InvalidOperationException("Could not find the JSON path of a child object."); } return path; }
/// <summary>Gets the JSON path of the given object.</summary> /// <param name="root">The root object.</param> /// <param name="objectToSearch">The object to search.</param> /// <param name="schemaDefinitionAppender">Appends the <paramref name="objectToSearch"/> to the 'definitions' if it could not be found.</param> /// <returns>The path or <c>null</c> when the object could not be found.</returns> /// <exception cref="InvalidOperationException">Could not find the JSON path of a child object.</exception> public static string GetJsonPath(object root, object objectToSearch, ISchemaDefinitionAppender schemaDefinitionAppender = null) { var path = GetJsonPath(root, objectToSearch, "#", new List <object>()); if (path == null) { if (schemaDefinitionAppender != null && objectToSearch is JsonSchema4) { schemaDefinitionAppender.Append(root, (JsonSchema4)objectToSearch); return(GetJsonPath(root, objectToSearch, schemaDefinitionAppender)); } else { throw new InvalidOperationException("Could not find the JSON path of a child object."); } } return(path); }
/// <summary>Gets the JSON path of the given object.</summary> /// <param name="root">The root object.</param> /// <param name="searchedObject">The object to search.</param> /// <param name="schemaDefinitionAppender">Appends the <paramref name="searchedObject"/> to the 'definitions' if it could not be found.</param> /// <returns>The path or <c>null</c> when the object could not be found.</returns> /// <exception cref="InvalidOperationException">Could not find the JSON path of a child object.</exception> public static string GetJsonPath(object root, object searchedObject, ISchemaDefinitionAppender schemaDefinitionAppender = null) { var path = GetJsonPath(root, searchedObject, "#", new HashSet <object>()); if (path == null) { var searchedSchema = searchedObject as JsonSchema4; if (schemaDefinitionAppender != null && searchedSchema != null) { schemaDefinitionAppender.Append(searchedSchema); return(GetJsonPath(root, searchedObject, schemaDefinitionAppender)); } else { throw new InvalidOperationException("Could not find the JSON path of a child object."); } } return(path); }
private SwaggerParameter CreatePrimitiveParameter(string name, ParameterInfo parameter, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { return(CreatePrimitiveParameter(name, parameter.GetXmlDocumentation(), parameter.ParameterType, parameter.GetCustomAttributes().ToList(), schemaResolver, schemaDefinitionAppender)); }
private void GenerateInheritance(Type type, JsonSchema4 schema, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { GenerateInheritanceDiscriminator(type, schema); var baseType = type.GetTypeInfo().BaseType; if (baseType != null && baseType != typeof(object)) { if (Settings.FlattenInheritanceHierarchy) { GeneratePropertiesAndInheritance(baseType, schema, schemaResolver, schemaDefinitionAppender); } else { var baseSchema = Generate(baseType, schemaResolver, schemaDefinitionAppender); schema.AllOf.Add(baseSchema); } } }
/// <exception cref="InvalidOperationException">Could not find value type of dictionary type.</exception> private void GenerateDictionary <TSchemaType>(Type type, TSchemaType schema, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) where TSchemaType : JsonSchema4, new() { var genericTypeArguments = ReflectionExtensions.GetGenericTypeArguments(type); var valueType = genericTypeArguments.Length == 2 ? genericTypeArguments[1] : typeof(object); if (valueType == typeof(object)) { schema.AdditionalPropertiesSchema = JsonSchema4.CreateAnySchema(); } else { if (RequiresSchemaReference(valueType, null)) { schema.AdditionalPropertiesSchema = new JsonSchema4 { SchemaReference = Generate(valueType, schemaResolver, schemaDefinitionAppender) }; } else { schema.AdditionalPropertiesSchema = Generate(valueType, schemaResolver, schemaDefinitionAppender); } } schema.AllowAdditionalProperties = true; }
private void GeneratePropertiesAndInheritance(Type type, JsonSchema4 schema, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { var properties = GetTypeProperties(type); #if !LEGACY var declaredFields = type.GetTypeInfo().DeclaredFields .Where(f => f.IsPublic); var declaredProperties = type.GetTypeInfo().DeclaredProperties .Where(p => p.GetMethod?.IsPublic == true || p.SetMethod?.IsPublic == true); #else var declaredFields = type.GetTypeInfo() .GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance); var declaredProperties = type.GetTypeInfo() .GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance) .Where(p => p.GetGetMethod()?.IsPublic == true || p.GetSetMethod()?.IsPublic == true); #endif foreach (var property in declaredProperties.Where(p => properties == null || properties.Contains(p.Name))) { LoadPropertyOrField(property, property.PropertyType, type, schema, schemaResolver, schemaDefinitionAppender); } foreach (var field in declaredFields.Where(p => properties == null || properties.Contains(p.Name))) { LoadPropertyOrField(field, field.FieldType, type, schema, schemaResolver, schemaDefinitionAppender); } GenerateInheritance(type, schema, schemaResolver, schemaDefinitionAppender); }
/// <summary>Updates the <see cref="JsonSchema4.SchemaReferencePath" /> properties /// from the available <see cref="JsonSchema4.SchemaReference" /> properties.</summary> /// <param name="root">The root.</param> /// <param name="schemaDefinitionAppender">The schema definition appender.</param> public static void UpdateSchemaReferencePaths(object root, ISchemaDefinitionAppender schemaDefinitionAppender) { UpdateSchemaReferencePaths(root, root, new HashSet <object>(), schemaDefinitionAppender); }
/// <summary>Generates a <see cref="JsonSchema4" /> object for the given type and adds the mapping to the given resolver.</summary> /// <param name="type">The type.</param> /// <param name="rootSchema">The root schema.</param> /// <param name="parentAttributes">The parent property or parameter attributes.</param> /// <param name="schemaDefinitionAppender">The schema definition appender.</param> /// <param name="schemaResolver">The schema resolver.</param> /// <returns>The schema.</returns> /// <exception cref="InvalidOperationException">Could not find value type of dictionary type.</exception> public TSchemaType Generate <TSchemaType>(Type type, JsonSchema4 rootSchema, IEnumerable <Attribute> parentAttributes, ISchemaDefinitionAppender schemaDefinitionAppender, ISchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new() { var schema = HandleSpecialTypes <TSchemaType>(type); if (schema != null) { return(schema); } schema = new TSchemaType(); if (rootSchema == null) { rootSchema = schema; } var typeDescription = JsonObjectTypeDescription.FromType(type, parentAttributes, Settings.DefaultEnumHandling); typeDescription.ApplyType(schema); ApplyExtensionDataAttributes(schema, type, parentAttributes); if (schema.Type.HasFlag(JsonObjectType.Object)) { if (typeDescription.IsDictionary) { GenerateDictionary(type, rootSchema, schema, schemaDefinitionAppender, schemaResolver); } else { schema.TypeNameRaw = GetTypeName(type); if (schemaResolver.HasSchema(type, false)) { schema.SchemaReference = schemaResolver.GetSchema(type, false); return(schema); } if (schema.GetType() == typeof(JsonSchema4)) { schema.Description = GetDescription(type.GetTypeInfo(), type.GetTypeInfo().GetCustomAttributes()); GenerateObject(type, schema, rootSchema, schemaDefinitionAppender, schemaResolver); } else { schema.SchemaReference = Generate(type, rootSchema, parentAttributes, schemaDefinitionAppender, schemaResolver); return(schema); } } } else if (type.GetTypeInfo().IsEnum) { var isIntegerEnumeration = typeDescription.Type == JsonObjectType.Integer; if (schemaResolver.HasSchema(type, isIntegerEnumeration)) { schema.Type = typeDescription.Type; schema.SchemaReference = schemaResolver.GetSchema(type, isIntegerEnumeration); return(schema); } if (schema.GetType() == typeof(JsonSchema4)) { LoadEnumerations(type, schema, typeDescription); schema.TypeNameRaw = GetTypeName(type); schema.Description = type.GetXmlDocumentation(); schemaResolver.AddSchema(type, isIntegerEnumeration, schema); } else { schema.SchemaReference = Generate(type, rootSchema, parentAttributes, schemaDefinitionAppender, schemaResolver); return(schema); } } else if (schema.Type.HasFlag(JsonObjectType.Array)) { schema.Type = JsonObjectType.Array; var genericTypeArguments = GetGenericTypeArguments(type); var itemType = genericTypeArguments.Length == 0 ? type.GetElementType() : genericTypeArguments[0]; if (itemType == null) { schema.Item = JsonSchema4.CreateAnySchema(); } else { schema.Item = Generate(itemType, rootSchema, null, schemaDefinitionAppender, schemaResolver); } } return(schema); }
private SwaggerParameter CreatePrimitiveParameter(string name, string description, Type type, IList <Attribute> parentAttributes, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { var typeDescription = JsonObjectTypeDescription.FromType(type, parentAttributes, Settings.DefaultEnumHandling); var parameterType = typeDescription.Type.HasFlag(JsonObjectType.Object) ? typeof(string) : type; // object types must be treated as string var operationParameter = _schemaGenerator.Generate <SwaggerParameter>(parameterType, parentAttributes, schemaResolver, schemaDefinitionAppender); if (parameterType.GetTypeInfo().IsEnum) { operationParameter.SchemaReference = _schemaGenerator.Generate <JsonSchema4>(parameterType, parentAttributes, schemaResolver, schemaDefinitionAppender); } else { _schemaGenerator.ApplyPropertyAnnotations(operationParameter, type, parentAttributes, typeDescription); } operationParameter.Name = name; operationParameter.IsRequired = parentAttributes?.Any(a => a.GetType().Name == "RequiredAttribute") ?? false; operationParameter.IsNullableRaw = typeDescription.IsNullable; if (description != string.Empty) { operationParameter.Description = description; } return(operationParameter); }
/// <summary>Generates a <see cref="JsonSchema4" /> object for the given type and adds the mapping to the given resolver.</summary> /// <param name="type">The type.</param> /// <param name="parentAttributes">The parent property or parameter attributes.</param> /// <param name="schemaResolver"></param> /// <param name="schemaDefinitionAppender"></param> /// <returns>The schema.</returns> /// <exception cref="InvalidOperationException">Could not find value type of dictionary type.</exception> public virtual TSchemaType Generate <TSchemaType>(Type type, IEnumerable <Attribute> parentAttributes, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) where TSchemaType : JsonSchema4, new() { var schema = HandleSpecialTypes <TSchemaType>(type, schemaResolver); if (schema != null) { return(schema); } schema = new TSchemaType(); if (schemaDefinitionAppender.RootObject == null) { schemaDefinitionAppender.RootObject = schema; } ApplyExtensionDataAttributes(schema, type, parentAttributes); var typeDescription = JsonObjectTypeDescription.FromType(type, parentAttributes, Settings.DefaultEnumHandling); if (typeDescription.Type.HasFlag(JsonObjectType.Object)) { if (typeDescription.IsDictionary) { typeDescription.ApplyType(schema); GenerateDictionary(type, schema, schemaResolver, schemaDefinitionAppender); } else { if (schemaResolver.HasSchema(type, false)) { schema.SchemaReference = schemaResolver.GetSchema(type, false); return(schema); } if (schema.GetType() == typeof(JsonSchema4)) { typeDescription.ApplyType(schema); schema.TypeNameRaw = ReflectionExtensions.GetSafeTypeName(type); schema.Description = GetDescription(type.GetTypeInfo(), type.GetTypeInfo().GetCustomAttributes()); GenerateObject(type, schema, schemaResolver, schemaDefinitionAppender); } else { schema.SchemaReference = Generate <JsonSchema4>(type, parentAttributes, schemaResolver, schemaDefinitionAppender); return(schema); } } } else if (type.GetTypeInfo().IsEnum) { var isIntegerEnumeration = typeDescription.Type == JsonObjectType.Integer; if (schemaResolver.HasSchema(type, isIntegerEnumeration)) { schema.SchemaReference = schemaResolver.GetSchema(type, isIntegerEnumeration); return(schema); } if (schema.GetType() == typeof(JsonSchema4)) { LoadEnumerations(type, schema, typeDescription); typeDescription.ApplyType(schema); schema.TypeNameRaw = ReflectionExtensions.GetSafeTypeName(type); schema.Description = type.GetXmlSummary(); schemaResolver.AddSchema(type, isIntegerEnumeration, schema); } else { schema.SchemaReference = Generate <JsonSchema4>(type, parentAttributes, schemaResolver, schemaDefinitionAppender); return(schema); } } else if (typeDescription.Type.HasFlag(JsonObjectType.Array)) { typeDescription.ApplyType(schema); var itemType = type.GetEnumerableItemType(); if (itemType == null) { var jsonSchemaAttribute = type.GetTypeInfo().GetCustomAttribute <JsonSchemaAttribute>(); if (jsonSchemaAttribute?.ArrayItem != null) { schema.Item = Generate(jsonSchemaAttribute.ArrayItem, schemaResolver, schemaDefinitionAppender); } else { schema.Item = JsonSchema4.CreateAnySchema(); } } else { if (itemType.GetTypeInfo().IsEnum) { schema.Item = new JsonSchema4 { SchemaReference = Generate(itemType, schemaResolver, schemaDefinitionAppender) } } ; else { schema.Item = Generate(itemType, schemaResolver, schemaDefinitionAppender); } } } else { typeDescription.ApplyType(schema); } return(schema); }
private void LoadReturnType(SwaggerOperation operation, MethodInfo method, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { var xmlDescription = method.ReturnParameter.GetXmlDocumentation(); if (xmlDescription == string.Empty) { xmlDescription = null; } var responseTypeAttributes = method.GetCustomAttributes() .Where(a => a.GetType().Name == "ResponseTypeAttribute") .ToList(); var producesResponseTypeAttributes = method.GetCustomAttributes() .Where(a => a.GetType().Name == "ProducesResponseTypeAttribute") .ToList(); if (responseTypeAttributes.Any() || producesResponseTypeAttributes.Any()) { foreach (var responseTypeAttribute in responseTypeAttributes) { dynamic dynResultTypeAttribute = responseTypeAttribute; var returnType = dynResultTypeAttribute.ResponseType; var httpStatusCode = IsVoidResponse(returnType) ? "204" : "200"; if (responseTypeAttribute.GetType().GetRuntimeProperty("HttpStatusCode") != null) { httpStatusCode = dynResultTypeAttribute.HttpStatusCode; } var description = xmlDescription; if (responseTypeAttribute.GetType().GetRuntimeProperty("Description") != null) { if (!string.IsNullOrEmpty(dynResultTypeAttribute.Description)) { description = dynResultTypeAttribute.Description; } } var typeDescription = JsonObjectTypeDescription.FromType(returnType, method.ReturnParameter?.GetCustomAttributes(), Settings.DefaultEnumHandling); var response = new SwaggerResponse { Description = description ?? string.Empty, IsNullableRaw = typeDescription.IsNullable }; if (IsVoidResponse(returnType) == false) { response.Schema = CreateAndAddSchema(returnType, typeDescription.IsNullable, null, schemaResolver, schemaDefinitionAppender); } operation.Responses[httpStatusCode] = response; } foreach (dynamic producesResponseTypeAttribute in producesResponseTypeAttributes) { var returnType = producesResponseTypeAttribute.Type; var typeDescription = JsonObjectTypeDescription.FromType(returnType, method.ReturnParameter?.GetCustomAttributes(), Settings.DefaultEnumHandling); var httpStatusCode = producesResponseTypeAttribute.StatusCode.ToString(CultureInfo.InvariantCulture); operation.Responses[httpStatusCode] = new SwaggerResponse { Description = xmlDescription ?? string.Empty, IsNullableRaw = typeDescription.IsNullable, Schema = CreateAndAddSchema(returnType, typeDescription.IsNullable, null, schemaResolver, schemaDefinitionAppender) }; } } else { LoadDefaultReturnType(operation, method, xmlDescription, schemaResolver, schemaDefinitionAppender); } }
private void GeneratePropertiesAndInheritance(Type type, JsonSchema4 schema, JsonSchema4 rootSchema, ISchemaDefinitionAppender schemaDefinitionAppender, ISchemaResolver schemaResolver) { var properties = GetTypeProperties(type); foreach (var property in type.GetTypeInfo().DeclaredProperties.Where(p => properties == null || properties.Contains(p.Name))) { LoadProperty(type, property, schema, rootSchema, schemaDefinitionAppender, schemaResolver); } GenerateInheritance(type, schema, rootSchema, schemaDefinitionAppender, schemaResolver); }
/// <exception cref="InvalidOperationException">Could not find value type of dictionary type.</exception> private void GenerateDictionary <TSchemaType>(Type type, JsonSchema4 rootSchema, TSchemaType schema, ISchemaDefinitionAppender schemaDefinitionAppender, ISchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new() { var genericTypeArguments = GetGenericTypeArguments(type); if (genericTypeArguments.Length != 2) { throw new InvalidOperationException("Could not find value type of dictionary type '" + type.FullName + "'."); } var valueType = genericTypeArguments[1]; if (valueType == typeof(object)) { schema.AdditionalPropertiesSchema = JsonSchema4.CreateAnySchema(); } else { schema.AdditionalPropertiesSchema = Generate(valueType, rootSchema, null, schemaDefinitionAppender, schemaResolver); } schema.AllowAdditionalProperties = true; }
private JsonSchema4 CreateAndAddSchema(Type type, bool mayBeNull, IEnumerable <Attribute> parentAttributes, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { if (type.Name == "Task`1") { type = type.GenericTypeArguments[0]; } if (type.Name == "JsonResult`1") { type = type.GenericTypeArguments[0]; } if (IsFileResponse(type)) { return new JsonSchema4 { Type = JsonObjectType.File } } ; var typeDescription = JsonObjectTypeDescription.FromType(type, parentAttributes, Settings.DefaultEnumHandling); if (typeDescription.Type.HasFlag(JsonObjectType.Object) && !typeDescription.IsDictionary) { if (type == typeof(object)) { return(new JsonSchema4 { // IsNullable is directly set on SwaggerParameter or SwaggerResponse Type = Settings.NullHandling == NullHandling.JsonSchema ? JsonObjectType.Object | JsonObjectType.Null : JsonObjectType.Object, AllowAdditionalProperties = false }); } if (!schemaResolver.HasSchema(type, false)) { _schemaGenerator.Generate(type, schemaResolver, schemaDefinitionAppender); } if (mayBeNull) { if (Settings.NullHandling == NullHandling.JsonSchema) { var schema = new JsonSchema4(); schema.OneOf.Add(new JsonSchema4 { Type = JsonObjectType.Null }); schema.OneOf.Add(new JsonSchema4 { SchemaReference = schemaResolver.GetSchema(type, false) }); return(schema); } else { // IsNullable is directly set on SwaggerParameter or SwaggerResponse return(new JsonSchema4 { SchemaReference = schemaResolver.GetSchema(type, false) }); } } else { return new JsonSchema4 { SchemaReference = schemaResolver.GetSchema(type, false) } }; } if (typeDescription.Type.HasFlag(JsonObjectType.Array)) { var itemType = type.GenericTypeArguments.Length == 0 ? type.GetElementType() : type.GenericTypeArguments[0]; return(new JsonSchema4 { // IsNullable is directly set on SwaggerParameter or SwaggerResponse Type = Settings.NullHandling == NullHandling.JsonSchema ? JsonObjectType.Array | JsonObjectType.Null : JsonObjectType.Array, Item = CreateAndAddSchema(itemType, false, null, schemaResolver, schemaDefinitionAppender) }); } return(_schemaGenerator.Generate(type, schemaResolver, schemaDefinitionAppender)); } } }
private static void UpdateSchemaReferencePaths(object root, object obj, HashSet <object> checkedObjects, ISchemaDefinitionAppender schemaDefinitionAppender) { if (obj == null || obj is string) { return; } var schema = obj as JsonSchema4; if (schema != null && schema.SchemaReference != null) { schema.SchemaReferencePath = JsonPathUtilities.GetJsonPath(root, schema.SchemaReference.ActualSchema, schemaDefinitionAppender); } if (obj is IDictionary) { foreach (var item in ((IDictionary)obj).Values.OfType <object>().ToList()) { UpdateSchemaReferencePaths(root, item, checkedObjects, schemaDefinitionAppender); } } else if (obj is IEnumerable) { foreach (var item in ((IEnumerable)obj).OfType <object>().ToArray()) { UpdateSchemaReferencePaths(root, item, checkedObjects, schemaDefinitionAppender); } } if (!(obj is JToken)) { foreach (var property in ReflectionCache.GetProperties(obj.GetType()).Where(p => p.CanRead && p.IsIndexer == false && p.MemberInfo is PropertyInfo && p.CustomAttributes.JsonIgnoreAttribute == null)) { var value = property.GetValue(obj); if (value != null) { if (!checkedObjects.Contains(value)) { checkedObjects.Add(value); UpdateSchemaReferencePaths(root, value, checkedObjects, schemaDefinitionAppender); } } } } }
private void LoadPropertyOrField(MemberInfo property, Type propertyType, Type parentType, JsonSchema4 parentSchema, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { var attributes = property.GetCustomAttributes(inherit: true).OfType <Attribute>().ToArray(); var propertyTypeDescription = JsonObjectTypeDescription.FromType(propertyType, attributes, Settings.DefaultEnumHandling); if (IsPropertyIgnored(parentType, attributes) == false) { JsonProperty jsonProperty; if (propertyType.Name == "Nullable`1") #if !LEGACY { propertyType = propertyType.GenericTypeArguments[0]; } #else { propertyType = propertyType.GetGenericArguments()[0]; } #endif var requiresSchemaReference = RequiresSchemaReference(propertyType, attributes); if (requiresSchemaReference) { var propertySchema = Generate <JsonSchema4>(propertyType, attributes, schemaResolver, schemaDefinitionAppender); // The schema is automatically added to Definitions if it is missing in JsonPathUtilities.GetJsonPath() if (Settings.NullHandling == NullHandling.JsonSchema) { jsonProperty = new JsonProperty(); jsonProperty.OneOf.Add(new JsonSchema4 { SchemaReference = propertySchema.ActualSchema }); } else { jsonProperty = new JsonProperty { SchemaReference = propertySchema.ActualSchema }; } } else { jsonProperty = Generate <JsonProperty>(propertyType, attributes, schemaResolver, schemaDefinitionAppender); } var propertyName = JsonPathUtilities.GetPropertyName(property, Settings.DefaultPropertyNameHandling); if (parentSchema.Properties.ContainsKey(propertyName)) { throw new InvalidOperationException("The JSON property '" + propertyName + "' is defined multiple times on type '" + parentType.FullName + "'."); } parentSchema.Properties.Add(propertyName, jsonProperty); var requiredAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.RequiredAttribute"); var jsonPropertyAttribute = attributes.OfType <JsonPropertyAttribute>().SingleOrDefault(); var hasJsonNetAttributeRequired = jsonPropertyAttribute != null && ( jsonPropertyAttribute.Required == Required.Always || jsonPropertyAttribute.Required == Required.AllowNull); var isDataContractMemberRequired = GetDataMemberAttribute(parentType, attributes)?.IsRequired == true; var hasRequiredAttribute = requiredAttribute != null; if (hasRequiredAttribute || isDataContractMemberRequired || hasJsonNetAttributeRequired) { parentSchema.RequiredProperties.Add(propertyName); } var isJsonNetAttributeNullable = jsonPropertyAttribute != null && jsonPropertyAttribute.Required == Required.AllowNull; var isNullable = !hasRequiredAttribute && !isDataContractMemberRequired && (propertyTypeDescription.IsNullable || isJsonNetAttributeNullable); if (isNullable) { if (Settings.NullHandling == NullHandling.JsonSchema) { if (requiresSchemaReference) { jsonProperty.OneOf.Add(new JsonSchema4 { Type = JsonObjectType.Null }); } else if (jsonProperty.Type == JsonObjectType.None) { jsonProperty.OneOf.Add(new JsonSchema4 { Type = JsonObjectType.None }); jsonProperty.OneOf.Add(new JsonSchema4 { Type = JsonObjectType.Null }); } else { jsonProperty.Type = jsonProperty.Type | JsonObjectType.Null; } } } else if (Settings.NullHandling == NullHandling.Swagger) { if (!parentSchema.RequiredProperties.Contains(propertyName)) { parentSchema.RequiredProperties.Add(propertyName); } } dynamic readOnlyAttribute = attributes.TryGetIfAssignableTo("System.ComponentModel.ReadOnlyAttribute"); if (readOnlyAttribute != null) { jsonProperty.IsReadOnly = readOnlyAttribute.IsReadOnly; } jsonProperty.Description = GetDescription(property, attributes); ApplyPropertyAnnotations(jsonProperty, parentType, attributes, propertyTypeDescription); } }
private void LoadProperty(Type parentType, PropertyInfo property, JsonSchema4 parentSchema, JsonSchema4 rootSchema, ISchemaDefinitionAppender schemaDefinitionAppender, ISchemaResolver schemaResolver) { var propertyType = property.PropertyType; var propertyTypeDescription = JsonObjectTypeDescription.FromType(propertyType, property.GetCustomAttributes(), Settings.DefaultEnumHandling); var attributes = property.GetCustomAttributes().ToArray(); if (IsPropertyIgnored(parentType, attributes) == false) { JsonProperty jsonProperty; if (propertyType.Name == "Nullable`1") { propertyType = propertyType.GenericTypeArguments[0]; } var useSchemaReference = !propertyTypeDescription.IsDictionary && (propertyTypeDescription.Type.HasFlag(JsonObjectType.Object) || propertyTypeDescription.IsEnum); if (useSchemaReference) { // schema is automatically added to Definitions if it is missing in JsonPathUtilities.GetJsonPath() var propertySchema = Generate(propertyType, rootSchema, property.GetCustomAttributes(), schemaDefinitionAppender, schemaResolver); if (Settings.NullHandling == NullHandling.JsonSchema) { jsonProperty = new JsonProperty(); jsonProperty.OneOf.Add(new JsonSchema4 { SchemaReference = propertySchema.ActualSchema }); } else { jsonProperty = new JsonProperty { SchemaReference = propertySchema.ActualSchema }; } } else { jsonProperty = Generate <JsonProperty>(propertyType, rootSchema, property.GetCustomAttributes(), schemaDefinitionAppender, schemaResolver); propertyTypeDescription.ApplyType(jsonProperty); } var propertyName = JsonPathUtilities.GetPropertyName(property); parentSchema.Properties.Add(propertyName, jsonProperty); var requiredAttribute = TryGetAttribute(attributes, "System.ComponentModel.DataAnnotations.RequiredAttribute"); var jsonPropertyAttribute = property.GetCustomAttribute <JsonPropertyAttribute>(); var hasJsonNetAttributeRequired = jsonPropertyAttribute != null && ( jsonPropertyAttribute.Required == Required.Always || jsonPropertyAttribute.Required == Required.AllowNull); var hasRequiredAttribute = requiredAttribute != null; if (hasRequiredAttribute || hasJsonNetAttributeRequired) { parentSchema.RequiredProperties.Add(propertyName); } var isJsonNetAttributeNullable = jsonPropertyAttribute != null && jsonPropertyAttribute.Required == Required.AllowNull; var isNullable = !hasRequiredAttribute && (propertyTypeDescription.IsNullable || isJsonNetAttributeNullable); if (isNullable) { if (Settings.NullHandling == NullHandling.JsonSchema) { if (useSchemaReference) { jsonProperty.OneOf.Add(new JsonSchema4 { Type = JsonObjectType.Null }); } else { jsonProperty.Type = jsonProperty.Type | JsonObjectType.Null; } } } else if (Settings.NullHandling == NullHandling.Swagger) { if (!parentSchema.RequiredProperties.Contains(propertyName)) { parentSchema.RequiredProperties.Add(propertyName); } } dynamic readOnlyAttribute = TryGetAttribute(attributes, "System.ComponentModel.ReadOnlyAttribute"); if (readOnlyAttribute != null) { jsonProperty.IsReadOnly = readOnlyAttribute.IsReadOnly; } jsonProperty.Description = GetDescription(property, attributes); ApplyPropertyAnnotations(jsonProperty, attributes, propertyTypeDescription); } }
/// <summary>Generates a <see cref="JsonSchema4" /> object for the given type and adds the mapping to the given resolver.</summary> /// <param name="type">The type.</param> /// <param name="schemaResolver"></param> /// <param name="schemaDefinitionAppender"></param> /// <returns>The schema.</returns> /// <exception cref="InvalidOperationException">Could not find value type of dictionary type.</exception> public JsonSchema4 Generate(Type type, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { return(Generate <JsonSchema4>(type, null, schemaResolver, schemaDefinitionAppender)); }
/// <summary>Generates a <see cref="JsonSchema4" /> object for the given type and adds the mapping to the given resolver.</summary> /// <param name="type">The type.</param> /// <param name="rootSchema">The root schema.</param> /// <param name="parentAttributes">The parent property or parameter attributes.</param> /// <param name="schemaDefinitionAppender">The schema definition appender.</param> /// <param name="schemaResolver">The schema resolver.</param> /// <returns>The schema.</returns> /// <exception cref="InvalidOperationException">Could not find value type of dictionary type.</exception> public JsonSchema4 Generate(Type type, JsonSchema4 rootSchema, IEnumerable <Attribute> parentAttributes, ISchemaDefinitionAppender schemaDefinitionAppender, ISchemaResolver schemaResolver) { return(Generate <JsonSchema4>(type, rootSchema, parentAttributes, schemaDefinitionAppender, schemaResolver)); }
/// <summary>Generates the properties for the given type and schema.</summary> /// <typeparam name="TSchemaType">The type of the schema type.</typeparam> /// <param name="type">The types.</param> /// <param name="schema">The properties</param> /// <param name="schemaResolver"></param> /// <param name="schemaDefinitionAppender"></param> protected override void GenerateObject <TSchemaType>(Type type, TSchemaType schema, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender) { if (_isRootType) { _isRootType = false; base.GenerateObject(type, schema, schemaResolver, schemaDefinitionAppender); _isRootType = true; } else { if (!schemaResolver.HasSchema(type, false)) { _isRootType = true; Generate(type, schemaResolver, schemaDefinitionAppender); _isRootType = false; } schema.SchemaReference = schemaResolver.GetSchema(type, false); } }
private static void UpdateSchemaReferencePaths(object root, object obj, List <object> checkedObjects, ISchemaDefinitionAppender schemaDefinitionAppender) { if (obj == null || obj is string) { return; } var schema = obj as JsonSchema4; if (schema != null && schema.SchemaReference != null) { schema.SchemaReferencePath = JsonPathUtilities.GetJsonPath(root, schema.SchemaReference.ActualSchema, schemaDefinitionAppender); } if (obj is IDictionary) { foreach (var item in ((IDictionary)obj).Values.OfType <object>().ToList()) { UpdateSchemaReferencePaths(root, item, checkedObjects, schemaDefinitionAppender); } } else if (obj is IEnumerable) { foreach (var item in (IEnumerable)obj) { UpdateSchemaReferencePaths(root, item, checkedObjects, schemaDefinitionAppender); } } else { foreach (var property in obj.GetType().GetRuntimeProperties().Where(p => p.CanRead && p.GetCustomAttribute <JsonIgnoreAttribute>() == null)) { var value = property.GetValue(obj); if (value != null) { if (!checkedObjects.Contains(value)) { checkedObjects.Add(value); UpdateSchemaReferencePaths(root, value, checkedObjects, schemaDefinitionAppender); } } } } }