usingSystem;usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.Collections.Specialized;usingSystem.ComponentModel.DataAnnotations;usingSystem.Globalization;usingSystem.Reflection;usingSystem.Runtime.Serialization;usingSystem.Web.Http;usingSystem.Web.Http.Description;usingSystem.Xml.Serialization;usingNewtonsoft.Json;namespaceHHECS.API.Areas.HelpPage.ModelDescriptions{///<summary>///Generatesmodeldescriptionsforgiventypes.///</summary>publicclassModelDescriptionGenerator{//Modifythistosupportmoredataannotationattributes.privatereadonlyIDictionary<Type,Func<object,string>>AnnotationTextGenerator=newDictionary<Type,Func<object,string>>{{typeof(RequiredAttribute),a=>"Required"},{typeof(RangeAttribute),a=>{RangeAttributerange=(RangeAttribute)a;returnString.Format(CultureInfo.CurrentCulture,"Range: inclusive between {0} and {1}",range.Minimum,range.Maximum);}},{typeof(MaxLengthAttribute),a=>{MaxLengthAttributemaxLength=(MaxLengthAttribute)a;returnString.Format(CultureInfo.CurrentCulture,"Max length: {0}",maxLength.Length);}},{typeof(MinLengthAttribute),a=>{MinLengthAttributeminLength=(MinLengthAttribute)a;returnString.Format(CultureInfo.CurrentCulture,"Min length: {0}",minLength.Length);}},{typeof(StringLengthAttribute),a=>{StringLengthAttributestrLength=(StringLengthAttribute)a;returnString.Format(CultureInfo.CurrentCulture,"String length: inclusive between {0} and {1}",strLength.MinimumLength,strLength.MaximumLength);}},{typeof(DataTypeAttribute),a=>{DataTypeAttributedataType=(DataTypeAttribute)a;returnString.Format(CultureInfo.CurrentCulture,"Data type: {0}",dataType.CustomDataType??dataType.DataType.ToString());}},{typeof(RegularExpressionAttribute),a=>{RegularExpressionAttributeregularExpression=(RegularExpressionAttribute)a;returnString.Format(CultureInfo.CurrentCulture,"Matching regular expression pattern: {0}",regularExpression.Pattern);}},};//Modifythistoaddmoredefaultdocumentations.privatereadonlyIDictionary<Type,string>DefaultTypeDocumentation=newDictionary<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"},};privateLazy<IModelDocumentationProvider>_documentationProvider;publicModelDescriptionGenerator(HttpConfigurationconfig){if(config==null){thrownewArgumentNullException("config");}_documentationProvider=newLazy<IModelDocumentationProvider>(()=>config.Services.GetDocumentationProvider()asIModelDocumentationProvider);GeneratedModels=newDictionary<string,ModelDescription>(StringComparer.OrdinalIgnoreCase);}publicDictionary<string,ModelDescription>GeneratedModels{get;privateset;}privateIModelDocumentationProviderDocumentationProvider{get{return_documentationProvider.Value;}}publicModelDescriptionGetOrCreateModelDescription(TypemodelType){if(modelType==null){thrownewArgumentNullException("modelType");}TypeunderlyingType=Nullable.GetUnderlyingType(modelType);if(underlyingType!=null){modelType=underlyingType;}ModelDescriptionmodelDescription;stringmodelName=ModelNameHelper.GetModelName(modelType);if(GeneratedModels.TryGetValue(modelName,outmodelDescription)){if(modelType!=modelDescription.ModelType){thrownewInvalidOperationException(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));}returnmodelDescription;}if(DefaultTypeDocumentation.ContainsKey(modelType)){returnGenerateSimpleTypeModelDescription(modelType);}if(modelType.IsEnum){returnGenerateEnumTypeModelDescription(modelType);}if(modelType.IsGenericType){Type[]genericArguments=modelType.GetGenericArguments();if(genericArguments.Length==1){TypeenumerableType=typeof(IEnumerable<>).MakeGenericType(genericArguments);if(enumerableType.IsAssignableFrom(modelType)){returnGenerateCollectionModelDescription(modelType,genericArguments[0]);}}if(genericArguments.Length==2){TypedictionaryType=typeof(IDictionary<,>).MakeGenericType(genericArguments);if(dictionaryType.IsAssignableFrom(modelType)){returnGenerateDictionaryModelDescription(modelType,genericArguments[0],genericArguments[1]);}TypekeyValuePairType=typeof(KeyValuePair<,>).MakeGenericType(genericArguments);if(keyValuePairType.IsAssignableFrom(modelType)){returnGenerateKeyValuePairModelDescription(modelType,genericArguments[0],genericArguments[1]);}}}if(modelType.IsArray){TypeelementType=modelType.GetElementType();returnGenerateCollectionModelDescription(modelType,elementType);}if(modelType==typeof(NameValueCollection)){returnGenerateDictionaryModelDescription(modelType,typeof(string),typeof(string));}if(typeof(IDictionary).IsAssignableFrom(modelType)){returnGenerateDictionaryModelDescription(modelType,typeof(object),typeof(object));}if(typeof(IEnumerable).IsAssignableFrom(modelType)){returnGenerateCollectionModelDescription(modelType,typeof(object));}returnGenerateComplexTypeModelDescription(modelType);}//Changethistoprovidedifferentnameforthemember.privatestaticstringGetMemberName(MemberInfomember,boolhasDataContractAttribute){JsonPropertyAttributejsonProperty=member.GetCustomAttribute<JsonPropertyAttribute>();if(jsonProperty!=null&&!String.IsNullOrEmpty(jsonProperty.PropertyName)){returnjsonProperty.PropertyName;}if(hasDataContractAttribute){DataMemberAttributedataMember=member.GetCustomAttribute<DataMemberAttribute>();if(dataMember!=null&&!String.IsNullOrEmpty(dataMember.Name)){returndataMember.Name;}}returnmember.Name;}privatestaticboolShouldDisplayMember(MemberInfomember,boolhasDataContractAttribute){JsonIgnoreAttributejsonIgnore=member.GetCustomAttribute<JsonIgnoreAttribute>();XmlIgnoreAttributexmlIgnore=member.GetCustomAttribute<XmlIgnoreAttribute>();IgnoreDataMemberAttributeignoreDataMember=member.GetCustomAttribute<IgnoreDataMemberAttribute>();NonSerializedAttributenonSerialized=member.GetCustomAttribute<NonSerializedAttribute>();ApiExplorerSettingsAttributeapiExplorerSetting=member.GetCustomAttribute<ApiExplorerSettingsAttribute>();boolhasMemberAttribute=member.DeclaringType.IsEnum?member.GetCustomAttribute<EnumMemberAttribute>()!=null:member.GetCustomAttribute<DataMemberAttribute>()!=null;//Displaymemberonlyifallthefollowingsaretrue://noJsonIgnoreAttribute//noXmlIgnoreAttribute//noIgnoreDataMemberAttribute//noNonSerializedAttribute//noApiExplorerSettingsAttributewithIgnoreApisettotrue//noDataContractAttributewithoutDataMemberAttributeorEnumMemberAttributereturnjsonIgnore==null&&xmlIgnore==null&&ignoreDataMember==null&&nonSerialized==null&&(apiExplorerSetting==null||!apiExplorerSetting.IgnoreApi)&&(!hasDataContractAttribute||hasMemberAttribute);}privatestringCreateDefaultDocumentation(Typetype){stringdocumentation;if(DefaultTypeDocumentation.TryGetValue(type,outdocumentation)){returndocumentation;}if(DocumentationProvider!=null){documentation=DocumentationProvider.GetDocumentation(type);}returndocumentation;}privatevoidGenerateAnnotations(MemberInfoproperty,ParameterDescriptionpropertyModel){List<ParameterAnnotation>annotations=newList<ParameterAnnotation>();IEnumerable<Attribute>attributes=property.GetCustomAttributes();foreach(Attributeattributeinattributes){Func<object,string>textGenerator;if(AnnotationTextGenerator.TryGetValue(attribute.GetType(),outtextGenerator)){annotations.Add(newParameterAnnotation{AnnotationAttribute=attribute,Documentation=textGenerator(attribute)});}}//Rearrangetheannotationsannotations.Sort((x,y)=>{//Special-caseRequiredAttributesothatitshowsupontopif(x.AnnotationAttributeisRequiredAttribute){return-1;}if(y.AnnotationAttributeisRequiredAttribute){return1;}//SorttherestbasedonalphabeticorderofthedocumentationreturnString.Compare(x.Documentation,y.Documentation,StringComparison.OrdinalIgnoreCase);});foreach(ParameterAnnotationannotationinannotations){propertyModel.Annotations.Add(annotation);}}privateCollectionModelDescriptionGenerateCollectionModelDescription(TypemodelType,TypeelementType){ModelDescriptioncollectionModelDescription=GetOrCreateModelDescription(elementType);if(collectionModelDescription!=null){returnnewCollectionModelDescription{Name=ModelNameHelper.GetModelName(modelType),ModelType=modelType,ElementDescription=collectionModelDescription};}returnnull;}privateModelDescriptionGenerateComplexTypeModelDescription(TypemodelType){ComplexTypeModelDescriptioncomplexModelDescription=newComplexTypeModelDescription{Name=ModelNameHelper.GetModelName(modelType),ModelType=modelType,Documentation=CreateDefaultDocumentation(modelType)};GeneratedModels.Add(complexModelDescription.Name,complexModelDescription);boolhasDataContractAttribute=modelType.GetCustomAttribute<DataContractAttribute>()!=null;PropertyInfo[]properties=modelType.GetProperties(BindingFlags.Public|BindingFlags.Instance);foreach(PropertyInfopropertyinproperties){if(ShouldDisplayMember(property,hasDataContractAttribute)){ParameterDescriptionpropertyModel=newParameterDescription{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(FieldInfofieldinfields){if(ShouldDisplayMember(field,hasDataContractAttribute)){ParameterDescriptionpropertyModel=newParameterDescription{Name=GetMemberName(field,hasDataContractAttribute)};if(DocumentationProvider!=null){propertyModel.Documentation=DocumentationProvider.GetDocumentation(field);}complexModelDescription.Properties.Add(propertyModel);propertyModel.TypeDescription=GetOrCreateModelDescription(field.FieldType);}}returncomplexModelDescription;}privateDictionaryModelDescriptionGenerateDictionaryModelDescription(TypemodelType,TypekeyType,TypevalueType){ModelDescriptionkeyModelDescription=GetOrCreateModelDescription(keyType);ModelDescriptionvalueModelDescription=GetOrCreateModelDescription(valueType);returnnewDictionaryModelDescription{Name=ModelNameHelper.GetModelName(modelType),ModelType=modelType,KeyModelDescription=keyModelDescription,ValueModelDescription=valueModelDescription};}privateEnumTypeModelDescriptionGenerateEnumTypeModelDescription(TypemodelType){EnumTypeModelDescriptionenumDescription=newEnumTypeModelDescription{Name=ModelNameHelper.GetModelName(modelType),ModelType=modelType,Documentation=CreateDefaultDocumentation(modelType)};boolhasDataContractAttribute=modelType.GetCustomAttribute<DataContractAttribute>()!=null;foreach(FieldInfofieldinmodelType.GetFields(BindingFlags.Public|BindingFlags.Static)){if(ShouldDisplayMember(field,hasDataContractAttribute)){EnumValueDescriptionenumValue=newEnumValueDescription{Name=field.Name,Value=field.GetRawConstantValue().ToString()};if(DocumentationProvider!=null){enumValue.Documentation=DocumentationProvider.GetDocumentation(field);}enumDescription.Values.Add(enumValue);}}GeneratedModels.Add(enumDescription.Name,enumDescription);returnenumDescription;}privateKeyValuePairModelDescriptionGenerateKeyValuePairModelDescription(TypemodelType,TypekeyType,TypevalueType){ModelDescriptionkeyModelDescription=GetOrCreateModelDescription(keyType);ModelDescriptionvalueModelDescription=GetOrCreateModelDescription(valueType);returnnewKeyValuePairModelDescription{Name=ModelNameHelper.GetModelName(modelType),ModelType=modelType,KeyModelDescription=keyModelDescription,ValueModelDescription=valueModelDescription};}privateModelDescriptionGenerateSimpleTypeModelDescription(TypemodelType){SimpleTypeModelDescriptionsimpleModelDescription=newSimpleTypeModelDescription{Name=ModelNameHelper.GetModelName(modelType),ModelType=modelType,Documentation=CreateDefaultDocumentation(modelType)};GeneratedModels.Add(simpleModelDescription.Name,simpleModelDescription);returnsimpleModelDescription;}}}