468 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C#
		
	
	
	
		
		
			
		
	
	
			468 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C#
		
	
	
	
|  | using System; | ||
|  | using System.Collections.Generic; | ||
|  | using System.Collections.ObjectModel; | ||
|  | using System.ComponentModel; | ||
|  | using System.Diagnostics; | ||
|  | using System.Diagnostics.CodeAnalysis; | ||
|  | using System.Globalization; | ||
|  | using System.Linq; | ||
|  | using System.Net.Http; | ||
|  | using System.Net.Http.Headers; | ||
|  | using System.Web.Http; | ||
|  | using System.Web.Http.Controllers; | ||
|  | using System.Web.Http.Description; | ||
|  | using WebAPI.Areas.HelpPage.ModelDescriptions; | ||
|  | using WebAPI.Areas.HelpPage.Models; | ||
|  | 
 | ||
|  | namespace WebAPI.Areas.HelpPage | ||
|  | { | ||
|  |     public static class HelpPageConfigurationExtensions | ||
|  |     { | ||
|  |         private const string ApiModelPrefix = "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> | ||
|  |         public static void SetDocumentationProvider(this HttpConfiguration config, IDocumentationProvider documentationProvider) | ||
|  |         { | ||
|  |             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> | ||
|  |         public static void SetSampleObjects(this HttpConfiguration config, 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> | ||
|  |         public static void SetSampleRequest(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, string controllerName, string actionName) | ||
|  |         { | ||
|  |             config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(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> | ||
|  |         public static void SetSampleRequest(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, string controllerName, string actionName, params string[] parameterNames) | ||
|  |         { | ||
|  |             config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(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> | ||
|  |         public static void SetSampleResponse(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, string controllerName, string actionName) | ||
|  |         { | ||
|  |             config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(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> | ||
|  |         public static void SetSampleResponse(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, string controllerName, string actionName, params string[] parameterNames) | ||
|  |         { | ||
|  |             config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(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> | ||
|  |         public static void SetSampleForMediaType(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType) | ||
|  |         { | ||
|  |             config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(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> | ||
|  |         public static void SetSampleForType(this HttpConfiguration config, object sample, MediaTypeHeaderValue mediaType, Type type) | ||
|  |         { | ||
|  |             config.GetHelpPageSampleGenerator().ActionSamples.Add(new HelpPageSampleKey(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> | ||
|  |         public static void SetActualRequestType(this HttpConfiguration config, Type type, string controllerName, string actionName) | ||
|  |         { | ||
|  |             config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(new HelpPageSampleKey(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> | ||
|  |         public static void SetActualRequestType(this HttpConfiguration config, Type type, string controllerName, string actionName, params string[] parameterNames) | ||
|  |         { | ||
|  |             config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(new HelpPageSampleKey(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> | ||
|  |         public static void SetActualResponseType(this HttpConfiguration config, Type type, string controllerName, string actionName) | ||
|  |         { | ||
|  |             config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(new HelpPageSampleKey(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> | ||
|  |         public static void SetActualResponseType(this HttpConfiguration config, Type type, string controllerName, string actionName, params string[] parameterNames) | ||
|  |         { | ||
|  |             config.GetHelpPageSampleGenerator().ActualHttpMessageTypes.Add(new HelpPageSampleKey(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> | ||
|  |         public static HelpPageSampleGenerator GetHelpPageSampleGenerator(this HttpConfiguration config) | ||
|  |         { | ||
|  |             return (HelpPageSampleGenerator)config.Properties.GetOrAdd( | ||
|  |                 typeof(HelpPageSampleGenerator), | ||
|  |                 k => new HelpPageSampleGenerator()); | ||
|  |         } | ||
|  | 
 | ||
|  |         /// <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> | ||
|  |         public static void SetHelpPageSampleGenerator(this HttpConfiguration config, HelpPageSampleGenerator sampleGenerator) | ||
|  |         { | ||
|  |             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> | ||
|  |         public static ModelDescriptionGenerator GetModelDescriptionGenerator(this HttpConfiguration config) | ||
|  |         { | ||
|  |             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> | ||
|  |         public static HelpPageApiModel GetHelpPageApiModel(this HttpConfiguration config, string apiDescriptionId) | ||
|  |         { | ||
|  |             object model; | ||
|  |             string modelId = ApiModelPrefix + apiDescriptionId; | ||
|  |             if (!config.Properties.TryGetValue(modelId, out model)) | ||
|  |             { | ||
|  |                 Collection<ApiDescription> apiDescriptions = config.Services.GetApiExplorer().ApiDescriptions; | ||
|  |                 ApiDescription apiDescription = 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; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static HelpPageApiModel GenerateApiModel(ApiDescription apiDescription, HttpConfiguration config) | ||
|  |         { | ||
|  |             HelpPageApiModel apiModel = new HelpPageApiModel() | ||
|  |             { | ||
|  |                 ApiDescription = apiDescription, | ||
|  |             }; | ||
|  | 
 | ||
|  |             ModelDescriptionGenerator modelGenerator = config.GetModelDescriptionGenerator(); | ||
|  |             HelpPageSampleGenerator sampleGenerator = config.GetHelpPageSampleGenerator(); | ||
|  |             GenerateUriParameters(apiModel, modelGenerator); | ||
|  |             GenerateRequestModelDescription(apiModel, modelGenerator, sampleGenerator); | ||
|  |             GenerateResourceDescription(apiModel, modelGenerator); | ||
|  |             GenerateSamples(apiModel, sampleGenerator); | ||
|  | 
 | ||
|  |             return apiModel; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void GenerateUriParameters(HelpPageApiModel apiModel, ModelDescriptionGenerator modelGenerator) | ||
|  |         { | ||
|  |             ApiDescription apiDescription = apiModel.ApiDescription; | ||
|  |             foreach (ApiParameterDescription apiParameter in apiDescription.ParameterDescriptions) | ||
|  |             { | ||
|  |                 if (apiParameter.Source == ApiParameterSource.FromUri) | ||
|  |                 { | ||
|  |                     HttpParameterDescriptor parameterDescriptor = apiParameter.ParameterDescriptor; | ||
|  |                     Type parameterType = null; | ||
|  |                     ModelDescription typeDescription = null; | ||
|  |                     ComplexTypeModelDescription complexTypeDescription = null; | ||
|  |                     if (parameterDescriptor != null) | ||
|  |                     { | ||
|  |                         parameterType = parameterDescriptor.ParameterType; | ||
|  |                         typeDescription = modelGenerator.GetOrCreateModelDescription(parameterType); | ||
|  |                         complexTypeDescription = typeDescription as ComplexTypeModelDescription; | ||
|  |                     } | ||
|  | 
 | ||
|  |                     // 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 (ParameterDescription uriParameter in complexTypeDescription.Properties) | ||
|  |                         { | ||
|  |                             apiModel.UriParameters.Add(uriParameter); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     else if (parameterDescriptor != null) | ||
|  |                     { | ||
|  |                         ParameterDescription uriParameter = | ||
|  |                             AddParameterDescription(apiModel, apiParameter, typeDescription); | ||
|  | 
 | ||
|  |                         if (!parameterDescriptor.IsOptional) | ||
|  |                         { | ||
|  |                             uriParameter.Annotations.Add(new ParameterAnnotation() { Documentation = "Required" }); | ||
|  |                         } | ||
|  | 
 | ||
|  |                         object defaultValue = parameterDescriptor.DefaultValue; | ||
|  |                         if (defaultValue != null) | ||
|  |                         { | ||
|  |                             uriParameter.Annotations.Add(new ParameterAnnotation() { 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. | ||
|  |                         ModelDescription modelDescription = modelGenerator.GetOrCreateModelDescription(typeof(string)); | ||
|  |                         AddParameterDescription(apiModel, apiParameter, modelDescription); | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private static bool IsBindableWithTypeConverter(Type parameterType) | ||
|  |         { | ||
|  |             if (parameterType == null) | ||
|  |             { | ||
|  |                 return false; | ||
|  |             } | ||
|  | 
 | ||
|  |             return TypeDescriptor.GetConverter(parameterType).CanConvertFrom(typeof(string)); | ||
|  |         } | ||
|  | 
 | ||
|  |         private static ParameterDescription AddParameterDescription(HelpPageApiModel apiModel, | ||
|  |             ApiParameterDescription apiParameter, ModelDescription typeDescription) | ||
|  |         { | ||
|  |             ParameterDescription parameterDescription = new ParameterDescription | ||
|  |             { | ||
|  |                 Name = apiParameter.Name, | ||
|  |                 Documentation = apiParameter.Documentation, | ||
|  |                 TypeDescription = typeDescription, | ||
|  |             }; | ||
|  | 
 | ||
|  |             apiModel.UriParameters.Add(parameterDescription); | ||
|  |             return parameterDescription; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void GenerateRequestModelDescription(HelpPageApiModel apiModel, ModelDescriptionGenerator modelGenerator, HelpPageSampleGenerator sampleGenerator) | ||
|  |         { | ||
|  |             ApiDescription apiDescription = apiModel.ApiDescription; | ||
|  |             foreach (ApiParameterDescription apiParameter in apiDescription.ParameterDescriptions) | ||
|  |             { | ||
|  |                 if (apiParameter.Source == ApiParameterSource.FromBody) | ||
|  |                 { | ||
|  |                     Type parameterType = apiParameter.ParameterDescriptor.ParameterType; | ||
|  |                     apiModel.RequestModelDescription = modelGenerator.GetOrCreateModelDescription(parameterType); | ||
|  |                     apiModel.RequestDocumentation = apiParameter.Documentation; | ||
|  |                 } | ||
|  |                 else if (apiParameter.ParameterDescriptor != null && | ||
|  |                     apiParameter.ParameterDescriptor.ParameterType == typeof(HttpRequestMessage)) | ||
|  |                 { | ||
|  |                     Type parameterType = sampleGenerator.ResolveHttpRequestMessageType(apiDescription); | ||
|  | 
 | ||
|  |                     if (parameterType != null) | ||
|  |                     { | ||
|  |                         apiModel.RequestModelDescription = modelGenerator.GetOrCreateModelDescription(parameterType); | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void GenerateResourceDescription(HelpPageApiModel apiModel, ModelDescriptionGenerator modelGenerator) | ||
|  |         { | ||
|  |             ResponseDescription response = apiModel.ApiDescription.ResponseDescription; | ||
|  |             Type responseType = 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.")] | ||
|  |         private static void GenerateSamples(HelpPageApiModel apiModel, HelpPageSampleGenerator sampleGenerator) | ||
|  |         { | ||
|  |             try | ||
|  |             { | ||
|  |                 foreach (var item in sampleGenerator.GetSampleRequests(apiModel.ApiDescription)) | ||
|  |                 { | ||
|  |                     apiModel.SampleRequests.Add(item.Key, item.Value); | ||
|  |                     LogInvalidSampleAsError(apiModel, item.Value); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 foreach (var item in sampleGenerator.GetSampleResponses(apiModel.ApiDescription)) | ||
|  |                 { | ||
|  |                     apiModel.SampleResponses.Add(item.Key, item.Value); | ||
|  |                     LogInvalidSampleAsError(apiModel, item.Value); | ||
|  |                 } | ||
|  |             } | ||
|  |             catch (Exception e) | ||
|  |             { | ||
|  |                 apiModel.ErrorMessages.Add(String.Format(CultureInfo.CurrentCulture, | ||
|  |                     "An exception has occurred while generating the sample. Exception message: {0}", | ||
|  |                     HelpPageSampleGenerator.UnwrapException(e).Message)); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private static bool TryGetResourceParameter(ApiDescription apiDescription, HttpConfiguration config, out ApiParameterDescription parameterDescription, out Type resourceType) | ||
|  |         { | ||
|  |             parameterDescription = apiDescription.ParameterDescriptions.FirstOrDefault( | ||
|  |                 p => p.Source == ApiParameterSource.FromBody || | ||
|  |                     (p.ParameterDescriptor != null && p.ParameterDescriptor.ParameterType == typeof(HttpRequestMessage))); | ||
|  | 
 | ||
|  |             if (parameterDescription == null) | ||
|  |             { | ||
|  |                 resourceType = null; | ||
|  |                 return false; | ||
|  |             } | ||
|  | 
 | ||
|  |             resourceType = parameterDescription.ParameterDescriptor.ParameterType; | ||
|  | 
 | ||
|  |             if (resourceType == typeof(HttpRequestMessage)) | ||
|  |             { | ||
|  |                 HelpPageSampleGenerator sampleGenerator = config.GetHelpPageSampleGenerator(); | ||
|  |                 resourceType = sampleGenerator.ResolveHttpRequestMessageType(apiDescription); | ||
|  |             } | ||
|  | 
 | ||
|  |             if (resourceType == null) | ||
|  |             { | ||
|  |                 parameterDescription = null; | ||
|  |                 return false; | ||
|  |             } | ||
|  | 
 | ||
|  |             return true; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static ModelDescriptionGenerator InitializeModelDescriptionGenerator(HttpConfiguration config) | ||
|  |         { | ||
|  |             ModelDescriptionGenerator modelGenerator = new ModelDescriptionGenerator(config); | ||
|  |             Collection<ApiDescription> apis = config.Services.GetApiExplorer().ApiDescriptions; | ||
|  |             foreach (ApiDescription api in apis) | ||
|  |             { | ||
|  |                 ApiParameterDescription parameterDescription; | ||
|  |                 Type parameterType; | ||
|  |                 if (TryGetResourceParameter(api, config, out parameterDescription, out parameterType)) | ||
|  |                 { | ||
|  |                     modelGenerator.GetOrCreateModelDescription(parameterType); | ||
|  |                 } | ||
|  |             } | ||
|  |             return modelGenerator; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void LogInvalidSampleAsError(HelpPageApiModel apiModel, object sample) | ||
|  |         { | ||
|  |             InvalidSample invalidSample = sample as InvalidSample; | ||
|  |             if (invalidSample != null) | ||
|  |             { | ||
|  |                 apiModel.ErrorMessages.Add(invalidSample.ErrorMessage); | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |