private void AddParameterDescriptionsToModel(ActionApiDescriptionModel actionModel, MethodInfo method, ApiDescription apiDescription)
        {
            if (!apiDescription.ParameterDescriptions.Any())
            {
                return;
            }

            var matchedMethodParamNames = ArrayMatcher.Match(
                apiDescription.ParameterDescriptions.Select(p => p.Name).ToArray(),
                method.GetParameters().Select(GetMethodParamName).ToArray()
            );

            for (var i = 0; i < apiDescription.ParameterDescriptions.Count; i++)
            {
                var parameterDescription = apiDescription.ParameterDescriptions[i];
                var matchedMethodParamName = matchedMethodParamNames.Length > i
                                                 ? matchedMethodParamNames[i]
                                                 : parameterDescription.Name;

                actionModel.AddParameter(new ParameterApiDescriptionModel(
                        parameterDescription.Name,
                        matchedMethodParamName,
                        parameterDescription.Type,
                        parameterDescription.RouteInfo?.IsOptional ?? false,
                        parameterDescription.RouteInfo?.DefaultValue,
                        parameterDescription.RouteInfo?.Constraints?.Select(c => c.GetType().Name).ToArray(),
                        parameterDescription.Source.Id
                    )
                );
            }
        }
        private ApiExplorerData CreateSerializableData(ApiDescription description)
        {
            var data = new ApiExplorerData()
            {
                GroupName = description.GroupName,
                HttpMethod = description.HttpMethod,
                RelativePath = description.RelativePath
            };

            foreach (var parameter in description.ParameterDescriptions)
            {
                var parameterData = new ApiExplorerParameterData()
                {
                    Name = parameter.Name,
                    Source = parameter.Source.Id,
                    Type = parameter.Type?.FullName,
                };

                if (parameter.RouteInfo != null)
                {
                    parameterData.RouteInfo = new ApiExplorerParameterRouteInfo()
                    {
                        ConstraintTypes = parameter.RouteInfo.Constraints?.Select(c => c.GetType().Name).ToArray(),
                        DefaultValue = parameter.RouteInfo.DefaultValue,
                        IsOptional = parameter.RouteInfo.IsOptional,
                    };
                }

                data.ParameterDescriptions.Add(parameterData);
            }

            foreach (var response in description.SupportedResponseTypes)
            {
                var responseType = new ApiExplorerResponseType()
                {
                    StatusCode = response.StatusCode,
                    ResponseType = response.Type?.FullName
                };

                foreach(var responseFormat in response.ApiResponseFormats)
                {
                    responseType.ResponseFormats.Add(new ApiExplorerResponseFormat()
                    {
                        FormatterType = responseFormat.Formatter?.GetType().FullName,
                        MediaType = responseFormat.MediaType
                    });
                }

                data.SupportedResponseTypes.Add(responseType);
            }

            return data;
        }
        private void AddApiDescriptionToModel(ApiDescription apiDescription, ApplicationApiDescriptionModel model)
        {
            var moduleModel = model.GetOrAddModule(GetModuleName(apiDescription));
            var controllerModel = moduleModel.GetOrAddController(apiDescription.GroupName);
            var method = apiDescription.ActionDescriptor.GetMethodInfo();

            if (controllerModel.Actions.ContainsKey(method.Name))
            {
                Logger.Warn($"Controller '{controllerModel.Name}' contains more than one action with name '{method.Name}' for module '{moduleModel.Name}'. Ignored: " + apiDescription.ActionDescriptor.GetMethodInfo());
                return;
            }


            var actionModel = controllerModel.AddAction(new ActionApiDescriptionModel(
                method.Name,
                apiDescription.RelativePath,
                apiDescription.HttpMethod
            ));

            AddParameterDescriptionsToModel(actionModel, method, apiDescription);
        }
        private string GetModuleName(ApiDescription apiDescription)
        {
            var controllerType = apiDescription.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType();
            if (controllerType == null)
            {
                return AbpControllerAssemblySetting.DefaultServiceModuleName;
            }

            foreach (var controllerSetting in _configuration.ControllerAssemblySettings)
            {
                if (controllerType.Assembly == controllerSetting.Assembly)
                {
                    return controllerSetting.ModuleName;
                }
            }

            return AbpControllerAssemblySetting.DefaultServiceModuleName;
        }
        private Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription CreateApiDescription(RouteEndpoint routeEndpoint)
        {
            var httpMethodMetadata = routeEndpoint.Metadata.GetMetadata <HttpMethodMetadata>();
            var verb = httpMethodMetadata?.HttpMethods.FirstOrDefault();

            var apiDescription = new Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription();

            // Default to a GET in case a Route map was registered inline - it's unlikely to be a composition handler in that case.
            apiDescription.HttpMethod       = verb ?? "GET";
            apiDescription.ActionDescriptor = new ActionDescriptor
            {
                RouteValues = new Dictionary <string, string>
                {
                    // Swagger uses this to group endpoints together.
                    // Group methods together using the service name.
                    // NOTE: Need a metadata model in service composer to begin supplying more info other than just http verbs and route patterns.
                    ["controller"] = "ViewModelComposition"// routeEndpoint.RoutePattern.GetParameter("controller").Default.ToString()
                }
            };
            apiDescription.RelativePath = routeEndpoint.RoutePattern.RawText.TrimStart('/');
            apiDescription.SupportedRequestFormats.Add(new ApiRequestFormat {
                MediaType = "application/json"
            });

            foreach (var producesDefaultResponseTypeAttribute in routeEndpoint.Metadata.OfType <ProducesDefaultResponseTypeAttribute>())
            {
                apiDescription.SupportedResponseTypes.Add(new ApiResponseType
                {
                    Type = producesDefaultResponseTypeAttribute.Type,
                    ApiResponseFormats = { new ApiResponseFormat {
                                               MediaType = "application/json"
                                           } },
                    StatusCode        = producesDefaultResponseTypeAttribute.StatusCode,
                    IsDefaultResponse = true,
                    ModelMetadata     = _modelMetadataProvider.GetMetadataForType(producesDefaultResponseTypeAttribute.Type)
                });
            }

            foreach (var producesResponseTypeAttribute in routeEndpoint.Metadata.OfType <ProducesResponseTypeAttribute>())
            {
                apiDescription.SupportedResponseTypes.Add(new ApiResponseType
                {
                    Type = producesResponseTypeAttribute.Type,
                    ApiResponseFormats = { new ApiResponseFormat {
                                               MediaType = "application/json"
                                           } },
                    StatusCode        = producesResponseTypeAttribute.StatusCode,
                    IsDefaultResponse = false,
                    ModelMetadata     = _modelMetadataProvider.GetMetadataForType(producesResponseTypeAttribute.Type)
                });
            }

            foreach (var apiParameterDescriptionAttribute in routeEndpoint.Metadata.OfType <ApiParameterDescriptionAttribute>())
            {
                apiDescription.ParameterDescriptions.Add(new ApiParameterDescription()
                {
                    Name          = apiParameterDescriptionAttribute.Name,
                    IsRequired    = apiParameterDescriptionAttribute.IsRequired,
                    Type          = apiParameterDescriptionAttribute.Type,
                    Source        = GetBindingSource(apiParameterDescriptionAttribute.Source),
                    ModelMetadata = _modelMetadataProvider.GetMetadataForType(apiParameterDescriptionAttribute.Type)
                });
            }

            return(apiDescription);
        }