Ejemplo n.º 1
0
        private void ParseModel(IDictionary <string, SwaggerModel> models, Type modelType, string route, string verb)
        {
            if (IsSwaggerScalarType(modelType) || modelType.ExcludesFeature(Feature.Metadata))
            {
                return;
            }

            var modelId = GetModelTypeName(modelType, route, verb);

            if (models.ContainsKey(modelId))
            {
                return;
            }

            var modelTypeName = GetModelTypeName(modelType);
            var model         = new SwaggerModel
            {
                Id          = modelId,
                Description = modelType.GetDescription() ?? modelTypeName,
                Properties  = new OrderedDictionary <string, SwaggerProperty>()
            };

            models[model.Id] = model;

            var properties = modelType.GetProperties();

            // Order model properties by DataMember.Order if [DataContract] and [DataMember](s) defined
            // Ordering defined by: http://msdn.microsoft.com/en-us/library/ms729813.aspx
            var dataContractAttr = modelType.FirstAttribute <DataContractAttribute>();

            if (dataContractAttr != null && properties.Any(prop => prop.IsDefined(typeof(DataMemberAttribute), true)))
            {
                var typeOrder = new List <Type> {
                    modelType
                };
                var baseType = modelType.BaseType;
                while (baseType != null)
                {
                    typeOrder.Add(baseType);
                    baseType = baseType.BaseType;
                }

                var propsWithDataMember = properties.Where(prop => prop.IsDefined(typeof(DataMemberAttribute), true));
                var propDataMemberAttrs = properties.ToDictionary(prop => prop, prop => prop.FirstAttribute <DataMemberAttribute>());

                properties = propsWithDataMember
                             .OrderBy(prop => propDataMemberAttrs[prop].Order)                // Order by DataMember.Order
                             .ThenByDescending(prop => typeOrder.IndexOf(prop.DeclaringType)) // Then by BaseTypes First
                             .ThenBy(prop =>                                                  // Then by [DataMember].Name / prop.Name
                {
                    var name = propDataMemberAttrs[prop].Name;
                    return(name.IsNullOrEmpty() ? prop.Name : name);
                }).ToArray();
            }

            var parseProperties = modelType.IsUserType();

            if (parseProperties)
            {
                foreach (var prop in properties)
                {
                    if (prop.HasAttribute <IgnoreDataMemberAttribute>())
                    {
                        continue;
                    }

                    var apiMembers = prop
                                     .AllAttributes <ApiMemberAttribute>()
                                     .OrderByDescending(attr => attr.Route)
                                     .ToList();
                    var apiDoc = apiMembers
                                 .Where(attr => string.IsNullOrEmpty(verb) || string.IsNullOrEmpty(attr.Verb) || (verb ?? "").Equals(attr.Verb))
                                 .Where(attr => string.IsNullOrEmpty(route) || string.IsNullOrEmpty(attr.Route) || (route ?? "").StartsWith(attr.Route))
                                 .FirstOrDefault(attr => attr.ParameterType == "body" || attr.ParameterType == "model");

                    if (apiMembers.Any(x => x.ExcludeInSchema))
                    {
                        continue;
                    }

                    var propertyType = prop.PropertyType;
                    var modelProp    = new SwaggerProperty
                    {
                        Type        = GetSwaggerTypeName(propertyType, route, verb),
                        Description = prop.GetDescription(),
                    };

                    if ((propertyType.IsValueType && !IsNullable(propertyType)) || apiMembers.Any(x => x.IsRequired))
                    {
                        if (model.Required == null)
                        {
                            model.Required = new List <string>();
                        }

                        model.Required.Add(prop.Name);
                    }

                    if (IsListType(propertyType))
                    {
                        modelProp.Type = SwaggerType.Array;
                        var listItemType = GetListElementType(propertyType);
                        modelProp.Items = new Dictionary <string, string> {
                            { IsSwaggerScalarType(listItemType)
                                ? "type"
                                : "$ref", GetSwaggerTypeName(listItemType, route, verb) }
                        };
                        ParseModel(models, listItemType, route, verb);
                    }
                    else if ((Nullable.GetUnderlyingType(propertyType) ?? propertyType).IsEnum)
                    {
                        var enumType = Nullable.GetUnderlyingType(propertyType) ?? propertyType;
                        if (enumType.IsNumericType())
                        {
                            var underlyingType = Enum.GetUnderlyingType(enumType);
                            modelProp.Type = GetSwaggerTypeName(underlyingType, route, verb);
                            modelProp.Enum = GetNumericValues(enumType, underlyingType).ToList();
                        }
                        else
                        {
                            modelProp.Type = SwaggerType.String;
                            modelProp.Enum = Enum.GetNames(enumType).ToList();
                        }
                    }
                    else
                    {
                        ParseModel(models, propertyType, route, verb);

                        var propAttr = prop.FirstAttribute <ApiMemberAttribute>();
                        if (propAttr != null)
                        {
                            if (propAttr.DataType != null)
                            {
                                modelProp.Type = propAttr.DataType;
                            }
                            if (propAttr.Format != null)
                            {
                                modelProp.Format = propAttr.Format;
                            }
                        }
                    }

                    if (apiDoc != null && modelProp.Description == null)
                    {
                        modelProp.Description = apiDoc.Description;
                    }

                    var allowableValues = prop.FirstAttribute <ApiAllowableValuesAttribute>();
                    if (allowableValues != null)
                    {
                        modelProp.Enum = GetEnumValues(allowableValues);
                    }

                    ModelPropertyFilter?.Invoke(modelProp);

                    model.Properties[GetModelPropertyName(prop)] = modelProp;
                }
            }

            ModelFilter?.Invoke(model);
        }