private static void AddUndeclaredRouteParameters(HttpParsedRoute parsedRoute, IDictionary <string, object> routeDefaults, IList <ApiParameterDescription> parameterDescriptions) { foreach (PathSegment path in parsedRoute.PathSegments) { PathContentSegment content = path as PathContentSegment; if (content != null) { foreach (PathSubsegment subSegment in content.Subsegments) { PathParameterSubsegment parameter = subSegment as PathParameterSubsegment; if (parameter != null) { object parameterValue; string parameterName = parameter.ParameterName; if (!parameterDescriptions.Any(p => String.Equals(p.Name, parameterName, StringComparison.OrdinalIgnoreCase)) && (!routeDefaults.TryGetValue(parameterName, out parameterValue) || parameterValue != RouteParameter.Optional)) { parameterDescriptions.Add( new ApiParameterDescription { Name = parameterName, Source = ApiParameterSource.FromUri }); } } } } } }
private static bool TryExpandUriParameters(IHttpRoute route, string routeTemplate, ICollection <ApiParameterDescription> parameterDescriptions, out string expandedRouteTemplate) { HttpParsedRoute parsedRoute = HttpRouteParser.Parse(routeTemplate); Dictionary <string, object> parameterValuesForRoute = new Dictionary <string, object>(); foreach (ApiParameterDescription parameterDescriptor in parameterDescriptions) { Type parameterType = parameterDescriptor.ParameterDescriptor.ParameterType; if (parameterDescriptor.Source == ApiParameterSource.FromUri && TypeHelper.IsSimpleUnderlyingType(parameterType)) { parameterValuesForRoute.Add(parameterDescriptor.Name, "{" + parameterDescriptor.Name + "}"); } } BoundRouteTemplate boundRouteTemplate = parsedRoute.Bind(null, parameterValuesForRoute, new HttpRouteValueDictionary(route.Defaults), new HttpRouteValueDictionary(route.Constraints)); if (boundRouteTemplate == null) { expandedRouteTemplate = null; return(false); } expandedRouteTemplate = Uri.UnescapeDataString(boundRouteTemplate.BoundTemplate); return(true); }
private static int Compare(RouteEntry entry1, RouteEntry entry2) #endif { #if ASPNETWEBAPI HttpParsedRoute parsedRoute1 = entry1.ParsedRoute; HttpParsedRoute parsedRoute2 = entry2.ParsedRoute; #else ParsedRoute parsedRoute1 = entry1.ParsedRoute; ParsedRoute parsedRoute2 = entry2.ParsedRoute; #endif IList <PathContentSegment> segments1 = parsedRoute1.PathSegments.OfType <PathContentSegment>().ToArray(); IList <PathContentSegment> segments2 = parsedRoute2.PathSegments.OfType <PathContentSegment>().ToArray(); for (int i = 0; i < segments1.Count && i < segments2.Count; i++) { PathContentSegment segment1 = segments1[i]; PathContentSegment segment2 = segments2[i]; int order1 = GetOrder(segment1, entry1.Route.Constraints); int order2 = GetOrder(segment2, entry2.Route.Constraints); if (order1 > order2) { return(1); } else if (order1 < order2) { return(-1); } } return(0); }
private void PopulateActionDescriptions(HttpActionDescriptor actionDescriptor, IHttpRoute route, string localPath, Collection <ApiDescription> apiDescriptions) { string apiDocumentation = GetApiDocumentation(actionDescriptor); HttpParsedRoute parsedRoute = RouteParser.Parse(localPath); // parameters IList <ApiParameterDescription> parameterDescriptions = CreateParameterDescriptions(actionDescriptor, parsedRoute, route.Defaults); // expand all parameter variables string finalPath; if (!TryExpandUriParameters(route, parsedRoute, parameterDescriptions, out finalPath)) { // the action cannot be reached due to parameter mismatch, e.g. routeTemplate = "/users/{name}" and GetUsers(id) return; } // request formatters ApiParameterDescription bodyParameter = parameterDescriptions.FirstOrDefault(description => description.Source == ApiParameterSource.FromBody); IEnumerable <MediaTypeFormatter> supportedRequestBodyFormatters = bodyParameter != null? actionDescriptor.Configuration.Formatters.Where(f => f.CanReadType(bodyParameter.ParameterDescriptor.ParameterType)) : Enumerable.Empty <MediaTypeFormatter>(); // response formatters ResponseDescription responseDescription = CreateResponseDescription(actionDescriptor); Type returnType = responseDescription.ResponseType ?? responseDescription.DeclaredType; IEnumerable <MediaTypeFormatter> supportedResponseFormatters = (returnType != null && returnType != typeof(void)) ? actionDescriptor.Configuration.Formatters.Where(f => f.CanWriteType(returnType)) : Enumerable.Empty <MediaTypeFormatter>(); // Replacing the formatter tracers with formatters if tracers are present. supportedRequestBodyFormatters = GetInnerFormatters(supportedRequestBodyFormatters); supportedResponseFormatters = GetInnerFormatters(supportedResponseFormatters); // get HttpMethods supported by an action. Usually there is one HttpMethod per action but we allow multiple of them per action as well. IList <HttpMethod> supportedMethods = GetHttpMethodsSupportedByAction(route, actionDescriptor); foreach (HttpMethod method in supportedMethods) { apiDescriptions.Add(new ApiDescription { Documentation = apiDocumentation, HttpMethod = method, RelativePath = finalPath, ActionDescriptor = actionDescriptor, Route = route, SupportedResponseFormatters = new Collection <MediaTypeFormatter>(supportedResponseFormatters.ToList()), SupportedRequestBodyFormatters = new Collection <MediaTypeFormatter>(supportedRequestBodyFormatters.ToList()), ParameterDescriptions = new Collection <ApiParameterDescription>(parameterDescriptions), ResponseDescription = responseDescription }); } }
private static decimal Compute(string template) { DefaultInlineConstraintResolver resolver = new DefaultInlineConstraintResolver(); HttpRouteValueDictionary defaults = new HttpRouteValueDictionary(); HttpRouteValueDictionary constraints = new HttpRouteValueDictionary(); string standardRouteTemplate = InlineRouteTemplateParser.ParseRouteTemplate(template, defaults, constraints, new DefaultInlineConstraintResolver()); HttpParsedRoute parsedRoute = HttpRouteParser.Parse(standardRouteTemplate); return(RoutePrecedence.Compute(parsedRoute, constraints)); }
// Set as internal for the unit test. internal static bool TryExpandUriParameters(IHttpRoute route, HttpParsedRoute parsedRoute, ICollection <ApiParameterDescription> parameterDescriptions, out string expandedRouteTemplate) { Dictionary <string, object> parameterValuesForRoute = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase); bool emitPrefixes = ShouldEmitPrefixes(parameterDescriptions); string prefix = String.Empty; foreach (ApiParameterDescription parameterDescriptor in parameterDescriptions) { if (parameterDescriptor.Source == ApiParameterSource.FromUri) { if (parameterDescriptor.ParameterDescriptor == null || (parameterDescriptor.ParameterDescriptor != null && TypeHelper.CanConvertFromString(parameterDescriptor.ParameterDescriptor.ParameterType))) { if (!parameterValuesForRoute.ContainsKey(parameterDescriptor.Name)) { parameterValuesForRoute.Add(parameterDescriptor.Name, "{" + parameterDescriptor.Name + "}"); } } else if (parameterDescriptor.ParameterDescriptor != null && parameterDescriptor.CanConvertPropertiesFromString()) { if (emitPrefixes) { prefix = parameterDescriptor.Name + "."; } // Inserting the individual properties of the object in the query string // as all the complex object can not be converted from string, but all its // individual properties can. foreach (PropertyInfo property in parameterDescriptor.GetBindableProperties()) { string queryParameterName = prefix + property.Name; if (!parameterValuesForRoute.ContainsKey(queryParameterName)) { parameterValuesForRoute.Add(queryParameterName, "{" + queryParameterName + "}"); } } } } } BoundRouteTemplate boundRouteTemplate = parsedRoute.Bind(null, parameterValuesForRoute, new HttpRouteValueDictionary(route.Defaults), new HttpRouteValueDictionary(route.Constraints)); if (boundRouteTemplate == null) { expandedRouteTemplate = null; return(false); } expandedRouteTemplate = Uri.UnescapeDataString(boundRouteTemplate.BoundTemplate); return(true); }
private IList <ApiParameterDescription> CreateParameterDescriptions( HttpActionDescriptor actionDescriptor, HttpParsedRoute parsedRoute, IDictionary <string, object> routeDefaults ) { IList <ApiParameterDescription> parameterDescriptions = new List <ApiParameterDescription>(); HttpActionBinding actionBinding = GetActionBinding(actionDescriptor); // try get parameter binding information if available if (actionBinding != null) { HttpParameterBinding[] parameterBindings = actionBinding.ParameterBindings; if (parameterBindings != null) { foreach (HttpParameterBinding parameter in parameterBindings) { parameterDescriptions.Add(CreateParameterDescriptionFromBinding(parameter)); } } } else { Collection <HttpParameterDescriptor> parameters = actionDescriptor.GetParameters(); if (parameters != null) { foreach (HttpParameterDescriptor parameter in parameters) { parameterDescriptions.Add( CreateParameterDescriptionFromDescriptor(parameter) ); } } } // Adding route parameters not declared on the action. We're doing this because route parameters may or // may not be part of the action parameters and we want to have them in the description. AddUndeclaredRouteParameters(parsedRoute, routeDefaults, parameterDescriptions); return(parameterDescriptions); }
// Set as internal for the unit test. internal static bool TryExpandUriParameters(IHttpRoute route, HttpParsedRoute parsedRoute, ICollection <ApiParameterDescription> parameterDescriptions, out string expandedRouteTemplate) { Dictionary <string, object> parameterValuesForRoute = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase); bool emitPrefixes = ShouldEmitPrefixes(parameterDescriptions); string prefix = String.Empty; foreach (ApiParameterDescription parameterDescription in parameterDescriptions) { if (parameterDescription.Source == ApiParameterSource.FromUri) { if (parameterDescription.ParameterDescriptor == null) { // Undeclared route parameter handling generates query string like // "?name={name}" AddPlaceholder(parameterValuesForRoute, parameterDescription.Name); } else if (TypeHelper.CanConvertFromString(parameterDescription.ParameterDescriptor.ParameterType)) { // Simple type generates query string like // "?name={name}" AddPlaceholder(parameterValuesForRoute, parameterDescription.Name); } else if (IsBindableCollection(parameterDescription.ParameterDescriptor.ParameterType)) { string parameterName = parameterDescription.ParameterDescriptor.ParameterName; Type innerType = GetCollectionElementType(parameterDescription.ParameterDescriptor.ParameterType); PropertyInfo[] innerTypeProperties = ApiParameterDescription.GetBindableProperties(innerType).ToArray(); if (innerTypeProperties.Any()) { // Complex array and collection generate query string like // "?name[0].foo={name[0].foo}&name[0].bar={name[0].bar} // &name[1].foo={name[1].foo}&name[1].bar={name[1].bar}" AddPlaceholderForProperties(parameterValuesForRoute, innerTypeProperties, parameterName + "[0]."); AddPlaceholderForProperties(parameterValuesForRoute, innerTypeProperties, parameterName + "[1]."); } else { // Simple array and collection generate query string like // "?name[0]={name[0]}&name[1]={name[1]}". AddPlaceholder(parameterValuesForRoute, parameterName + "[0]"); AddPlaceholder(parameterValuesForRoute, parameterName + "[1]"); } } else if (IsBindableKeyValuePair(parameterDescription.ParameterDescriptor.ParameterType)) { // KeyValuePair generates query string like // "?key={key}&value={value}" AddPlaceholder(parameterValuesForRoute, "key"); AddPlaceholder(parameterValuesForRoute, "value"); } else if (IsBindableDictionry(parameterDescription.ParameterDescriptor.ParameterType)) { // Dictionary generates query string like // "?dict[0].key={dict[0].key}&dict[0].value={dict[0].value} // &dict[1].key={dict[1].key}&dict[1].value={dict[1].value}" string parameterName = parameterDescription.ParameterDescriptor.ParameterName; AddPlaceholder(parameterValuesForRoute, parameterName + "[0].key"); AddPlaceholder(parameterValuesForRoute, parameterName + "[0].value"); AddPlaceholder(parameterValuesForRoute, parameterName + "[1].key"); AddPlaceholder(parameterValuesForRoute, parameterName + "[1].value"); } else if (parameterDescription.CanConvertPropertiesFromString()) { if (emitPrefixes) { prefix = parameterDescription.Name + "."; } // Inserting the individual properties of the object in the query string // as all the complex object can not be converted from string, but all its // individual properties can. AddPlaceholderForProperties(parameterValuesForRoute, parameterDescription.GetBindableProperties(), prefix); } } } BoundRouteTemplate boundRouteTemplate = parsedRoute.Bind(null, parameterValuesForRoute, new HttpRouteValueDictionary(route.Defaults), new HttpRouteValueDictionary(route.Constraints)); if (boundRouteTemplate == null) { expandedRouteTemplate = null; return(false); } expandedRouteTemplate = Uri.UnescapeDataString(boundRouteTemplate.BoundTemplate); return(true); }