From 03a0d99de9c5fed6bea8bc83b49ce27786bda38c Mon Sep 17 00:00:00 2001
From: tangxu <tangxu76880903>
Date: 星期五, 07 二月 2025 09:29:59 +0800
Subject: [PATCH] 添加OPENAPI接口

---
 WebApi/Areas/HelpPage/ModelDescriptions/ModelDescriptionGenerator.cs |  451 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 451 insertions(+), 0 deletions(-)

diff --git a/WebApi/Areas/HelpPage/ModelDescriptions/ModelDescriptionGenerator.cs b/WebApi/Areas/HelpPage/ModelDescriptions/ModelDescriptionGenerator.cs
new file mode 100644
index 0000000..3ac5ba2
--- /dev/null
+++ b/WebApi/Areas/HelpPage/ModelDescriptions/ModelDescriptionGenerator.cs
@@ -0,0 +1,451 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.ComponentModel.DataAnnotations;
+using System.Globalization;
+using System.Reflection;
+using System.Runtime.Serialization;
+using System.Web.Http;
+using System.Web.Http.Description;
+using System.Xml.Serialization;
+using Newtonsoft.Json;
+
+namespace IStation.WebApi.Areas.HelpPage.ModelDescriptions
+{
+    /// <summary>
+    /// Generates model descriptions for given types.
+    /// </summary>
+    public class ModelDescriptionGenerator
+    {
+        // Modify this to support more data annotation attributes.
+        private readonly IDictionary<Type, Func<object, string>> AnnotationTextGenerator = new Dictionary<Type, Func<object, string>>
+        {
+            { typeof(RequiredAttribute), a => "Required" },
+            { typeof(RangeAttribute), a =>
+                {
+                    RangeAttribute range = (RangeAttribute)a;
+                    return String.Format(CultureInfo.CurrentCulture, "Range: inclusive between {0} and {1}", range.Minimum, range.Maximum);
+                }
+            },
+            { typeof(MaxLengthAttribute), a =>
+                {
+                    MaxLengthAttribute maxLength = (MaxLengthAttribute)a;
+                    return String.Format(CultureInfo.CurrentCulture, "Max length: {0}", maxLength.Length);
+                }
+            },
+            { typeof(MinLengthAttribute), a =>
+                {
+                    MinLengthAttribute minLength = (MinLengthAttribute)a;
+                    return String.Format(CultureInfo.CurrentCulture, "Min length: {0}", minLength.Length);
+                }
+            },
+            { typeof(StringLengthAttribute), a =>
+                {
+                    StringLengthAttribute strLength = (StringLengthAttribute)a;
+                    return String.Format(CultureInfo.CurrentCulture, "String length: inclusive between {0} and {1}", strLength.MinimumLength, strLength.MaximumLength);
+                }
+            },
+            { typeof(DataTypeAttribute), a =>
+                {
+                    DataTypeAttribute dataType = (DataTypeAttribute)a;
+                    return String.Format(CultureInfo.CurrentCulture, "Data type: {0}", dataType.CustomDataType ?? dataType.DataType.ToString());
+                }
+            },
+            { typeof(RegularExpressionAttribute), a =>
+                {
+                    RegularExpressionAttribute regularExpression = (RegularExpressionAttribute)a;
+                    return String.Format(CultureInfo.CurrentCulture, "Matching regular expression pattern: {0}", regularExpression.Pattern);
+                }
+            },
+        };
+
+        // Modify this to add more default documentations.
+        private readonly IDictionary<Type, string> DefaultTypeDocumentation = new Dictionary<Type, string>
+        {
+            { typeof(Int16), "integer" },
+            { typeof(Int32), "integer" },
+            { typeof(Int64), "integer" },
+            { typeof(UInt16), "unsigned integer" },
+            { typeof(UInt32), "unsigned integer" },
+            { typeof(UInt64), "unsigned integer" },
+            { typeof(Byte), "byte" },
+            { typeof(Char), "character" },
+            { typeof(SByte), "signed byte" },
+            { typeof(Uri), "URI" },
+            { typeof(Single), "decimal number" },
+            { typeof(Double), "decimal number" },
+            { typeof(Decimal), "decimal number" },
+            { typeof(String), "string" },
+            { typeof(Guid), "globally unique identifier" },
+            { typeof(TimeSpan), "time interval" },
+            { typeof(DateTime), "date" },
+            { typeof(DateTimeOffset), "date" },
+            { typeof(Boolean), "boolean" },
+        };
+
+        private Lazy<IModelDocumentationProvider> _documentationProvider;
+
+        public ModelDescriptionGenerator(HttpConfiguration config)
+        {
+            if (config == null)
+            {
+                throw new ArgumentNullException("config");
+            }
+
+            _documentationProvider = new Lazy<IModelDocumentationProvider>(() => config.Services.GetDocumentationProvider() as IModelDocumentationProvider);
+            GeneratedModels = new Dictionary<string, ModelDescription>(StringComparer.OrdinalIgnoreCase);
+        }
+
+        public Dictionary<string, ModelDescription> GeneratedModels { get; private set; }
+
+        private IModelDocumentationProvider DocumentationProvider
+        {
+            get
+            {
+                return _documentationProvider.Value;
+            }
+        }
+
+        public ModelDescription GetOrCreateModelDescription(Type modelType)
+        {
+            if (modelType == null)
+            {
+                throw new ArgumentNullException("modelType");
+            }
+
+            Type underlyingType = Nullable.GetUnderlyingType(modelType);
+            if (underlyingType != null)
+            {
+                modelType = underlyingType;
+            }
+
+            ModelDescription modelDescription;
+            string modelName = ModelNameHelper.GetModelName(modelType);
+            if (GeneratedModels.TryGetValue(modelName, out modelDescription))
+            {
+                if (modelType != modelDescription.ModelType)
+                {
+                    throw new InvalidOperationException(
+                        String.Format(
+                            CultureInfo.CurrentCulture,
+                            "A model description could not be created. Duplicate model name '{0}' was found for types '{1}' and '{2}'. " +
+                            "Use the [ModelName] attribute to change the model name for at least one of the types so that it has a unique name.",
+                            modelName,
+                            modelDescription.ModelType.FullName,
+                            modelType.FullName));
+                }
+
+                return modelDescription;
+            }
+
+            if (DefaultTypeDocumentation.ContainsKey(modelType))
+            {
+                return GenerateSimpleTypeModelDescription(modelType);
+            }
+
+            if (modelType.IsEnum)
+            {
+                return GenerateEnumTypeModelDescription(modelType);
+            }
+
+            if (modelType.IsGenericType)
+            {
+                Type[] genericArguments = modelType.GetGenericArguments();
+
+                if (genericArguments.Length == 1)
+                {
+                    Type enumerableType = typeof(IEnumerable<>).MakeGenericType(genericArguments);
+                    if (enumerableType.IsAssignableFrom(modelType))
+                    {
+                        return GenerateCollectionModelDescription(modelType, genericArguments[0]);
+                    }
+                }
+                if (genericArguments.Length == 2)
+                {
+                    Type dictionaryType = typeof(IDictionary<,>).MakeGenericType(genericArguments);
+                    if (dictionaryType.IsAssignableFrom(modelType))
+                    {
+                        return GenerateDictionaryModelDescription(modelType, genericArguments[0], genericArguments[1]);
+                    }
+
+                    Type keyValuePairType = typeof(KeyValuePair<,>).MakeGenericType(genericArguments);
+                    if (keyValuePairType.IsAssignableFrom(modelType))
+                    {
+                        return GenerateKeyValuePairModelDescription(modelType, genericArguments[0], genericArguments[1]);
+                    }
+                }
+            }
+
+            if (modelType.IsArray)
+            {
+                Type elementType = modelType.GetElementType();
+                return GenerateCollectionModelDescription(modelType, elementType);
+            }
+
+            if (modelType == typeof(NameValueCollection))
+            {
+                return GenerateDictionaryModelDescription(modelType, typeof(string), typeof(string));
+            }
+
+            if (typeof(IDictionary).IsAssignableFrom(modelType))
+            {
+                return GenerateDictionaryModelDescription(modelType, typeof(object), typeof(object));
+            }
+
+            if (typeof(IEnumerable).IsAssignableFrom(modelType))
+            {
+                return GenerateCollectionModelDescription(modelType, typeof(object));
+            }
+
+            return GenerateComplexTypeModelDescription(modelType);
+        }
+
+        // Change this to provide different name for the member.
+        private static string GetMemberName(MemberInfo member, bool hasDataContractAttribute)
+        {
+            JsonPropertyAttribute jsonProperty = member.GetCustomAttribute<JsonPropertyAttribute>();
+            if (jsonProperty != null && !String.IsNullOrEmpty(jsonProperty.PropertyName))
+            {
+                return jsonProperty.PropertyName;
+            }
+
+            if (hasDataContractAttribute)
+            {
+                DataMemberAttribute dataMember = member.GetCustomAttribute<DataMemberAttribute>();
+                if (dataMember != null && !String.IsNullOrEmpty(dataMember.Name))
+                {
+                    return dataMember.Name;
+                }
+            }
+
+            return member.Name;
+        }
+
+        private static bool ShouldDisplayMember(MemberInfo member, bool hasDataContractAttribute)
+        {
+            JsonIgnoreAttribute jsonIgnore = member.GetCustomAttribute<JsonIgnoreAttribute>();
+            XmlIgnoreAttribute xmlIgnore = member.GetCustomAttribute<XmlIgnoreAttribute>();
+            IgnoreDataMemberAttribute ignoreDataMember = member.GetCustomAttribute<IgnoreDataMemberAttribute>();
+            NonSerializedAttribute nonSerialized = member.GetCustomAttribute<NonSerializedAttribute>();
+            ApiExplorerSettingsAttribute apiExplorerSetting = member.GetCustomAttribute<ApiExplorerSettingsAttribute>();
+
+            bool hasMemberAttribute = member.DeclaringType.IsEnum ?
+                member.GetCustomAttribute<EnumMemberAttribute>() != null :
+                member.GetCustomAttribute<DataMemberAttribute>() != null;
+
+            // Display member only if all the followings are true:
+            // no JsonIgnoreAttribute
+            // no XmlIgnoreAttribute
+            // no IgnoreDataMemberAttribute
+            // no NonSerializedAttribute
+            // no ApiExplorerSettingsAttribute with IgnoreApi set to true
+            // no DataContractAttribute without DataMemberAttribute or EnumMemberAttribute
+            return jsonIgnore == null &&
+                xmlIgnore == null &&
+                ignoreDataMember == null &&
+                nonSerialized == null &&
+                (apiExplorerSetting == null || !apiExplorerSetting.IgnoreApi) &&
+                (!hasDataContractAttribute || hasMemberAttribute);
+        }
+
+        private string CreateDefaultDocumentation(Type type)
+        {
+            string documentation;
+            if (DefaultTypeDocumentation.TryGetValue(type, out documentation))
+            {
+                return documentation;
+            }
+            if (DocumentationProvider != null)
+            {
+                documentation = DocumentationProvider.GetDocumentation(type);
+            }
+
+            return documentation;
+        }
+
+        private void GenerateAnnotations(MemberInfo property, ParameterDescription propertyModel)
+        {
+            List<ParameterAnnotation> annotations = new List<ParameterAnnotation>();
+
+            IEnumerable<Attribute> attributes = property.GetCustomAttributes();
+            foreach (Attribute attribute in attributes)
+            {
+                Func<object, string> textGenerator;
+                if (AnnotationTextGenerator.TryGetValue(attribute.GetType(), out textGenerator))
+                {
+                    annotations.Add(
+                        new ParameterAnnotation
+                        {
+                            AnnotationAttribute = attribute,
+                            Documentation = textGenerator(attribute)
+                        });
+                }
+            }
+
+            // Rearrange the annotations
+            annotations.Sort((x, y) =>
+            {
+                // Special-case RequiredAttribute so that it shows up on top
+                if (x.AnnotationAttribute is RequiredAttribute)
+                {
+                    return -1;
+                }
+                if (y.AnnotationAttribute is RequiredAttribute)
+                {
+                    return 1;
+                }
+
+                // Sort the rest based on alphabetic order of the documentation
+                return String.Compare(x.Documentation, y.Documentation, StringComparison.OrdinalIgnoreCase);
+            });
+
+            foreach (ParameterAnnotation annotation in annotations)
+            {
+                propertyModel.Annotations.Add(annotation);
+            }
+        }
+
+        private CollectionModelDescription GenerateCollectionModelDescription(Type modelType, Type elementType)
+        {
+            ModelDescription collectionModelDescription = GetOrCreateModelDescription(elementType);
+            if (collectionModelDescription != null)
+            {
+                return new CollectionModelDescription
+                {
+                    Name = ModelNameHelper.GetModelName(modelType),
+                    ModelType = modelType,
+                    ElementDescription = collectionModelDescription
+                };
+            }
+
+            return null;
+        }
+
+        private ModelDescription GenerateComplexTypeModelDescription(Type modelType)
+        {
+            ComplexTypeModelDescription complexModelDescription = new ComplexTypeModelDescription
+            {
+                Name = ModelNameHelper.GetModelName(modelType),
+                ModelType = modelType,
+                Documentation = CreateDefaultDocumentation(modelType)
+            };
+
+            GeneratedModels.Add(complexModelDescription.Name, complexModelDescription);
+            bool hasDataContractAttribute = modelType.GetCustomAttribute<DataContractAttribute>() != null;
+            PropertyInfo[] properties = modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
+            foreach (PropertyInfo property in properties)
+            {
+                if (ShouldDisplayMember(property, hasDataContractAttribute))
+                {
+                    ParameterDescription propertyModel = new ParameterDescription
+                    {
+                        Name = GetMemberName(property, hasDataContractAttribute)
+                    };
+
+                    if (DocumentationProvider != null)
+                    {
+                        propertyModel.Documentation = DocumentationProvider.GetDocumentation(property);
+                    }
+
+                    GenerateAnnotations(property, propertyModel);
+                    complexModelDescription.Properties.Add(propertyModel);
+                    propertyModel.TypeDescription = GetOrCreateModelDescription(property.PropertyType);
+                }
+            }
+
+            FieldInfo[] fields = modelType.GetFields(BindingFlags.Public | BindingFlags.Instance);
+            foreach (FieldInfo field in fields)
+            {
+                if (ShouldDisplayMember(field, hasDataContractAttribute))
+                {
+                    ParameterDescription propertyModel = new ParameterDescription
+                    {
+                        Name = GetMemberName(field, hasDataContractAttribute)
+                    };
+
+                    if (DocumentationProvider != null)
+                    {
+                        propertyModel.Documentation = DocumentationProvider.GetDocumentation(field);
+                    }
+
+                    complexModelDescription.Properties.Add(propertyModel);
+                    propertyModel.TypeDescription = GetOrCreateModelDescription(field.FieldType);
+                }
+            }
+
+            return complexModelDescription;
+        }
+
+        private DictionaryModelDescription GenerateDictionaryModelDescription(Type modelType, Type keyType, Type valueType)
+        {
+            ModelDescription keyModelDescription = GetOrCreateModelDescription(keyType);
+            ModelDescription valueModelDescription = GetOrCreateModelDescription(valueType);
+
+            return new DictionaryModelDescription
+            {
+                Name = ModelNameHelper.GetModelName(modelType),
+                ModelType = modelType,
+                KeyModelDescription = keyModelDescription,
+                ValueModelDescription = valueModelDescription
+            };
+        }
+
+        private EnumTypeModelDescription GenerateEnumTypeModelDescription(Type modelType)
+        {
+            EnumTypeModelDescription enumDescription = new EnumTypeModelDescription
+            {
+                Name = ModelNameHelper.GetModelName(modelType),
+                ModelType = modelType,
+                Documentation = CreateDefaultDocumentation(modelType)
+            };
+            bool hasDataContractAttribute = modelType.GetCustomAttribute<DataContractAttribute>() != null;
+            foreach (FieldInfo field in modelType.GetFields(BindingFlags.Public | BindingFlags.Static))
+            {
+                if (ShouldDisplayMember(field, hasDataContractAttribute))
+                {
+                    EnumValueDescription enumValue = new EnumValueDescription
+                    {
+                        Name = field.Name,
+                        Value = field.GetRawConstantValue().ToString()
+                    };
+                    if (DocumentationProvider != null)
+                    {
+                        enumValue.Documentation = DocumentationProvider.GetDocumentation(field);
+                    }
+                    enumDescription.Values.Add(enumValue);
+                }
+            }
+            GeneratedModels.Add(enumDescription.Name, enumDescription);
+
+            return enumDescription;
+        }
+
+        private KeyValuePairModelDescription GenerateKeyValuePairModelDescription(Type modelType, Type keyType, Type valueType)
+        {
+            ModelDescription keyModelDescription = GetOrCreateModelDescription(keyType);
+            ModelDescription valueModelDescription = GetOrCreateModelDescription(valueType);
+
+            return new KeyValuePairModelDescription
+            {
+                Name = ModelNameHelper.GetModelName(modelType),
+                ModelType = modelType,
+                KeyModelDescription = keyModelDescription,
+                ValueModelDescription = valueModelDescription
+            };
+        }
+
+        private ModelDescription GenerateSimpleTypeModelDescription(Type modelType)
+        {
+            SimpleTypeModelDescription simpleModelDescription = new SimpleTypeModelDescription
+            {
+                Name = ModelNameHelper.GetModelName(modelType),
+                ModelType = modelType,
+                Documentation = CreateDefaultDocumentation(modelType)
+            };
+            GeneratedModels.Add(simpleModelDescription.Name, simpleModelDescription);
+
+            return simpleModelDescription;
+        }
+    }
+}
\ No newline at end of file

--
Gitblit v1.9.3