usingSystem;usingSystem.Collections.Generic;usingSystem.Collections.ObjectModel;usingSystem.ComponentModel;usingSystem.Diagnostics.CodeAnalysis;usingSystem.Globalization;usingSystem.IO;usingSystem.Linq;usingSystem.Net.Http;usingSystem.Net.Http.Formatting;usingSystem.Net.Http.Headers;usingSystem.Web.Http.Description;usingSystem.Xml.Linq;usingNewtonsoft.Json;namespaceHHECS.API.Areas.HelpPage{///<summary>///Thisclasswillgeneratethesamplesforthehelppage.///</summary>publicclassHelpPageSampleGenerator{///<summary>///Initializesanewinstanceofthe<seecref="HelpPageSampleGenerator"/>class.///</summary>publicHelpPageSampleGenerator(){ActualHttpMessageTypes=newDictionary<HelpPageSampleKey,Type>();ActionSamples=newDictionary<HelpPageSampleKey,object>();SampleObjects=newDictionary<Type,object>();SampleObjectFactories=newList<Func<HelpPageSampleGenerator,Type,object>>{DefaultSampleObjectFactory,};}///<summary>///GetsCLRtypesthatareusedasthecontentof<seecref="HttpRequestMessage"/>or<seecref="HttpResponseMessage"/>.///</summary>publicIDictionary<HelpPageSampleKey,Type>ActualHttpMessageTypes{get;internalset;}///<summary>///Getstheobjectsthatareuseddirectlyassamplesforcertainactions.///</summary>publicIDictionary<HelpPageSampleKey,object>ActionSamples{get;internalset;}///<summary>///Getstheobjectsthatareserializedassamplesbythesupportedformatters.///</summary>publicIDictionary<Type,object>SampleObjects{get;internalset;}///<summary>///Getsfactoriesfortheobjectsthatthesupportedformatterswillserializeassamples.Processedinorder,///stoppingwhenthefactorysuccessfullyreturnsanon-<seelangref="null"/>object.///</summary>///<remarks>///Collectionincludesjust<seecref="ObjectGenerator.GenerateObject(Type)"/>initially.Use///<code>SampleObjectFactories.Insert(0,func)</code>toprovideanoverrideand///<code>SampleObjectFactories.Add(func)</code>toprovideafallback.</remarks>[SuppressMessage("Microsoft.Design","CA1006:DoNotNestGenericTypesInMemberSignatures",Justification="This is an appropriate nesting of generic types")]publicIList<Func<HelpPageSampleGenerator,Type,object>>SampleObjectFactories{get;privateset;}///<summary>///Getstherequestbodysamplesforagiven<seecref="ApiDescription"/>.///</summary>///<paramname="api">The<seecref="ApiDescription"/>.</param>///<returns>Thesampleskeyedbymediatype.</returns>publicIDictionary<MediaTypeHeaderValue,object>GetSampleRequests(ApiDescriptionapi){returnGetSample(api,SampleDirection.Request);}///<summary>///Getstheresponsebodysamplesforagiven<seecref="ApiDescription"/>.///</summary>///<paramname="api">The<seecref="ApiDescription"/>.</param>///<returns>Thesampleskeyedbymediatype.</returns>publicIDictionary<MediaTypeHeaderValue,object>GetSampleResponses(ApiDescriptionapi){returnGetSample(api,SampleDirection.Response);}///<summary>///Getstherequestorresponsebodysamples.///</summary>///<paramname="api">The<seecref="ApiDescription"/>.</param>///<paramname="sampleDirection">Thevalueindicatingwhetherthesampleisforarequestorforaresponse.</param>///<returns>Thesampleskeyedbymediatype.</returns>publicvirtualIDictionary<MediaTypeHeaderValue,object>GetSample(ApiDescriptionapi,SampleDirectionsampleDirection){if(api==null){thrownewArgumentNullException("api");}stringcontrollerName=api.ActionDescriptor.ControllerDescriptor.ControllerName;stringactionName=api.ActionDescriptor.ActionName;IEnumerable<string>parameterNames=api.ParameterDescriptions.Select(p=>p.Name);Collection<MediaTypeFormatter>formatters;Typetype=ResolveType(api,controllerName,actionName,parameterNames,sampleDirection,outformatters);varsamples=newDictionary<MediaTypeHeaderValue,object>();//UsethesamplesprovideddirectlyforactionsvaractionSamples=GetAllActionSamples(controllerName,actionName,parameterNames,sampleDirection);foreach(varactionSampleinactionSamples){samples.Add(actionSample.Key.MediaType,WrapSampleIfString(actionSample.Value));}//Dothesamplegenerationbasedonformattersonlyifanactiondoesn'treturnanHttpResponseMessage.//Herewecannotrelyonformattersbecausewedon'tknowwhat'sintheHttpResponseMessage,itmightnotevenuseformatters.if(type!=null&&!typeof(HttpResponseMessage).IsAssignableFrom(type)){objectsampleObject=GetSampleObject(type);foreach(varformatterinformatters){foreach(MediaTypeHeaderValuemediaTypeinformatter.SupportedMediaTypes){if(!samples.ContainsKey(mediaType)){objectsample=GetActionSample(controllerName,actionName,parameterNames,type,formatter,mediaType,sampleDirection);//Ifnosamplefound,trygeneratesampleusingformatterandsampleobjectif(sample==null&&sampleObject!=null){sample=WriteSampleObjectUsingFormatter(formatter,sampleObject,type,mediaType);}samples.Add(mediaType,WrapSampleIfString(sample));}}}}returnsamples;}///<summary>///Searchforsamplesthatareprovideddirectlythrough<seecref="ActionSamples"/>.///</summary>///<paramname="controllerName">Nameofthecontroller.</param>///<paramname="actionName">Nameoftheaction.</param>///<paramname="parameterNames">Theparameternames.</param>///<paramname="type">TheCLRtype.</param>///<paramname="formatter">Theformatter.</param>///<paramname="mediaType">Themediatype.</param>///<paramname="sampleDirection">Thevalueindicatingwhetherthesampleisforarequestorforaresponse.</param>///<returns>Thesamplethatmatchestheparameters.</returns>publicvirtualobjectGetActionSample(stringcontrollerName,stringactionName,IEnumerable<string>parameterNames,Typetype,MediaTypeFormatterformatter,MediaTypeHeaderValuemediaType,SampleDirectionsampleDirection){objectsample;//First,trytogetthesampleprovidedforthespecifiedmediaType,sampleDirection,controllerName,actionNameandparameterNames.//Ifnotfound,trytogetthesampleprovidedforthespecifiedmediaType,sampleDirection,controllerNameandactionNameregardlessoftheparameterNames.//Ifstillnotfound,trytogetthesampleprovidedforthespecifiedmediaTypeandtype.//Finally,trytogetthesampleprovidedforthespecifiedmediaType.if(ActionSamples.TryGetValue(newHelpPageSampleKey(mediaType,sampleDirection,controllerName,actionName,parameterNames),outsample)||ActionSamples.TryGetValue(newHelpPageSampleKey(mediaType,sampleDirection,controllerName,actionName,new[]{"*"}),outsample)||ActionSamples.TryGetValue(newHelpPageSampleKey(mediaType,type),outsample)||ActionSamples.TryGetValue(newHelpPageSampleKey(mediaType),outsample)){returnsample;}returnnull;}///<summary>///Getsthesampleobjectthatwillbeserializedbytheformatters.///First,itwilllookatthe<seecref="SampleObjects"/>.Ifnosampleobjectisfound,itwilltrytocreate///oneusing<seecref="DefaultSampleObjectFactory"/>(whichwrapsan<seecref="ObjectGenerator"/>)andother///factoriesin<seecref="SampleObjectFactories"/>.///</summary>///<paramname="type">Thetype.</param>///<returns>Thesampleobject.</returns>[SuppressMessage("Microsoft.Design","CA1031:DoNotCatchGeneralExceptionTypes",Justification="Even if all items in SampleObjectFactories throw, problem will be visible as missing sample.")]publicvirtualobjectGetSampleObject(Typetype){objectsampleObject;if(!SampleObjects.TryGetValue(type,outsampleObject)){//Nospecificobjectavailable,tryourfactories.foreach(Func<HelpPageSampleGenerator,Type,object>factoryinSampleObjectFactories){if(factory==null){continue;}try{sampleObject=factory(this,type);if(sampleObject!=null){break;}}catch{//Ignoreanyproblemsencounteredinthefactory;goontothenextone(ifany).}}}returnsampleObject;}///<summary>///Resolvestheactualtypeof<seecref="System.Net.Http.ObjectContent{T}"/>passedtothe<seecref="System.Net.Http.HttpRequestMessage"/>inanaction.///</summary>///<paramname="api">The<seecref="ApiDescription"/>.</param>///<returns>Thetype.</returns>publicvirtualTypeResolveHttpRequestMessageType(ApiDescriptionapi){stringcontrollerName=api.ActionDescriptor.ControllerDescriptor.ControllerName;stringactionName=api.ActionDescriptor.ActionName;IEnumerable<string>parameterNames=api.ParameterDescriptions.Select(p=>p.Name);Collection<MediaTypeFormatter>formatters;returnResolveType(api,controllerName,actionName,parameterNames,SampleDirection.Request,outformatters);}///<summary>///Resolvesthetypeoftheactionparameterorreturnvaluewhen<seecref="HttpRequestMessage"/>or<seecref="HttpResponseMessage"/>isused.///</summary>///<paramname="api">The<seecref="ApiDescription"/>.</param>///<paramname="controllerName">Nameofthecontroller.</param>///<paramname="actionName">Nameoftheaction.</param>///<paramname="parameterNames">Theparameternames.</param>///<paramname="sampleDirection">Thevalueindicatingwhetherthesampleisforarequestoraresponse.</param>///<paramname="formatters">Theformatters.</param>[SuppressMessage("Microsoft.Design","CA1021:AvoidOutParameters",Justification="This is only used in advanced scenarios.")]publicvirtualTypeResolveType(ApiDescriptionapi,stringcontrollerName,stringactionName,IEnumerable<string>parameterNames,SampleDirectionsampleDirection,outCollection<MediaTypeFormatter>formatters){if(!Enum.IsDefined(typeof(SampleDirection),sampleDirection)){thrownewInvalidEnumArgumentException("sampleDirection",(int)sampleDirection,typeof(SampleDirection));}if(api==null){thrownewArgumentNullException("api");}Typetype;if(ActualHttpMessageTypes.TryGetValue(newHelpPageSampleKey(sampleDirection,controllerName,actionName,parameterNames),outtype)||ActualHttpMessageTypes.TryGetValue(newHelpPageSampleKey(sampleDirection,controllerName,actionName,new[]{"*"}),outtype)){//Re-computethesupportedformattersbasedontypeCollection<MediaTypeFormatter>newFormatters=newCollection<MediaTypeFormatter>();foreach(varformatterinapi.ActionDescriptor.Configuration.Formatters){if(IsFormatSupported(sampleDirection,formatter,type)){newFormatters.Add(formatter);}}formatters=newFormatters;}else{switch(sampleDirection){caseSampleDirection.Request:ApiParameterDescriptionrequestBodyParameter=api.ParameterDescriptions.FirstOrDefault(p=>p.Source==ApiParameterSource.FromBody);type=requestBodyParameter==null?null:requestBodyParameter.ParameterDescriptor.ParameterType;formatters=api.SupportedRequestBodyFormatters;break;caseSampleDirection.Response:default:type=api.ResponseDescription.ResponseType??api.ResponseDescription.DeclaredType;formatters=api.SupportedResponseFormatters;break;}}returntype;}///<summary>///Writesthesampleobjectusingformatter.///</summary>///<paramname="formatter">Theformatter.</param>///<paramname="value">Thevalue.</param>///<paramname="type">Thetype.</param>///<paramname="mediaType">Typeofthemedia.</param>///<returns></returns>[SuppressMessage("Microsoft.Design","CA1031:DoNotCatchGeneralExceptionTypes",Justification="The exception is recorded as InvalidSample.")]publicvirtualobjectWriteSampleObjectUsingFormatter(MediaTypeFormatterformatter,objectvalue,Typetype,MediaTypeHeaderValuemediaType){if(formatter==null){thrownewArgumentNullException("formatter");}if(mediaType==null){thrownewArgumentNullException("mediaType");}objectsample=String.Empty;MemoryStreamms=null;HttpContentcontent=null;try{if(formatter.CanWriteType(type)){ms=newMemoryStream();content=newObjectContent(type,value,formatter,mediaType);formatter.WriteToStreamAsync(type,value,ms,content,null).Wait();ms.Position=0;StreamReaderreader=newStreamReader(ms);stringserializedSampleString=reader.ReadToEnd();if(mediaType.MediaType.ToUpperInvariant().Contains("XML")){serializedSampleString=TryFormatXml(serializedSampleString);}elseif(mediaType.MediaType.ToUpperInvariant().Contains("JSON")){serializedSampleString=TryFormatJson(serializedSampleString);}sample=newTextSample(serializedSampleString);}else{sample=newInvalidSample(String.Format(CultureInfo.CurrentCulture,"Failed to generate the sample for media type '{0}'. Cannot use formatter '{1}' to write type '{2}'.",mediaType,formatter.GetType().Name,type.Name));}}catch(Exceptione){sample=newInvalidSample(String.Format(CultureInfo.CurrentCulture,"An exception has occurred while using the formatter '{0}' to generate sample for media type '{1}'. Exception message: {2}",formatter.GetType().Name,mediaType.MediaType,UnwrapException(e).Message));}finally{if(ms!=null){ms.Dispose();}if(content!=null){content.Dispose();}}returnsample;}internalstaticExceptionUnwrapException(Exceptionexception){AggregateExceptionaggregateException=exceptionasAggregateException;if(aggregateException!=null){returnaggregateException.Flatten().InnerException;}returnexception;}//DefaultfactoryforsampleobjectsprivatestaticobjectDefaultSampleObjectFactory(HelpPageSampleGeneratorsampleGenerator,Typetype){//TrytocreateadefaultsampleobjectObjectGeneratorobjectGenerator=newObjectGenerator();returnobjectGenerator.GenerateObject(type);}[SuppressMessage("Microsoft.Design","CA1031:DoNotCatchGeneralExceptionTypes",Justification="Handling the failure by returning the original string.")]privatestaticstringTryFormatJson(stringstr){try{objectparsedJson=JsonConvert.DeserializeObject(str);returnJsonConvert.SerializeObject(parsedJson,Formatting.Indented);}catch{//can'tparseJSON,returntheoriginalstringreturnstr;}}[SuppressMessage("Microsoft.Design","CA1031:DoNotCatchGeneralExceptionTypes",Justification="Handling the failure by returning the original string.")]privatestaticstringTryFormatXml(stringstr){try{XDocumentxml=XDocument.Parse(str);returnxml.ToString();}catch{//can'tparseXML,returntheoriginalstringreturnstr;}}privatestaticboolIsFormatSupported(SampleDirectionsampleDirection,MediaTypeFormatterformatter,Typetype){switch(sampleDirection){caseSampleDirection.Request:returnformatter.CanReadType(type);caseSampleDirection.Response:returnformatter.CanWriteType(type);}returnfalse;}privateIEnumerable<KeyValuePair<HelpPageSampleKey,object>>GetAllActionSamples(stringcontrollerName,stringactionName,IEnumerable<string>parameterNames,SampleDirectionsampleDirection){HashSet<string>parameterNamesSet=newHashSet<string>(parameterNames,StringComparer.OrdinalIgnoreCase);foreach(varsampleinActionSamples){HelpPageSampleKeysampleKey=sample.Key;if(String.Equals(controllerName,sampleKey.ControllerName,StringComparison.OrdinalIgnoreCase)&&String.Equals(actionName,sampleKey.ActionName,StringComparison.OrdinalIgnoreCase)&&(sampleKey.ParameterNames.SetEquals(new[]{"*"})||parameterNamesSet.SetEquals(sampleKey.ParameterNames))&&sampleDirection==sampleKey.SampleDirection){yieldreturnsample;}}}privatestaticobjectWrapSampleIfString(objectsample){stringstringSample=sampleasstring;if(stringSample!=null){returnnewTextSample(stringSample);}returnsample;}}}