Example #1
0
        /// <inheritdoc />
        public string CreateUrl(ApiOperationLink link, object result = null)
        {
            // This duplicates the checks in CreateRelativeUrlFromLink for the purpose of not creating a new instance
            // of StringBuilder unnecessarily
            if (result == null)
            {
                return(this._baseUri + link.UrlFormat);
            }

            // We can short-circuit in the (relatively uncommon case) of no placeholders
            if (!link.HasPlaceholders())
            {
                return(this._baseUri + link.UrlFormat);
            }

            var relativeUrl = CreateRelativeUrlFromLink(link, result);

            // We cannot create a full URL if the relative link is null
            if (relativeUrl == null)
            {
                return(null);
            }

            // baseUri always has / at end, relative never has at start
            return(this._baseUri + relativeUrl);
        }
Example #2
0
        /// <inheritdoc />
        public string CreateUrl(ApiOperationLink link, object result = null)
        {
            // We can short-circuit in the (relatively uncommon case) of no placeholders
            if (!link.HasPlaceholders())
            {
                return(this._baseUri + link.UrlFormat);
            }

            var relativeUrl = link.CreateRelativeUrl(result);

            // We cannot create a full URL if the relative link is null
            if (relativeUrl == null)
            {
                return(null);
            }

            // baseUri always has / at end, relative never has at start
            return(this._baseUri + relativeUrl);
        }
Example #3
0
        private static StringBuilder CreateRelativeUrlFromLink(ApiOperationLink link, object result)
        {
            if (result == null)
            {
                return(new StringBuilder(link.UrlFormat));
            }

            // We can short-circuit in the (relatively uncommon case) of no placeholders
            if (!link.HasPlaceholders())
            {
                return(new StringBuilder(link.UrlFormat));
            }

            var builtUrl     = new StringBuilder();
            var currentIndex = 0;

            foreach (var placeholder in link.Placeholders)
            {
                // Grab the static bit of the URL _before_ this placeholder.
                builtUrl.Append(link.UrlFormat.Substring(currentIndex, placeholder.Index - currentIndex));

                // Now skip over the actual placeholder for the next iteration
                currentIndex = placeholder.Index + placeholder.Length;

                object placeholderValue;

                if (link.OperationDescriptor.OperationType == result.GetType())
                {
                    // Do not have to deal with "alternate" names, we know the original name is correct
                    placeholderValue = placeholder.Property.GetValue(result);
                }
                else
                {
                    // We cannot use the existing PropertyInfo on placeholder because the type is different, even though they are the same name
                    var property = result
                                   .GetType()
                                   .GetProperty(placeholder.AlternatePropertyName ?? placeholder.Property.Name, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);

                    if (property == null)
                    {
                        if (placeholder.AlternatePropertyName != null)
                        {
                            throw new InvalidOperationException(
                                      $"Cannot find property '{placeholder.AlternatePropertyName}' (specified as alternate name) on type '{result.GetType()}'");
                        }

                        throw new InvalidOperationException(
                                  $"Cannot find property '{placeholder.Property.Name}' on type '{result.GetType()}'");
                    }

                    placeholderValue = property.GetValue(result);
                }

                // If we have a placeholder value then we must return null if it does not exist, otherwise we would build URLs
                // like /users/null if using a "safe" representation
                if (placeholderValue == null)
                {
                    return(null);
                }

                if (placeholder.Format != null)
                {
                    builtUrl.Append(Uri.EscapeDataString(string.Format(placeholder.FormatSpecifier, placeholderValue)));
                }
                else
                {
                    // We do not have a format so just ToString the result. We pick a few common types to cast directly to avoid indirect
                    // call to ToString when doing it as (object).ToString()
                    switch (placeholderValue)
                    {
                    case string s:
                        builtUrl.Append(Uri.EscapeDataString(s));
                        break;

                    case Guid g:
                        builtUrl.Append(Uri.EscapeDataString(g.ToString()));
                        break;

                    case int i:
                        builtUrl.Append(Uri.EscapeDataString(i.ToString()));
                        break;

                    case long l:
                        builtUrl.Append(Uri.EscapeDataString(l.ToString()));
                        break;

                    default:
                        builtUrl.Append(Uri.EscapeDataString(placeholderValue.ToString()));
                        break;
                    }
                }
            }

            if (currentIndex < link.UrlFormat.Length)
            {
                builtUrl.Append(link.UrlFormat.Substring(currentIndex));
            }

            return(builtUrl);
        }