/// <summary>Checks whether the given type is a dictionary type.</summary> /// <param name="contextualType">The type.</param> /// <returns>true or false.</returns> protected virtual bool IsDictionaryType(ContextualType contextualType) { if (contextualType.TypeName == "IDictionary`2" || contextualType.TypeName == "IReadOnlyDictionary`2") { return(true); } return(contextualType.TypeInfo.ImplementedInterfaces.Contains(typeof(IDictionary)) && (contextualType.TypeInfo.BaseType == null || !contextualType.TypeInfo.BaseType.GetTypeInfo().ImplementedInterfaces.Contains(typeof(IDictionary)))); }
/// <summary>Checks whether the give type is a string enum.</summary> /// <param name="contextualType">The type.</param> /// <param name="serializerSettings">The serializer settings.</param> /// <returns>The result.</returns> public virtual bool IsStringEnum(ContextualType contextualType, JsonSerializerSettings serializerSettings) { if (!contextualType.TypeInfo.IsEnum) { return(false); } var hasGlobalStringEnumConverter = serializerSettings.Converters.OfType <StringEnumConverter>().Any(); return(hasGlobalStringEnumConverter || HasStringEnumConverter(contextualType)); }
private bool HasStringEnumConverter(ContextualType contextualType) { dynamic jsonConverterAttribute = contextualType.Attributes?.FirstOrDefault(a => a.GetType().Name == "JsonConverterAttribute"); if (jsonConverterAttribute != null && ObjectExtensions.HasProperty(jsonConverterAttribute, "ConverterType")) { var converterType = (Type)jsonConverterAttribute.ConverterType; return(converterType.IsAssignableToTypeName("StringEnumConverter", TypeNameStyle.Name)); } return(false); }
private OpenApiParameter CreatePrimitiveOpenApiParameter(ContextualType contextualParameter, JsonTypeDescription typeDescription) { OpenApiParameter operationParameter; if (typeDescription.RequiresSchemaReference(_settings.TypeMappers)) { operationParameter = new OpenApiParameter(); operationParameter.Schema = new JsonSchema(); _settings.SchemaGenerator.ApplyDataAnnotations(operationParameter.Schema, typeDescription); var referencedSchema = _settings.SchemaGenerator.Generate(contextualParameter, _schemaResolver); var hasSchemaAnnotations = JsonConvert.SerializeObject(operationParameter.Schema) != "{}"; if (hasSchemaAnnotations || typeDescription.IsNullable) { operationParameter.Schema.IsNullableRaw = true; if (_settings.AllowReferencesWithProperties) { operationParameter.Schema.Reference = referencedSchema.ActualSchema; } else { operationParameter.Schema.OneOf.Add(new JsonSchema { Reference = referencedSchema.ActualSchema }); } } else { operationParameter.Schema = new JsonSchema { Reference = referencedSchema.ActualSchema }; } } else { operationParameter = new OpenApiParameter(); operationParameter.Schema = _settings.SchemaGenerator.GenerateWithReferenceAndNullability <JsonSchema>( contextualParameter, typeDescription.IsNullable, _schemaResolver); _settings.SchemaGenerator.ApplyDataAnnotations(operationParameter.Schema, typeDescription); } if (typeDescription.Type.HasFlag(JsonObjectType.Array)) { operationParameter.Style = OpenApiParameterStyle.Form; operationParameter.Explode = true; } return(operationParameter); }
public static bool IsNullable(this ContextualType type) { if (type.Nullability != Nullability.NotNullable) { return(true); } var origType = type.OriginalType; if (Argument.IsArgumentType(origType)) { type = type.GenericArguments[0]; } return(type.Nullability != Nullability.NotNullable); }
private ContentDescriptor Generate(ContextualType type, string id, IJsonRpcSerializer serializer, bool isRequired) { var schema = schemaGenerator.GenerateSchema(type, serializer); var contentDescriptor = new ContentDescriptor { Name = id, Schema = schema, Required = isRequired, Description = type.GetXmlDocsRemarks(), // dont get confused: Description is taken from "remarks" tag; Summary = type.GetDescription(), // Summary is taken from attributes or "summary" tag (method should be named "GetSummary"?) Deprecated = type.GetAttribute <ObsoleteAttribute>() != null }; return(contentDescriptor); }
/// <summary>Checks whether the given type is a file/binary type.</summary> /// <param name="contextualType">The type.</param> /// <returns>true or false.</returns> protected virtual bool IsBinary(ContextualType contextualType) { // TODO: Move all file handling to NSwag. How? var parameterTypeName = contextualType.TypeName; return(parameterTypeName == "IFormFile" || contextualType.IsAssignableToTypeName("HttpPostedFile", TypeNameStyle.Name) || contextualType.IsAssignableToTypeName("HttpPostedFileBase", TypeNameStyle.Name) || #if !LEGACY contextualType.TypeInfo.ImplementedInterfaces.Any(i => i.Name == "IFormFile")); #else contextualType.TypeInfo.GetInterfaces().Any(i => i.Name == "IFormFile"); #endif }
/// <summary>Checks whether the given type is a dictionary type.</summary> /// <param name="contextualType">The type.</param> /// <returns>true or false.</returns> protected virtual bool IsDictionaryType(ContextualType contextualType) { bool IsDictionaryInterface(Type type) { return(type == typeof(IDictionary) || (type.IsConstructedGenericType && (type.GetGenericTypeDefinition() == typeof(IDictionary <,>) || type.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary <,>)))); } if (contextualType.TypeName == "IDictionary`2" || contextualType.TypeName == "IReadOnlyDictionary`2") { return(true); } return(contextualType.TypeInfo.ImplementedInterfaces.Any(IsDictionaryInterface) && (contextualType.TypeInfo.BaseType == null || !contextualType.TypeInfo.BaseType.GetTypeInfo().ImplementedInterfaces.Contains(typeof(IDictionary)))); }
/// <summary>Checks whether the given type is an array type.</summary> /// <param name="contextualType">The type.</param> /// <returns>true or false.</returns> protected virtual bool IsArrayType(ContextualType contextualType) { if (IsDictionaryType(contextualType)) { return(false); } if (contextualType.TypeName == "ObservableCollection`1") { return(true); } return(contextualType.Type.IsArray || (contextualType.TypeInfo.ImplementedInterfaces.Contains(typeof(IEnumerable)) && (contextualType.TypeInfo.BaseType == null || !contextualType.TypeInfo.BaseType.GetTypeInfo().ImplementedInterfaces.Contains(typeof(IEnumerable))))); }
private OpenApiParameter CreatePrimitiveSwaggerParameter(ContextualType contextualParameter, JsonTypeDescription typeDescription) { OpenApiParameter operationParameter; if (typeDescription.RequiresSchemaReference(_settings.TypeMappers)) { var referencedSchema = _settings.SchemaGenerator.Generate(contextualParameter, _schemaResolver); operationParameter = new OpenApiParameter { Type = typeDescription.Type, CustomSchema = new JsonSchema { Reference = referencedSchema.ActualSchema } }; // Copy enumeration for compatibility with other tools which do not understand x-schema. // The enumeration will be ignored by NSwag and only the x-schema is processed if (referencedSchema.ActualSchema.IsEnumeration) { operationParameter.Enumeration.Clear(); foreach (var item in referencedSchema.ActualSchema.Enumeration) { operationParameter.Enumeration.Add(item); } } _settings.SchemaGenerator.ApplyDataAnnotations(operationParameter, typeDescription); } else { operationParameter = _settings.SchemaGenerator.Generate <OpenApiParameter>(contextualParameter, _schemaResolver); _settings.SchemaGenerator.ApplyDataAnnotations(operationParameter, typeDescription); } if (typeDescription.Type.HasFlag(JsonObjectType.Array)) { operationParameter.CollectionFormat = OpenApiParameterCollectionFormat.Multi; } return(operationParameter); }
/// <summary>Generates XMLObject structure for a property.</summary> /// <param name="propertySchema">The JSON Schema for the property</param> /// <param name="type">The type.</param> /// <param name="propertyName">The property name.</param> public static void GenerateXmlObjectForProperty(this JsonSchemaProperty propertySchema, ContextualType type, string propertyName) { string xmlName = null; string xmlNamespace = null; bool xmlWrapped = false; if (propertySchema.IsArray) { dynamic xmlArrayAttribute = type.Attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlArrayAttribute"); if (xmlArrayAttribute != null) { xmlName = xmlArrayAttribute.ElementName; xmlNamespace = xmlArrayAttribute.Namespace; } dynamic xmlArrayItemsAttribute = type.Attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlArrayItemAttribute"); if (xmlArrayItemsAttribute != null) { var xmlItemName = xmlArrayItemsAttribute.ElementName; var xmlItemNamespace = xmlArrayItemsAttribute.Namespace; GenerateXmlObject(xmlItemName, xmlItemNamespace, true, false, propertySchema.Item); } xmlWrapped = true; } dynamic xmlElementAttribute = type.Attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlElementAttribute"); if (xmlElementAttribute != null) { xmlName = xmlElementAttribute.ElementName; xmlNamespace = xmlElementAttribute.Namespace; } dynamic xmlAttribute = type.Attributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlAttributeAttribute"); if (xmlAttribute != null) { if (!string.IsNullOrEmpty(xmlAttribute.AttributeName)) { xmlName = xmlAttribute.AttributeName; } if (!string.IsNullOrEmpty(xmlAttribute.Namespace)) { xmlNamespace = xmlAttribute.Namespace; } } // Due to that the JSON Reference is used, the xml name from the referenced type will be copied to the property. // We need to ensure that the property name is preserved if (string.IsNullOrEmpty(xmlName) && propertySchema.Type == JsonObjectType.None) { dynamic xmlReferenceTypeAttribute = type.TypeAttributes.FirstAssignableToTypeNameOrDefault("System.Xml.Serialization.XmlTypeAttribute"); if (xmlReferenceTypeAttribute != null) { xmlName = propertyName; } } if (!string.IsNullOrEmpty(xmlName) || xmlWrapped) { GenerateXmlObject(xmlName, xmlNamespace, xmlWrapped, xmlAttribute != null ? true : false, propertySchema); } }
/// <summary> /// Extracts the generic arguments from the tuple contextual type. /// </summary> /// <param name="contextualType">The contextual type for a ValueTuple type.</param> /// <returns>Returns the generic arguments from the tuple contextual type.</returns> public static ContextualType[] GetTupleArguments(this ContextualType contextualType) => contextualType.EnumerateFlattenTupleArguments().ToArray();
/// <summary> /// Extracts the tuple element names if provided. /// </summary> /// <param name="contextualType">The contextual type for a ValueTuple type.</param> /// <returns>Returns the tuple element names or null.</returns> public static IList <String?>?GetTupleElementNames(this ContextualType contextualType) => contextualType.GetContextAttribute <TupleElementNamesAttribute>()?.TransformNames;
/// <summary>Creates a primitive parameter for the given parameter information reflection object.</summary> /// <param name="name">The name.</param> /// <param name="description">The description.</param> /// <param name="contextualParameter">Type of the parameter.</param> /// <returns>The parameter.</returns> public OpenApiParameter CreatePrimitiveParameter(string name, string description, ContextualType contextualParameter) { var typeDescription = _settings.ReflectionService.GetDescription(contextualParameter, _settings); var operationParameter = _settings.SchemaType == SchemaType.Swagger2 ? CreatePrimitiveSwaggerParameter(contextualParameter, typeDescription) : CreatePrimitiveOpenApiParameter(contextualParameter, typeDescription); operationParameter.Name = name; operationParameter.IsRequired = contextualParameter.ContextAttributes.FirstAssignableToTypeNameOrDefault("RequiredAttribute", TypeNameStyle.Name) != null; if (typeDescription.Type.HasFlag(JsonObjectType.Array)) { operationParameter.CollectionFormat = OpenApiParameterCollectionFormat.Multi; } operationParameter.IsNullableRaw = typeDescription.IsNullable; if (description != string.Empty) { operationParameter.Description = description; } return(operationParameter); }
public override JsonTypeDescription GetDescription(ContextualType contextualType, ReferenceTypeNullHandling defaultReferenceTypeNullHandling, JsonSchemaGeneratorSettings settings) { return(base.GetDescription(contextualType, defaultReferenceTypeNullHandling, settings)); }
public override bool IsStringEnum(ContextualType contextualType, JsonSerializerSettings serializerSettings) { return(base.IsStringEnum(contextualType, serializerSettings)); }
/// <summary>Creates a <see cref="JsonTypeDescription"/> from a <see cref="Type"/>. </summary> /// <param name="contextualType">The type.</param> /// <param name="settings">The settings.</param> /// <returns>The <see cref="JsonTypeDescription"/>. </returns> public JsonTypeDescription GetDescription(ContextualType contextualType, JsonSchemaGeneratorSettings settings) { return(GetDescription(contextualType, settings.DefaultReferenceTypeNullHandling, settings)); }
private JsonTypeDescription(ContextualType type, JsonObjectType jsonType, bool isNullable) { ContextualType = type; Type = jsonType; IsNullable = isNullable; }
public Boolean IsNullableValueType(ContextualType contextualType) => contextualType.IsNullableType;
/// <summary>Creates a primitive parameter for the given parameter information reflection object.</summary> /// <param name="name">The name.</param> /// <param name="description">The description.</param> /// <param name="contextualParameter">Type of the parameter.</param> /// <returns>The parameter.</returns> public OpenApiParameter CreatePrimitiveParameter( string name, string description, ContextualType contextualParameter) { OpenApiParameter operationParameter; var typeDescription = _settings.ReflectionService.GetDescription(contextualParameter, _settings); if (typeDescription.RequiresSchemaReference(_settings.TypeMappers)) { var schema = _settings.SchemaGenerator .Generate(contextualParameter, _schemaResolver); operationParameter = new OpenApiParameter(); if (_settings.SchemaType == SchemaType.Swagger2) { operationParameter.Type = typeDescription.Type; operationParameter.CustomSchema = new JsonSchema { Reference = schema.ActualSchema }; // Copy enumeration for compatibility with other tools which do not understand x-schema. // The enumeration will be ignored by NSwag and only the x-schema is processed if (schema.ActualSchema.IsEnumeration) { operationParameter.Enumeration.Clear(); foreach (var item in schema.ActualSchema.Enumeration) { operationParameter.Enumeration.Add(item); } } } else { if (typeDescription.IsNullable) { operationParameter.Schema = new JsonSchema { IsNullableRaw = true }; operationParameter.Schema.OneOf.Add(new JsonSchema { Reference = schema.ActualSchema }); } else { operationParameter.Schema = new JsonSchema { Reference = schema.ActualSchema }; } } } else { if (_settings.SchemaType == SchemaType.Swagger2) { operationParameter = _settings.SchemaGenerator .Generate <OpenApiParameter>(contextualParameter, _schemaResolver); } else { operationParameter = new OpenApiParameter { Schema = _settings.SchemaGenerator .GenerateWithReferenceAndNullability <JsonSchema>( contextualParameter, typeDescription.IsNullable, _schemaResolver) }; } } operationParameter.Name = name; operationParameter.IsRequired = contextualParameter.ContextAttributes.FirstAssignableToTypeNameOrDefault("RequiredAttribute", TypeNameStyle.Name) != null; if (typeDescription.Type.HasFlag(JsonObjectType.Array)) { operationParameter.CollectionFormat = OpenApiParameterCollectionFormat.Multi; } operationParameter.IsNullableRaw = typeDescription.IsNullable; _settings.SchemaGenerator.ApplyDataAnnotations(operationParameter, contextualParameter, typeDescription); if (description != string.Empty) { operationParameter.Description = description; } return(operationParameter); }
/// <summary>Checks whether the given type is an IAsyncEnumerable type.</summary> /// <remarks> /// See this issue: https://github.com/RicoSuter/NSwag/issues/2582#issuecomment-576165669 /// </remarks> /// <param name="contextualType">The type.</param> /// <returns>true or false.</returns> private bool IsIAsyncEnumerableType(ContextualType contextualType) { return(contextualType.TypeName == "IAsyncEnumerable`1"); }
public TypeNode ReadType(ContextualType contextualType, AssemblyNode assembly, Type[] parents, ActionNode actionNode) { var typeNode = new TypeNode(); if (contextualType.Nullability == Nullability.Nullable) { typeNode.IsNullable = true; } for (;;) { if (contextualType.GenericArguments.Length > 0) { if (contextualType.Type.ImplementsInterface(typeof(IDictionary <,>))) { typeNode.Modifiers.Add(TypeModifier.Dictionary); contextualType = contextualType.GenericArguments[1]; } else if (contextualType.Type.ImplementsInterface(typeof(IEnumerable <>))) { typeNode.Modifiers.Add(TypeModifier.Array); contextualType = contextualType.GenericArguments[0]; } else if (contextualType.Type.GetGenericTypeDefinition() == typeof(Optional <>)) { typeNode.IsOptional = true; contextualType = contextualType.GenericArguments[0]; } else { break; } } else if (contextualType.Type.IsArray) { typeNode.Modifiers.Add(TypeModifier.Array); if (contextualType.ElementType == null) { break; } contextualType = contextualType.ElementType; } else { break; } } var parameterType = contextualType.Type; if (parameterType.GetTypeInfo().IsGenericType) { typeNode.GenericParameters = contextualType.GenericArguments.Select(x => ReadType(x, assembly, parents, actionNode)).ToList(); parameterType = parameterType.GetGenericTypeDefinition(); } if (parameterType.GetTypeInfo().IsEnum) { typeNode.Type = TypeIdentifier.Enum; typeNode.Class = ReadClass(parameterType, assembly, actionNode, parents); } else if (parameterType == typeof(string)) { typeNode.Type = TypeIdentifier.String; } else if (parameterType == typeof(long)) { typeNode.Type = TypeIdentifier.Long; } else if (parameterType == typeof(int) || parameterType == typeof(short)) { typeNode.Type = TypeIdentifier.Int; } else if (parameterType == typeof(float)) { typeNode.Type = TypeIdentifier.Float; } else if (parameterType == typeof(byte)) { typeNode.Type = TypeIdentifier.Byte; } else if (parameterType == typeof(double)) { typeNode.Type = TypeIdentifier.Double; } else if (parameterType == typeof(DateTime)) { typeNode.Type = TypeIdentifier.DateTime; } else if (parameterType == typeof(bool)) { typeNode.Type = TypeIdentifier.Boolean; } else if (parameterType == typeof(decimal)) { typeNode.Type = TypeIdentifier.Decimal; } else if (parameterType == typeof(Guid)) { typeNode.Type = TypeIdentifier.Guid; } else if (parameterType == typeof(TimeSpan)) { typeNode.Type = TypeIdentifier.TimeSpan; } else if (parameterType == typeof(object)) { typeNode.Type = TypeIdentifier.Any; } else if (parameterType.IsGenericParameter) { typeNode.Type = TypeIdentifier.GenericParameter; typeNode.GenericName = parameterType.Name; } else { typeNode.Type = TypeIdentifier.Object; typeNode.Class = ReadClass(parameterType, assembly, actionNode, parents); } return(typeNode); }
/// <summary>Creates a <see cref="JsonTypeDescription"/> from a <see cref="Type"/>. </summary> /// <param name="contextualType">The type.</param> /// <param name="defaultReferenceTypeNullHandling">The default reference type null handling used when no nullability information is available.</param> /// <param name="settings">The settings.</param> /// <returns>The <see cref="JsonTypeDescription"/>. </returns> public virtual JsonTypeDescription GetDescription(ContextualType contextualType, ReferenceTypeNullHandling defaultReferenceTypeNullHandling, JsonSchemaGeneratorSettings settings) { var type = contextualType.OriginalType; var isNullable = IsNullable(contextualType, defaultReferenceTypeNullHandling); var jsonSchemaTypeAttribute = contextualType.GetAttribute <JsonSchemaTypeAttribute>(); if (jsonSchemaTypeAttribute != null) { type = jsonSchemaTypeAttribute.Type; contextualType = type.ToContextualType(); if (jsonSchemaTypeAttribute.IsNullableRaw.HasValue) { isNullable = jsonSchemaTypeAttribute.IsNullableRaw.Value; } } var jsonSchemaAttribute = contextualType.GetAttribute <JsonSchemaAttribute>(); if (jsonSchemaAttribute != null) { var classType = jsonSchemaAttribute.Type != JsonObjectType.None ? jsonSchemaAttribute.Type : JsonObjectType.Object; var format = !string.IsNullOrEmpty(jsonSchemaAttribute.Format) ? jsonSchemaAttribute.Format : null; return(JsonTypeDescription.Create(contextualType, classType, isNullable, format)); } if (type.GetTypeInfo().IsEnum) { var isStringEnum = IsStringEnum(contextualType, settings.ActualSerializerSettings); return(JsonTypeDescription.CreateForEnumeration(contextualType, isStringEnum ? JsonObjectType.String : JsonObjectType.Integer, false)); } // Primitive types if (type == typeof(short) || type == typeof(uint) || type == typeof(ushort)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.Integer, false, null)); } if (type == typeof(int)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.Integer, false, JsonFormatStrings.Integer)); } if (type == typeof(long) || type == typeof(ulong)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.Integer, false, JsonFormatStrings.Long)); } if (type == typeof(double)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.Number, false, JsonFormatStrings.Double)); } if (type == typeof(float)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.Number, false, JsonFormatStrings.Float)); } if (type == typeof(decimal)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.Number, false, JsonFormatStrings.Decimal)); } if (type == typeof(bool)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.Boolean, false, null)); } if (type == typeof(string) || type == typeof(Type)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, isNullable, null)); } if (type == typeof(char)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, false, null)); } if (type == typeof(Guid)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, false, JsonFormatStrings.Guid)); } // Date & time types if (type == typeof(DateTime) || type == typeof(DateTimeOffset) || type.FullName == "NodaTime.OffsetDateTime" || type.FullName == "NodaTime.LocalDateTime" || type.FullName == "NodaTime.ZonedDateTime" || type.FullName == "NodaTime.Instant") { return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, false, JsonFormatStrings.DateTime)); } if (type == typeof(TimeSpan) || type.FullName == "NodaTime.Duration") { return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, false, JsonFormatStrings.TimeSpan)); } if (type.FullName == "NodaTime.LocalDate") { return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, false, JsonFormatStrings.Date)); } if (type.FullName == "NodaTime.LocalTime") { return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, false, JsonFormatStrings.Time)); } // Special types if (type == typeof(Uri)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, isNullable, JsonFormatStrings.Uri)); } if (type == typeof(byte)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.Integer, false, JsonFormatStrings.Byte)); } if (type == typeof(byte[])) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, isNullable, JsonFormatStrings.Byte)); } if (type.IsAssignableToTypeName(nameof(JArray), TypeNameStyle.Name)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.Array, isNullable, null)); } if (type.IsAssignableToTypeName(nameof(JToken), TypeNameStyle.Name) || type.FullName == "System.Dynamic.ExpandoObject" || type.FullName == "System.Text.Json.JsonElement" || type == typeof(object)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.None, isNullable, null)); } if (IsBinary(contextualType)) { if (settings.SchemaType == SchemaType.Swagger2) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.File, isNullable, null)); } else { return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, isNullable, JsonFormatStrings.Binary)); } } if (contextualType.IsNullableType) { var typeDescription = GetDescription(contextualType.OriginalGenericArguments[0], defaultReferenceTypeNullHandling, settings); typeDescription.IsNullable = true; return(typeDescription); } var contract = settings.ResolveContract(type); if (IsDictionaryType(contextualType) && contract is JsonDictionaryContract) { return(JsonTypeDescription.CreateForDictionary(contextualType, JsonObjectType.Object, isNullable)); } // TODO: Don't trust JsonArrayContract when contextualType is IAsyncEnumerable<T> until it is fixed if (IsIAsyncEnumerableType(contextualType) || (IsArrayType(contextualType) && contract is JsonArrayContract)) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.Array, isNullable, null)); } if (contract is JsonStringContract) { return(JsonTypeDescription.Create(contextualType, JsonObjectType.String, isNullable, null)); } return(JsonTypeDescription.Create(contextualType, JsonObjectType.Object, isNullable, null)); }
public ActionNode?ReadAction(string routePrefix, MethodInfo methodInfo, ActionsGroupNode actionsGroup) { string? route = null; ActionMethod actionMethod = ActionMethod.Unknown; if (methodInfo.GetCustomAttribute <HttpGetAttribute>() != null) { actionMethod = ActionMethod.Get; route = methodInfo.GetCustomAttribute <HttpGetAttribute>().Template; } else if (methodInfo.GetCustomAttribute <HttpPostAttribute>() != null) { actionMethod = ActionMethod.Post; route = methodInfo.GetCustomAttribute <HttpPostAttribute>().Template; } else if (methodInfo.GetCustomAttribute <HttpPutAttribute>() != null) { actionMethod = ActionMethod.Put; route = methodInfo.GetCustomAttribute <HttpPutAttribute>().Template; } else if (methodInfo.GetCustomAttribute <HttpDeleteAttribute>() != null) { actionMethod = ActionMethod.Delete; route = methodInfo.GetCustomAttribute <HttpDeleteAttribute>().Template; } else if (methodInfo.GetCustomAttribute <HttpPatchAttribute>() != null) { actionMethod = ActionMethod.Patch; route = methodInfo.GetCustomAttribute <HttpPatchAttribute>().Template; } var routeAttribute = methodInfo.GetCustomAttribute <RouteAttribute>(); if (routeAttribute != null) { route = routeAttribute.Template; } if (route == null) { return(null); } if (actionMethod == ActionMethod.Unknown) { if (methodInfo.Name.StartsWith("Get", StringComparison.OrdinalIgnoreCase)) { actionMethod = ActionMethod.Get; } else if (methodInfo.Name.StartsWith("Post", StringComparison.OrdinalIgnoreCase)) { actionMethod = ActionMethod.Post; } else if (methodInfo.Name.StartsWith("Put", StringComparison.OrdinalIgnoreCase)) { actionMethod = ActionMethod.Put; } else if (methodInfo.Name.StartsWith("Delete", StringComparison.OrdinalIgnoreCase)) { actionMethod = ActionMethod.Delete; } else { return(null); } } // Remove type info from route route = Regex.Replace(route, @"{(\w+\??)(?::\w+)?}", "{$1}"); if (route.StartsWith("~")) { route = Regex.Replace(route, @"^~/?", string.Empty); } else { route = $"{routePrefix}/{route}"; } route = route.Replace("[controller]", actionsGroup.Name); var actionNode = new ActionNode(actionsGroup, methodInfo.Name, route); actionNode.Type = actionMethod; actionNode.Route = route; var versionMatch = Regex.Match(route, @"api/v([\d\.])+"); actionNode.Version = versionMatch.Success ? versionMatch.Groups[1].Value : null; var authorizeAttribute = methodInfo.GetCustomAttribute <AuthorizeAttribute>(); if (authorizeAttribute != null) { actionNode.Authorization = authorizeAttribute.Policy ?? authorizeAttribute.Roles; } // Read documentation var methodNode = documentation.GetMethodDocumentation(methodInfo); var summary = methodNode?.Element("summary"); if (summary != null) { actionNode.Documentation = summary.Value; } Dictionary <string, XElement>?parameterNodes = null; if (methodNode != null) { parameterNodes = methodNode.Elements("param").ToDictionary(x => x.Attribute("name").Value); } var routeParameters = new Dictionary <string, bool>(); var routeParametersMatches = Regex.Matches(route, @"{(\w+)(\?)?(?:\:\w+)?}"); foreach (Match match in routeParametersMatches) { var parameter = match.Groups[1].Value; var optional = match.Groups[2].Value == "?"; routeParameters.Add(parameter, optional); } foreach (var parameterInfo in methodInfo.GetParameters()) { var parameter = ReadParameter(parameterInfo, parameterNodes != null && parameterNodes.ContainsKey(parameterInfo.Name) ? parameterNodes[parameterInfo.Name] : null, actionsGroup.Assembly, routeParameters, actionNode); actionNode.Parameters.Add(parameter); if (parameter.Position == ParameterPosition.Body) { parameter.Type.Class?.SetWritable(); } } ContextualType returnType = methodInfo.ReturnParameter.ToContextualParameter(); if (returnType.Type.IsGenericType && returnType.Type.GetGenericTypeDefinition() == typeof(Task <>)) { returnType = returnType.GenericArguments[0]; } if (returnType.Type.IsGenericType && returnType.Type.GetGenericTypeDefinition() == typeof(ActionResult <>)) { returnType = returnType.GenericArguments[0]; } if (!returnType.Type.GetInterfaces().Contains(typeof(IActionResult)) && returnType.Type != typeof(IActionResult) && returnType.Type != typeof(Task) && returnType.Type != typeof(void)) { var returnDocumentation = methodNode?.Element("returns"); actionNode.Return = ReadReturn(returnType, actionsGroup.Assembly, returnDocumentation, actionNode); } return(actionNode); }