internal static RouteHandlerLookupNode BuildRouteHandlerLookupTree(IEnumerable <Type> requestHandlers)
        {
            var tree = new RouteHandlerLookupNode();
            var knownRouteFragmentSets = new List <IList <string> >();

            foreach (var requestHandler in requestHandlers)
            {
                var routeAttributes = RequestHandlerDescriptor.GetRouteAttributes(requestHandler);
                if (routeAttributes.Count == 0)
                {
                    throw new InvalidOperationException(ExceptionMessageBuilder.BuildMissingRouteMessage(requestHandler));
                }

                var routeHandlerVerb  = RequestHandlerDescriptor.GetVerb(requestHandler);
                var routeFragmentSets = routeAttributes.Select(x => RouteIdentifierBuilder.BuildIdentifier(routeHandlerVerb, x.Template)).ToList();

                knownRouteFragmentSets.AddRange(routeFragmentSets);
                ScanForUnreachableRouteHandlers(knownRouteFragmentSets, routeAttributes.First().Template, requestHandler);
                ScanForUnreachableRouteParameters(routeFragmentSets, routeAttributes, requestHandler);

                foreach (var routeFragementSet in routeFragmentSets)
                {
                    tree.AddNode(routeFragementSet, requestHandler);
                }
            }

            return(tree);
        }
        internal void AddNode(IList <string> routeTemplateFragments, Type requestHandler)
        {
            var headFragment = routeTemplateFragments.First();
            var remainingTemplateFragments = routeTemplateFragments.Skip(1).ToList();

            var childNode = FindChildNode(headFragment);

            if (childNode != null)
            {
                if (remainingTemplateFragments.Any())
                {
                    childNode.AddNode(remainingTemplateFragments, requestHandler);
                }
                else
                {
                    childNode.RequestHandler = requestHandler;
                }
            }
            else
            {
                var newChildNode = new RouteHandlerLookupNode(headFragment, remainingTemplateFragments, requestHandler);
                ChildNodes.Add(newChildNode);
                if (remainingTemplateFragments.Any())
                {
                    newChildNode.AddNode(remainingTemplateFragments, requestHandler);
                }
            }
        }
        private static bool IsMatch(RouteHandlerLookupNode node, string pathFragment, Dictionary <string, string> routeParameters)
        {
            if (node.IsStaticRouteTemplateFragment)
            {
                return(node.RouteTemplateFragment.Equals(pathFragment, StringComparison.InvariantCultureIgnoreCase));
            }

            routeParameters.Add(node.RouteTemplateFragment, pathFragment);
            return(true);
        }
        private static void ScanForUnreachableRouteParameters(IEnumerable <IList <string> > routeFragmentSets, IEnumerable <RouteAttribute> routeAttributes, Type requestHandlerType)
        {
            var dynamicRouteFragments = (from routeFragmentSet in routeFragmentSets
                                         from fragment in routeFragmentSet
                                         where RouteHandlerLookupNode.IsStaticFragment(fragment) == false
                                         select RouteHandlerLookupNode.RemoveDynamicFragmentTokens(fragment)).ToList();

            if (dynamicRouteFragments.Count == 0)
            {
                return;
            }

            var propertyNames = requestHandlerType.GetProperties().Select(x => x.Name).ToList();

            var unreachableParameter = dynamicRouteFragments.FirstOrDefault(f => propertyNames.Any(n => n.Equals(f, StringComparison.InvariantCultureIgnoreCase)) == false);

            if (unreachableParameter == null)
            {
                return;
            }

            throw new InvalidOperationException(ExceptionMessageBuilder.BuildUnreachableRouteParameterMessage(routeAttributes, requestHandlerType, unreachableParameter, propertyNames));
        }
        private static RouteHandlerLookupResult FindNode(RouteHandlerLookupNode node, IList <string> pathFragments, Dictionary <string, string> routeParameters)
        {
            foreach (var childNode in node.ChildNodes)
            {
                if (IsMatch(childNode, pathFragments.First(), routeParameters) == false)
                {
                    continue;
                }

                var remainingPathFragments = pathFragments.Skip(1).ToList();
                if (remainingPathFragments.Count == 0)
                {
                    return(new RouteHandlerLookupResult(childNode.RequestHandler, routeParameters));
                }

                var requestHandler = FindNode(childNode, remainingPathFragments, routeParameters);
                if (requestHandler != null)
                {
                    return(requestHandler);
                }
            }

            return(RouteHandlerLookupResult.FailedResult);
        }
 public RequestRouter(IEnumerable <Type> requestHandlers)
 {
     _tree = RouteHandlerLookupTreeBuilder.BuildRouteHandlerLookupTree(requestHandlers);
 }