private static string GetUrlTemplate(ServiceMethodMetadata metadata, IProxyMetadata proxyMetadata)
        {
            string urlTemplate = (metadata.ServiceUrl + (metadata.UrlInfo.UrlTemplate.Length > 0 ? UrlSeparator + metadata.UrlInfo.UrlTemplate.TrimStart(UrlSeparator[0]) : UrlSeparator)).Trim(UrlSeparator[0]);

            if (proxyMetadata == null)
            {
                return urlTemplate;
            }

            var parameters = GetQueryStringParameters(metadata, proxyMetadata).Where(p => p.ExampleValue != null);
            var parameterBuilder = new StringBuilder();

            foreach (var parameter in parameters)
            {
                if (parameterBuilder.Length > 0)
                {
                    parameterBuilder.Append("&");
                }

                parameterBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}={{{0}}}", HttpUtility.UrlEncode(parameter.Name));
            }

            if (parameterBuilder.Length == 0)
            {
                return urlTemplate;
            }

            return urlTemplate + "?" + parameterBuilder;
        }
        private static Tuple<ResourceExampleMetadata, ResourceExampleMetadata> GetResourceExampleTypes(MethodInfo method, IProxyMetadata proxyMetadata)
        {
            if (proxyMetadata == null)
            {
                return new Tuple<ResourceExampleMetadata, ResourceExampleMetadata>(null, null);
            }

            ResourceExampleMetadata requestResourceExample = proxyMetadata.GetRequestResourceExample(method);
            ResourceExampleMetadata responseResourceExample = proxyMetadata.GetResponseResourceExample(method);

            return Tuple.Create(requestResourceExample, responseResourceExample);
        }
        private static AuthenticationMetadata GetCredentials(ServiceMethodMetadata metadata, IProxyMetadata proxyMetadata)
        {
            if (proxyMetadata == null)
            {
                return null;
            }

            AuthenticationMetadata authenticationInfo = proxyMetadata.GetAuthentication(metadata.MethodInfo);

            if (authenticationInfo == null)
            {
                return null;
            }

            if (!String.IsNullOrEmpty(authenticationInfo.RelativeUrlToMatch) &&
                !authenticationInfo.RelativeUrlToMatch.Trim().TrimStart('~', '/').Equals(metadata.ServiceUrl, StringComparison.OrdinalIgnoreCase))
            {
                return null;
            }

            return authenticationInfo;
        }
        private static IEnumerable<ParameterMetadata> GetRouteParameters(ServiceMethodMetadata metadata, IProxyMetadata proxyMetadata)
        {
            var routeParameters = new List<ParameterMetadata>();

            foreach (ParameterInfo parameter in metadata.MethodInfo.GetParameters())
            {
                if (metadata.UrlInfo.UrlTemplate.IndexOf(String.Concat("{", parameter.Name, "}"), StringComparison.OrdinalIgnoreCase) < 0)
                {
                    continue;
                }

                ParameterMetadata parameterMetadata = proxyMetadata != null ?
                                                                proxyMetadata.GetParameter(metadata.MethodInfo, parameter.Name, RequestParameterType.Route) :
                                                                null;

                var routeParameter = new ParameterMetadata
                {
                    Name = parameter.Name.ToLowerInvariant(),
                    ParameterType = RequestParameterType.Route,
                    Type = parameter.ParameterType,
                    IsOptionalParameter = parameter.DefaultValue != DBNull.Value,
                    RegexConstraint = GetParameterConstraint(parameter),
                    ExampleValue = parameterMetadata != null ? parameterMetadata.ExampleValue : null,
                    AllowedValues = parameterMetadata != null ? parameterMetadata.AllowedValues : null
                };

                routeParameters.Add(routeParameter);
            }

            return routeParameters;
        }
        private static IEnumerable<ParameterMetadata> GetBodyParameters(ServiceMethodMetadata metadata, IProxyMetadata proxyMetadata)
        {
            var parameters = new List<ParameterMetadata>();

            if (proxyMetadata == null)
            {
                return parameters;
            }

            foreach (var parameter in proxyMetadata.GetParameters(metadata.MethodInfo, RequestParameterType.Body))
            {
                parameters.Add(new ParameterMetadata
                {
                    Name = parameter.Name.ToLowerInvariant(),
                    ParameterType = parameter.ParameterType,
                    Type = parameter.Type,
                    IsOptionalParameter = parameter.IsOptionalParameter,
                    RegexConstraint = parameter.RegexConstraint,
                    ExampleValue = parameter.ExampleValue,
                    AllowedValues = parameter.AllowedValues
                });
            }

            var bodyParameters = metadata.MethodInfo.GetParameters()
                                                    .Where(x => Attribute.IsDefined(x, typeof(FromBodyAttribute)) &&
                                                                parameters.All(p => p.Name != x.Name.ToLowerInvariant()))
                                                    .ToArray();

            foreach (ParameterInfo bodyParameter in bodyParameters)
            {
                parameters.Add(new ParameterMetadata
                {
                    Name = bodyParameter.Name.ToLowerInvariant(),
                    ParameterType = RequestParameterType.Body,
                    Type = bodyParameter.ParameterType
                });
            }

            return parameters;
        }
        private static ICollection<ParameterMetadata> GetParameters(ServiceMethodMetadata metadata, IProxyMetadata proxyMetadata)
        {
            var parameters = new List<ParameterMetadata>(GetQueryStringParameters(metadata, proxyMetadata));
            parameters.AddRange(GetBodyParameters(metadata, proxyMetadata));
            parameters.AddRange(GetRouteParameters(metadata, proxyMetadata));

            IReadOnlyList<XmlDocMetadata> contractDocumentation;
            XmlDocMetadata methodDocumentation = null;

            var xmlDocFactory = Rest.Configuration.Options.XmlDocFactory;

            if (xmlDocFactory != null && metadata.MethodInfo.DeclaringType != null &&
                xmlDocFactory.Value.TryGetValue(metadata.MethodInfo.DeclaringType, out contractDocumentation))
            {
                methodDocumentation = contractDocumentation.FirstOrDefault(x => x.Method == metadata.MethodInfo);
            }

            if (methodDocumentation != null)
            {
                foreach (ParameterMetadata parameter in parameters)
                {
                    string description;

                    if (methodDocumentation.Parameters.TryGetValue(parameter.Name, out description))
                    {
                        parameter.Description = description;
                    }
                }
            }

            return parameters.Distinct().ToList();
        }
        private static List<StatusCodeMetadata> GetStatusCodes(MethodInfo method, IProxyMetadata proxyMetadata, bool hasResource, bool hasResponse, bool requiresHttps)
        {
            var statusCodes = new List<StatusCodeMetadata>();

            if (proxyMetadata != null)
            {
                statusCodes.AddRange(proxyMetadata.GetResponseStatuses(method));
            }

            if (hasResource)
            {
                statusCodes.Add(new StatusCodeMetadata { Code = HttpStatusCode.BadRequest, Condition = Resources.Global.InvalidResourceBody });
                statusCodes.Add(new StatusCodeMetadata { Code = HttpStatusCode.UnsupportedMediaType, Condition = Resources.Global.UnsupportedMediaType });
            }

            if (hasResponse)
            {
                statusCodes.Add(new StatusCodeMetadata { Code = HttpStatusCode.NotAcceptable, Condition = Resources.Global.NonAcceptedMediaType });
            }

            if (!statusCodes.Any(code => code.GetNumericStatusCode() >= 200 && code.GetNumericStatusCode() <= 204))
            {
                statusCodes.Add(new StatusCodeMetadata { Code = HttpStatusCode.OK, Condition = Resources.Global.SuccessfulOperation });
            }

            if (requiresHttps)
            {
                statusCodes.Add(new StatusCodeMetadata { Code = HttpStatusCode.Forbidden, Condition = Resources.Global.HttpsRequiredStatusDescription });
            }

            statusCodes.Sort((code1, code2) => code1.CompareTo(code2));

            return statusCodes;
        }
        private static string GetLongDescription(MethodInfo method, IProxyMetadata proxyMetadata, XmlDocMetadata methodDocumentation)
        {
            if (proxyMetadata == null)
            {
                return Resources.Global.MissingDescription;
            }

            string description = proxyMetadata.GetLongDescription(method);

            if (description == null && methodDocumentation != null)
            {
                description = methodDocumentation.Remarks;
            }

            return (description ?? Resources.Global.MissingDescription).Trim();
        }