コード例 #1
0
        /// <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))));
        }
コード例 #2
0
        /// <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));
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        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);
        }
コード例 #5
0
ファイル: TypeUtility.cs プロジェクト: science-docs/Scriber
        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);
        }
コード例 #6
0
        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);
        }
コード例 #7
0
        /// <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
        }
コード例 #8
0
        /// <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))));
        }
コード例 #9
0
        /// <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)))));
        }
コード例 #10
0
        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);
        }
コード例 #11
0
        /// <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);
            }
        }
コード例 #12
0
 /// <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();
コード例 #13
0
 /// <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;
コード例 #14
0
        /// <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);
        }
コード例 #15
0
 public override JsonTypeDescription GetDescription(ContextualType contextualType,
                                                    ReferenceTypeNullHandling defaultReferenceTypeNullHandling, JsonSchemaGeneratorSettings settings)
 {
     return(base.GetDescription(contextualType, defaultReferenceTypeNullHandling, settings));
 }
コード例 #16
0
 public override bool IsStringEnum(ContextualType contextualType, JsonSerializerSettings serializerSettings)
 {
     return(base.IsStringEnum(contextualType, serializerSettings));
 }
コード例 #17
0
 /// <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));
 }
コード例 #18
0
 private JsonTypeDescription(ContextualType type, JsonObjectType jsonType, bool isNullable)
 {
     ContextualType = type;
     Type           = jsonType;
     IsNullable     = isNullable;
 }
コード例 #19
0
 public Boolean IsNullableValueType(ContextualType contextualType) => contextualType.IsNullableType;
コード例 #20
0
        /// <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);
        }
コード例 #21
0
 /// <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");
 }
コード例 #22
0
        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);
        }
コード例 #23
0
        /// <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));
        }
コード例 #24
0
        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);
        }