aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions')
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/CollectionModelDescription.cs7
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ComplexTypeModelDescription.cs14
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/DictionaryModelDescription.cs6
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/EnumTypeModelDescription.cs15
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/EnumValueDescription.cs11
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/IModelDocumentationProvider.cs12
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/KeyValuePairModelDescription.cs9
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelDescription.cs16
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelDescriptionGenerator.cs451
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelNameAttribute.cs18
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelNameHelper.cs36
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ParameterAnnotation.cs11
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ParameterDescription.cs21
-rw-r--r--ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/SimpleTypeModelDescription.cs6
14 files changed, 633 insertions, 0 deletions
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/CollectionModelDescription.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/CollectionModelDescription.cs
new file mode 100644
index 0000000..e8f0753
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/CollectionModelDescription.cs
@@ -0,0 +1,7 @@
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ public class CollectionModelDescription : ModelDescription
+ {
+ public ModelDescription ElementDescription { get; set; }
+ }
+} \ No newline at end of file
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ComplexTypeModelDescription.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ComplexTypeModelDescription.cs
new file mode 100644
index 0000000..4e4c31a
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ComplexTypeModelDescription.cs
@@ -0,0 +1,14 @@
+using System.Collections.ObjectModel;
+
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ public class ComplexTypeModelDescription : ModelDescription
+ {
+ public ComplexTypeModelDescription()
+ {
+ Properties = new Collection<ParameterDescription>();
+ }
+
+ public Collection<ParameterDescription> Properties { get; private set; }
+ }
+} \ No newline at end of file
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/DictionaryModelDescription.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/DictionaryModelDescription.cs
new file mode 100644
index 0000000..4d86e57
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/DictionaryModelDescription.cs
@@ -0,0 +1,6 @@
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ public class DictionaryModelDescription : KeyValuePairModelDescription
+ {
+ }
+} \ No newline at end of file
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/EnumTypeModelDescription.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/EnumTypeModelDescription.cs
new file mode 100644
index 0000000..9d23179
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/EnumTypeModelDescription.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ public class EnumTypeModelDescription : ModelDescription
+ {
+ public EnumTypeModelDescription()
+ {
+ Values = new Collection<EnumValueDescription>();
+ }
+
+ public Collection<EnumValueDescription> Values { get; private set; }
+ }
+} \ No newline at end of file
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/EnumValueDescription.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/EnumValueDescription.cs
new file mode 100644
index 0000000..7dbcb25
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/EnumValueDescription.cs
@@ -0,0 +1,11 @@
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ public class EnumValueDescription
+ {
+ public string Documentation { get; set; }
+
+ public string Name { get; set; }
+
+ public string Value { get; set; }
+ }
+} \ No newline at end of file
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/IModelDocumentationProvider.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/IModelDocumentationProvider.cs
new file mode 100644
index 0000000..95151dd
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/IModelDocumentationProvider.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Reflection;
+
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ public interface IModelDocumentationProvider
+ {
+ string GetDocumentation(MemberInfo member);
+
+ string GetDocumentation(Type type);
+ }
+} \ No newline at end of file
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/KeyValuePairModelDescription.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/KeyValuePairModelDescription.cs
new file mode 100644
index 0000000..37d227f
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/KeyValuePairModelDescription.cs
@@ -0,0 +1,9 @@
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ public class KeyValuePairModelDescription : ModelDescription
+ {
+ public ModelDescription KeyModelDescription { get; set; }
+
+ public ModelDescription ValueModelDescription { get; set; }
+ }
+} \ No newline at end of file
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelDescription.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelDescription.cs
new file mode 100644
index 0000000..6d44857
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelDescription.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ /// <summary>
+ /// Describes a type model.
+ /// </summary>
+ public abstract class ModelDescription
+ {
+ public string Documentation { get; set; }
+
+ public Type ModelType { get; set; }
+
+ public string Name { get; set; }
+ }
+} \ No newline at end of file
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelDescriptionGenerator.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelDescriptionGenerator.cs
new file mode 100644
index 0000000..c016a31
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/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 HousingWebAPI.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
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelNameAttribute.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelNameAttribute.cs
new file mode 100644
index 0000000..7c20658
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelNameAttribute.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ /// <summary>
+ /// Use this attribute to change the name of the <see cref="ModelDescription"/> generated for a type.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]
+ public sealed class ModelNameAttribute : Attribute
+ {
+ public ModelNameAttribute(string name)
+ {
+ Name = name;
+ }
+
+ public string Name { get; private set; }
+ }
+} \ No newline at end of file
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelNameHelper.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelNameHelper.cs
new file mode 100644
index 0000000..c5558c6
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ModelNameHelper.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ internal static class ModelNameHelper
+ {
+ // Modify this to provide custom model name mapping.
+ public static string GetModelName(Type type)
+ {
+ ModelNameAttribute modelNameAttribute = type.GetCustomAttribute<ModelNameAttribute>();
+ if (modelNameAttribute != null && !String.IsNullOrEmpty(modelNameAttribute.Name))
+ {
+ return modelNameAttribute.Name;
+ }
+
+ string modelName = type.Name;
+ if (type.IsGenericType)
+ {
+ // Format the generic type name to something like: GenericOfAgurment1AndArgument2
+ Type genericType = type.GetGenericTypeDefinition();
+ Type[] genericArguments = type.GetGenericArguments();
+ string genericTypeName = genericType.Name;
+
+ // Trim the generic parameter counts from the name
+ genericTypeName = genericTypeName.Substring(0, genericTypeName.IndexOf('`'));
+ string[] argumentTypeNames = genericArguments.Select(t => GetModelName(t)).ToArray();
+ modelName = String.Format(CultureInfo.InvariantCulture, "{0}Of{1}", genericTypeName, String.Join("And", argumentTypeNames));
+ }
+
+ return modelName;
+ }
+ }
+} \ No newline at end of file
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ParameterAnnotation.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ParameterAnnotation.cs
new file mode 100644
index 0000000..31a726b
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ParameterAnnotation.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ public class ParameterAnnotation
+ {
+ public Attribute AnnotationAttribute { get; set; }
+
+ public string Documentation { get; set; }
+ }
+} \ No newline at end of file
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ParameterDescription.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ParameterDescription.cs
new file mode 100644
index 0000000..53ea037
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/ParameterDescription.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ public class ParameterDescription
+ {
+ public ParameterDescription()
+ {
+ Annotations = new Collection<ParameterAnnotation>();
+ }
+
+ public Collection<ParameterAnnotation> Annotations { get; private set; }
+
+ public string Documentation { get; set; }
+
+ public string Name { get; set; }
+
+ public ModelDescription TypeDescription { get; set; }
+ }
+} \ No newline at end of file
diff --git a/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/SimpleTypeModelDescription.cs b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/SimpleTypeModelDescription.cs
new file mode 100644
index 0000000..d478205
--- /dev/null
+++ b/ApartmentManager/HousingWebAPI/Areas/HelpPage/ModelDescriptions/SimpleTypeModelDescription.cs
@@ -0,0 +1,6 @@
+namespace HousingWebAPI.Areas.HelpPage.ModelDescriptions
+{
+ public class SimpleTypeModelDescription : ModelDescription
+ {
+ }
+} \ No newline at end of file