usingSystem;usingSystem.Collections.Generic;usingSystem.Collections.ObjectModel;usingSystem.ComponentModel;usingSystem.Diagnostics;usingSystem.Diagnostics.CodeAnalysis;usingSystem.Globalization;usingSystem.Linq;usingSystem.Net.Http;usingSystem.Net.Http.Headers;usingSystem.Web.Http;usingSystem.Web.Http.Controllers;usingSystem.Web.Http.Description;usingHousingWebApi.Areas.HelpPage.ModelDescriptions;usingHousingWebApi.Areas.HelpPage.Models;namespaceHousingWebApi.Areas.HelpPage{publicstaticclassHelpPageConfigurationExtensions{privateconststringApiModelPrefix="MS_HelpPageApiModel_";/// <summary>/// Sets the documentation provider for help page./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="documentationProvider">The documentation provider.</param>publicstaticvoidSetDocumentationProvider(thisHttpConfigurationconfig,IDocumentationProviderdocumentationProvider){config.Services.Replace(typeof(IDocumentationProvider),documentationProvider);}/// <summary>/// Sets the objects that will be used by the formatters to produce sample requests/responses./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="sampleObjects">The sample objects.</param>publicstaticvoidSetSampleObjects(thisHttpConfigurationconfig,IDictionary<Type,object>sampleObjects){config.GetHelpPageSampleGenerator().SampleObjects=sampleObjects;}/// <summary>/// Sets the sample request directly for the specified media type and action./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="sample">The sample request.</param>/// <param name="mediaType">The media type.</param>/// <param name="controllerName">Name of the controller.</param>/// <param name="actionName">Name of the action.</param>publicstaticvoidSetSampleRequest(thisHttpConfigurationconfig,objectsample,MediaTypeHeaderValuemediaType,stringcontrollerName,stringactionName){config.GetHelpPageSampleGenerator().ActionSamples.Add(newHelpPageSampleKey(mediaType,SampleDirection.Request,controllerName,actionName,new[]{"*"}),sample);}/// <summary>/// Sets the sample request directly for the specified media type and action with parameters./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="sample">The sample request.</param>/// <param name="mediaType">The media type.</param>/// <param name="controllerName">Name of the controller.</param>/// <param name="actionName">Name of the action.</param>/// <param name="parameterNames">The parameter names.</param>publicstaticvoidSetSampleRequest(thisHttpConfigurationconfig,objectsample,MediaTypeHeaderValuemediaType,stringcontrollerName,stringactionName,paramsstring[]parameterNames){config.GetHelpPageSampleGenerator().ActionSamples.Add(newHelpPageSampleKey(mediaType,SampleDirection.Request,controllerName,actionName,parameterNames),sample);}/// <summary>/// Sets the sample request directly for the specified media type of the action./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="sample">The sample response.</param>/// <param name="mediaType">The media type.</param>/// <param name="controllerName">Name of the controller.</param>/// <param name="actionName">Name of the action.</param>publicstaticvoidSetSampleResponse(thisHttpConfigurationconfig,objectsample,MediaTypeHeaderValuemediaType,stringcontrollerName,stringactionName){config.GetHelpPageSampleGenerator().ActionSamples.Add(newHelpPageSampleKey(mediaType,SampleDirection.Response,controllerName,actionName,new[]{"*"}),sample);}/// <summary>/// Sets the sample response directly for the specified media type of the action with specific parameters./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="sample">The sample response.</param>/// <param name="mediaType">The media type.</param>/// <param name="controllerName">Name of the controller.</param>/// <param name="actionName">Name of the action.</param>/// <param name="parameterNames">The parameter names.</param>publicstaticvoidSetSampleResponse(thisHttpConfigurationconfig,objectsample,MediaTypeHeaderValuemediaType,stringcontrollerName,stringactionName,paramsstring[]parameterNames){config.GetHelpPageSampleGenerator().ActionSamples.Add(newHelpPageSampleKey(mediaType,SampleDirection.Response,controllerName,actionName,parameterNames),sample);}/// <summary>/// Sets the sample directly for all actions with the specified media type./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="sample">The sample.</param>/// <param name="mediaType">The media type.</param>publicstaticvoidSetSampleForMediaType(thisHttpConfigurationconfig,objectsample,MediaTypeHeaderValuemediaType){config.GetHelpPageSampleGenerator().ActionSamples.Add(newHelpPageSampleKey(mediaType),sample);}/// <summary>/// Sets the sample directly for all actions with the specified type and media type./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="sample">The sample.</param>/// <param name="mediaType">The media type.</param>/// <param name="type">The parameter type or return type of an action.</param>publicstaticvoidSetSampleForType(thisHttpConfigurationconfig,objectsample,MediaTypeHeaderValuemediaType,Typetype){config.GetHelpPageSampleGenerator().ActionSamples.Add(newHelpPageSampleKey(mediaType,type),sample);}/// <summary>/// Specifies the actual type of <see cref="System.Net.Http.ObjectContent{T}"/> passed to the <see cref="System.Net.Http.HttpRequestMessage"/> in an action./// The help page will use this information to produce more accurate request samples./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="type">The type.</param>/// <param name="controllerName">Name of the controller.</param>/// <param name="actionName">Name of the action.</param>publicstaticvoidSetActualRequestType(thisHttpConfigurationconfig,Typetype,stringcontrollerName,stringactionName){config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(newHelpPageSampleKey(SampleDirection.Request,controllerName,actionName,new[]{"*"}),type);}/// <summary>/// Specifies the actual type of <see cref="System.Net.Http.ObjectContent{T}"/> passed to the <see cref="System.Net.Http.HttpRequestMessage"/> in an action./// The help page will use this information to produce more accurate request samples./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="type">The type.</param>/// <param name="controllerName">Name of the controller.</param>/// <param name="actionName">Name of the action.</param>/// <param name="parameterNames">The parameter names.</param>publicstaticvoidSetActualRequestType(thisHttpConfigurationconfig,Typetype,stringcontrollerName,stringactionName,paramsstring[]parameterNames){config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(newHelpPageSampleKey(SampleDirection.Request,controllerName,actionName,parameterNames),type);}/// <summary>/// Specifies the actual type of <see cref="System.Net.Http.ObjectContent{T}"/> returned as part of the <see cref="System.Net.Http.HttpRequestMessage"/> in an action./// The help page will use this information to produce more accurate response samples./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="type">The type.</param>/// <param name="controllerName">Name of the controller.</param>/// <param name="actionName">Name of the action.</param>publicstaticvoidSetActualResponseType(thisHttpConfigurationconfig,Typetype,stringcontrollerName,stringactionName){config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(newHelpPageSampleKey(SampleDirection.Response,controllerName,actionName,new[]{"*"}),type);}/// <summary>/// Specifies the actual type of <see cref="System.Net.Http.ObjectContent{T}"/> returned as part of the <see cref="System.Net.Http.HttpRequestMessage"/> in an action./// The help page will use this information to produce more accurate response samples./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="type">The type.</param>/// <param name="controllerName">Name of the controller.</param>/// <param name="actionName">Name of the action.</param>/// <param name="parameterNames">The parameter names.</param>publicstaticvoidSetActualResponseType(thisHttpConfigurationconfig,Typetype,stringcontrollerName,stringactionName,paramsstring[]parameterNames){config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(newHelpPageSampleKey(SampleDirection.Response,controllerName,actionName,parameterNames),type);}/// <summary>/// Gets the help page sample generator./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <returns>The help page sample generator.</returns>publicstaticHelpPageSampleGeneratorGetHelpPageSampleGenerator(thisHttpConfigurationconfig){return(HelpPageSampleGenerator)config.Properties.GetOrAdd(typeof(HelpPageSampleGenerator),k=>newHelpPageSampleGenerator());}/// <summary>/// Sets the help page sample generator./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="sampleGenerator">The help page sample generator.</param>publicstaticvoidSetHelpPageSampleGenerator(thisHttpConfigurationconfig,HelpPageSampleGeneratorsampleGenerator){config.Properties.AddOrUpdate(typeof(HelpPageSampleGenerator),k=>sampleGenerator,(k,o)=>sampleGenerator);}/// <summary>/// Gets the model description generator./// </summary>/// <param name="config">The configuration.</param>/// <returns>The <see cref="ModelDescriptionGenerator"/></returns>publicstaticModelDescriptionGeneratorGetModelDescriptionGenerator(thisHttpConfigurationconfig){return(ModelDescriptionGenerator)config.Properties.GetOrAdd(typeof(ModelDescriptionGenerator),k=>InitializeModelDescriptionGenerator(config));}/// <summary>/// Gets the model that represents an API displayed on the help page. The model is initialized on the first call and cached for subsequent calls./// </summary>/// <param name="config">The <see cref="HttpConfiguration"/>.</param>/// <param name="apiDescriptionId">The <see cref="ApiDescription"/> ID.</param>/// <returns>/// An <see cref="HelpPageApiModel"/>/// </returns>publicstaticHelpPageApiModelGetHelpPageApiModel(thisHttpConfigurationconfig,stringapiDescriptionId){objectmodel;stringmodelId=ApiModelPrefix+apiDescriptionId;if(!config.Properties.TryGetValue(modelId,outmodel)){Collection<ApiDescription>apiDescriptions=config.Services.GetApiExplorer().ApiDescriptions;ApiDescriptionapiDescription=apiDescriptions.FirstOrDefault(api=>String.Equals(api.GetFriendlyId(),apiDescriptionId,StringComparison.OrdinalIgnoreCase));if(apiDescription!=null){model=GenerateApiModel(apiDescription,config);config.Properties.TryAdd(modelId,model);}}return(HelpPageApiModel)model;}privatestaticHelpPageApiModelGenerateApiModel(ApiDescriptionapiDescription,HttpConfigurationconfig){HelpPageApiModelapiModel=newHelpPageApiModel(){ApiDescription=apiDescription,};ModelDescriptionGeneratormodelGenerator=config.GetModelDescriptionGenerator();HelpPageSampleGeneratorsampleGenerator=config.GetHelpPageSampleGenerator();GenerateUriParameters(apiModel,modelGenerator);GenerateRequestModelDescription(apiModel,modelGenerator,sampleGenerator);GenerateResourceDescription(apiModel,modelGenerator);GenerateSamples(apiModel,sampleGenerator);returnapiModel;}privatestaticvoidGenerateUriParameters(HelpPageApiModelapiModel,ModelDescriptionGeneratormodelGenerator){ApiDescriptionapiDescription=apiModel.ApiDescription;foreach(ApiParameterDescriptionapiParameterinapiDescription.ParameterDescriptions){if(apiParameter.Source==ApiParameterSource.FromUri){HttpParameterDescriptorparameterDescriptor=apiParameter.ParameterDescriptor;TypeparameterType=null;ModelDescriptiontypeDescription=null;ComplexTypeModelDescriptioncomplexTypeDescription=null;if(parameterDescriptor!=null){parameterType=parameterDescriptor.ParameterType;typeDescription=modelGenerator.GetOrCreateModelDescription(parameterType);complexTypeDescription=typeDescriptionasComplexTypeModelDescription;}// Example:// [TypeConverter(typeof(PointConverter))]// public class Point// {// public Point(int x, int y)// {// X = x;// Y = y;// }// public int X { get; set; }// public int Y { get; set; }// }// Class Point is bindable with a TypeConverter, so Point will be added to UriParameters collection.// // public class Point// {// public int X { get; set; }// public int Y { get; set; }// }// Regular complex class Point will have properties X and Y added to UriParameters collection.if(complexTypeDescription!=null&&!IsBindableWithTypeConverter(parameterType)){foreach(ParameterDescriptionuriParameterincomplexTypeDescription.Properties){apiModel.UriParameters.Add(uriParameter);}}elseif(parameterDescriptor!=null){ParameterDescriptionuriParameter=AddParameterDescription(apiModel,apiParameter,typeDescription);if(!parameterDescriptor.IsOptional){uriParameter.Annotations.Add(newParameterAnnotation(){Documentation="Required"});}objectdefaultValue=parameterDescriptor.DefaultValue;if(defaultValue!=null){uriParameter.Annotations.Add(newParameterAnnotation(){Documentation="Default value is "+Convert.ToString(defaultValue,CultureInfo.InvariantCulture)});}}else{Debug.Assert(parameterDescriptor==null);// If parameterDescriptor is null, this is an undeclared route parameter which only occurs// when source is FromUri. Ignored in request model and among resource parameters but listed// as a simple string here.ModelDescriptionmodelDescription=modelGenerator.GetOrCreateModelDescription(typeof(string));AddParameterDescription(apiModel,apiParameter,modelDescription);}}}}privatestaticboolIsBindableWithTypeConverter(TypeparameterType){if(parameterType==null){returnfalse;}returnTypeDescriptor.GetConverter(parameterType).CanConvertFrom(typeof(string));}privatestaticParameterDescriptionAddParameterDescription(HelpPageApiModelapiModel,ApiParameterDescriptionapiParameter,ModelDescriptiontypeDescription){ParameterDescriptionparameterDescription=newParameterDescription{Name=apiParameter.Name,Documentation=apiParameter.Documentation,TypeDescription=typeDescription,};apiModel.UriParameters.Add(parameterDescription);returnparameterDescription;}privatestaticvoidGenerateRequestModelDescription(HelpPageApiModelapiModel,ModelDescriptionGeneratormodelGenerator,HelpPageSampleGeneratorsampleGenerator){ApiDescriptionapiDescription=apiModel.ApiDescription;foreach(ApiParameterDescriptionapiParameterinapiDescription.ParameterDescriptions){if(apiParameter.Source==ApiParameterSource.FromBody){TypeparameterType=apiParameter.ParameterDescriptor.ParameterType;apiModel.RequestModelDescription=modelGenerator.GetOrCreateModelDescription(parameterType);apiModel.RequestDocumentation=apiParameter.Documentation;}elseif(apiParameter.ParameterDescriptor!=null&&apiParameter.ParameterDescriptor.ParameterType==typeof(HttpRequestMessage)){TypeparameterType=sampleGenerator.ResolveHttpRequestMessageType(apiDescription);if(parameterType!=null){apiModel.RequestModelDescription=modelGenerator.GetOrCreateModelDescription(parameterType);}}}}privatestaticvoidGenerateResourceDescription(HelpPageApiModelapiModel,ModelDescriptionGeneratormodelGenerator){ResponseDescriptionresponse=apiModel.ApiDescription.ResponseDescription;TyperesponseType=response.ResponseType??response.DeclaredType;if(responseType!=null&&responseType!=typeof(void)){apiModel.ResourceDescription=modelGenerator.GetOrCreateModelDescription(responseType);}}[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "The exception is recorded as ErrorMessages.")]privatestaticvoidGenerateSamples(HelpPageApiModelapiModel,HelpPageSampleGeneratorsampleGenerator){try{foreach(variteminsampleGenerator.GetSampleRequests(apiModel.ApiDescription)){apiModel.SampleRequests.Add(item.Key,item.Value);LogInvalidSampleAsError(apiModel,item.Value);}foreach(variteminsampleGenerator.GetSampleResponses(apiModel.ApiDescription)){apiModel.SampleResponses.Add(item.Key,item.Value);LogInvalidSampleAsError(apiModel,item.Value);}}catch(Exceptione){apiModel.ErrorMessages.Add(String.Format(CultureInfo.CurrentCulture,"An exception has occurred while generating the sample. Exception message: {0}",HelpPageSampleGenerator.UnwrapException(e).Message));}}privatestaticboolTryGetResourceParameter(ApiDescriptionapiDescription,HttpConfigurationconfig,outApiParameterDescriptionparameterDescription,outTyperesourceType){parameterDescription=apiDescription.ParameterDescriptions.FirstOrDefault(p=>p.Source==ApiParameterSource.FromBody||(p.ParameterDescriptor!=null&&p.ParameterDescriptor.ParameterType==typeof(HttpRequestMessage)));if(parameterDescription==null){resourceType=null;returnfalse;}resourceType=parameterDescription.ParameterDescriptor.ParameterType;if(resourceType==typeof(HttpRequestMessage)){HelpPageSampleGeneratorsampleGenerator=config.GetHelpPageSampleGenerator();resourceType=sampleGenerator.ResolveHttpRequestMessageType(apiDescription);}if(resourceType==null){parameterDescription=null;returnfalse;}returntrue;}privatestaticModelDescriptionGeneratorInitializeModelDescriptionGenerator(HttpConfigurationconfig){ModelDescriptionGeneratormodelGenerator=newModelDescriptionGenerator(config);Collection<ApiDescription>apis=config.Services.GetApiExplorer().ApiDescriptions;foreach(ApiDescriptionapiinapis){ApiParameterDescriptionparameterDescription;TypeparameterType;if(TryGetResourceParameter(api,config,outparameterDescription,outparameterType)){modelGenerator.GetOrCreateModelDescription(parameterType);}}returnmodelGenerator;}privatestaticvoidLogInvalidSampleAsError(HelpPageApiModelapiModel,objectsample){InvalidSampleinvalidSample=sampleasInvalidSample;if(invalidSample!=null){apiModel.ErrorMessages.Add(invalidSample.ErrorMessage);}}}}