public void OptionalRouteConstraintTests(object parameterValue, bool shouldCallInner, bool expected)
        {
            // Arrange
            var inner = MockConstraintWithResult((string)parameterValue != "fail");

            // Act
            var constraint = new OptionalRouteConstraint(inner.Object);

#if ASPNETWEBAPI
            var optionalParameter = RouteParameter.Optional;
#else
            var optionalParameter = UrlParameter.Optional;
#endif
            var actual = TestValue(constraint, parameterValue ?? optionalParameter, route =>
            {
                route.Defaults.Add("fake", optionalParameter);
            });

            // Assert
            Assert.Equal(expected, actual);

            var timeMatchShouldHaveBeenCalled = shouldCallInner
                ? Times.Once()
                : Times.Never();

            AssertMatchWasCalled(inner, timeMatchShouldHaveBeenCalled);
        }
Esempio n. 2
0
        /// <summary>
        /// Builds a mapping of constraints.
        /// </summary>
        /// <returns>An <see cref="IDictionary{String, IRouteConstraint}"/> of the constraints.</returns>
        public IDictionary <string, IRouteConstraint> Build()
        {
            var constraints = new Dictionary <string, IRouteConstraint>(StringComparer.OrdinalIgnoreCase);

            foreach (var kvp in _constraints)
            {
                IRouteConstraint constraint;
                if (kvp.Value.Count == 1)
                {
                    constraint = kvp.Value[0];
                }
                else
                {
                    constraint = new CompositeRouteConstraint(kvp.Value.ToArray());
                }

                if (_optionalParameters.Contains(kvp.Key))
                {
                    var optionalConstraint = new OptionalRouteConstraint(constraint);
                    constraints.Add(kvp.Key, optionalConstraint);
                }
                else
                {
                    constraints.Add(kvp.Key, constraint);
                }
            }

            return(constraints);
        }
Esempio n. 3
0
        private IParameterPolicy InitializeRouteConstraint(
            bool optional,
            IRouteConstraint routeConstraint)
        {
            if (optional)
            {
                routeConstraint = new OptionalRouteConstraint(routeConstraint);
            }

            return(routeConstraint);
        }
Esempio n. 4
0
        public void ToSwagger_ReturnsCorrectCorrespondingSwaggerDataType()
        {
            // match the IHttpRouteConstraint with the corresponding swagger data type
            foreach (var httpRouteConstraint in _swaggerDataTypeByhttpConstraint.Keys)
            {
                Assert.Equal(httpRouteConstraint.ToSwaggerDataType(), _swaggerDataTypeByhttpConstraint[httpRouteConstraint]);
            }

            // unknown type should match against string
            var unknownHttpRouteConstraint = new OptionalRouteConstraint(new IntRouteConstraint());

            Assert.Equal(unknownHttpRouteConstraint.ToSwaggerDataType(), SwaggerDataType.String);
        }
Esempio n. 5
0
        public async Task MatchAsync_MultipleMatches_EndpointSelectorCalled_AllocatesDictionaryForRouteConstraint()
        {
            // Arrange
            var constraint = new OptionalRouteConstraint(new IntRouteConstraint());
            var endpoint1  = CreateEndpoint("/Teams", 0, policies: new { x = constraint, });
            var endpoint2  = CreateEndpoint("/Teams", 1, policies: new { x = constraint, });

            var endpointSelector = new Mock <EndpointSelector>();

            endpointSelector
            .Setup(s => s.SelectAsync(It.IsAny <HttpContext>(), It.IsAny <CandidateSet>()))
            .Callback <HttpContext, CandidateSet>((c, cs) =>
            {
                Assert.Equal(2, cs.Count);

                Assert.Same(endpoint1, cs[0].Endpoint);
                Assert.True(cs.IsValidCandidate(0));
                Assert.Equal(0, cs[0].Score);
                Assert.Empty(cs[0].Values);

                Assert.Same(endpoint2, cs[1].Endpoint);
                Assert.True(cs.IsValidCandidate(1));
                Assert.Equal(1, cs[1].Score);
                Assert.Empty(cs[1].Values);

                c.SetEndpoint(endpoint2);
            })
            .Returns(Task.CompletedTask);

            var endpointDataSource = new DefaultEndpointDataSource(new List <Endpoint>
            {
                endpoint1,
                endpoint2
            });

            var matcher = CreateDfaMatcher(endpointDataSource, endpointSelector: endpointSelector.Object);

            var httpContext = CreateContext();

            httpContext.Request.Path = "/Teams";

            // Act
            await matcher.MatchAsync(httpContext);

            // Assert
            Assert.Equal(endpoint2, httpContext.GetEndpoint());
        }
        private static IRouteConstraint GetInlineConstraint(
            Group constraintGroup,
            bool isOptional,
            IInlineConstraintResolver constraintResolver
            )
#endif
        {
#if ASPNETWEBAPI
            List <IHttpRouteConstraint> parameterConstraints = new List <IHttpRouteConstraint>();
#else
            List <IRouteConstraint> parameterConstraints = new List <IRouteConstraint>();
#endif
            foreach (Capture constraintCapture in constraintGroup.Captures)
            {
                string inlineConstraint = constraintCapture.Value;
                var    constraint       = constraintResolver.ResolveConstraint(inlineConstraint);
                if (constraint == null)
                {
                    throw Error.InvalidOperation(
                              ErrorResources.HttpRouteBuilder_CouldNotResolveConstraint,
                              constraintResolver.GetType().Name,
                              inlineConstraint
                              );
                }
                parameterConstraints.Add(constraint);
            }

            if (parameterConstraints.Count > 0)
            {
                var constraint =
                    parameterConstraints.Count == 1
                        ? parameterConstraints[0]
                        : new CompoundRouteConstraint(parameterConstraints);

                if (isOptional)
                {
                    // Constraints should match RouteParameter.Optional if the parameter is optional
                    // This prevents contraining when there's no value specified
                    constraint = new OptionalRouteConstraint(constraint);
                }

                return(constraint);
            }
            return(null);
        }
Esempio n. 7
0
        public static void RegisterRoutes(this IRouteBuilder routes)
        {
            //MIGRATION: Implement middleware to redirect users to lower case URLs
            //routes.LowercaseUrls = true;

            //routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            #region Constraints

            const string formats   = "rss|atom";
            const string postKinds = "Stories|Releases|Factsheets|Updates";

            //Aug. 3/2018
            //const string categories = "Ministries|Sectors|Regions|Tags|Themes";

            //The line above has been updated. During the News work in Fall 2017 (BC Gov news public web api) and move to OpenShift
            //Regions were not implemented in the application as they were never used. Therefore to prohibit the appliation throwing
            //errors on routes containing regions, it is being removed fromt he routes.

            //If regions are reimplemented in Repository.cs and the Web API, put them back in the route table.
            const string categories = "Ministries|Sectors|Tags|Themes|News-Subscribe";

            IRouteConstraint yearConstraint               = new RegexRouteConstraint(@"^\d{4}$");
            IRouteConstraint monthConstraint              = new RegexRouteConstraint(@"^(\d{2})?$");
            IRouteConstraint formatConstraint             = new OptionalRouteConstraint(new RegexRouteConstraint(formats));
            IRouteConstraint postKindConstraint           = new OptionalRouteConstraint(new RegexRouteConstraint(postKinds));
            IRouteConstraint categoryControllerConstraint = new RegexRouteConstraint(categories);

            #endregion

            //context.MapRoute(
            //    "Newsroom_default",
            //    "Newsroom/{controller}/{action}/{id}",
            //    new { action = "Index", id = UrlParameter.Optional }
            //);

            //#region Files
            routes.MapRoute(
                name: "Newsroom-Files",
                template: "files/{*path}",
                defaults: new { controller = "Files", action = "Single" }
                );

            //#endregion

            #region Assets

            routes.MapRoute(
                name: "Newsroom-Assets-License",
                template: "assets/license",
                defaults: new { controller = "Assets", action = "License" }
                );

            routes.MapRoute(
                name: "Newsroom-Assets",
                template: "assets/{*path}",
                defaults: new { controller = "Assets", action = "Single" }
                );

            #endregion

            #region Default

            /* The Default controller supports the following URL patterns:
             *
             *   index
             *   more-news
             *   (feed | embed [format])
             *   archive [year [month]]
             *   (top | feature) feed [format]
             *   biography
             *
             */

            routes.MapRoute(
                name: "NewsroomReference",
                template: "{reference}",
                defaults: new { controller = "Default", action = "Reference" },
                constraints: new { reference = @"\d+" }
                );

            //index
            routes.MapRoute(
                name: "Newsroom",
                template: "",
                defaults: new { controller = "Default", action = "Index" }
                );

            routes.MapRoute(
                name: "Newsroom-Sitemap",
                template: "sitemap/html",
                defaults: new { controller = "Default", action = "Sitemap" }
                );

            routes.MapRoute(
                name: "Newsroom-SiteStatus",
                template: "SiteStatus",
                defaults: new { controller = "Default", action = "SiteStatus" }
                );

            routes.MapRoute(
                name: "CarouselImage",
                template: "CarouselImage/{slideId}",
                defaults: new { controller = "Default", action = "CarouselImage" }
                );

            //more-news
            routes.MapRoute(
                name: "Newsroom-MoreNews",
                template: "more-news",
                defaults: new { controller = "Default", action = "MoreNews" }
                );

            //archive [year [month]]
            {
                routes.MapRoute(
                    name: "Newsroom-Archive",
                    template: "archive",
                    defaults: new { controller = "Default", action = "Archive" }
                    );

                routes.MapRoute(
                    name: "Newsroom-Archive-Month",
                    template: "archive/{year}/{month?}",
                    defaults: new { controller = "Default", action = "Month" },
                    constraints: new { year = yearConstraint, month = monthConstraint }
                    );
            }

            //feed | embed [format]
            routes.MapRoute(
                name: "Newsroom-Action",
                template: "{action}/{format?}",
                defaults: new { controller = "Default" },
                constraints: new { action = "Feed|Embed", format = formatConstraint }
                );

            //(top | feature) feed [format]
            routes.MapRoute(
                name: "Newsroom-Special-Action",
                template: "{action}/{type}/{format?}",
                defaults: new { controller = "Default" },
                constraints: new { action = "Top|Feature", format = formatConstraint }
                );

            //(top | feature) feed [format]
            routes.MapRoute(
                name: "Newsroom-Special-Action-Feed",
                template: "{action}/{key}/{type}/{format?}",
                defaults: new { controller = "Default" },
                constraints: new { action = "CategoryTop|CategoryFeature", format = formatConstraint }
                );

            #endregion

            //biographies key
            MapRouteOptional(
                routes: routes,
                name: "Newsroom[-Parent]-Biography",
                template: "ministries[/{parentKey}]/{key}/biography",
                defaults: new { controller = "Ministries", action = "Biography" },
                constraints: null
                );

            #region Ministries, Regions, Sectors, Tags, Themes

            /* The Categories controller supports the following URL patterns:
             *
             *   category [parentKey] [postKind]
             *   category [parentKey] key [postKind]
             *   category [parentKey] key [postKind] more-news
             *   category [parentKey] key [postKind] (feed | embed [format])
             *   category [parentKey] key [postKind] archive [year [month]]
             *
             */

            //category key [postKind] more-news
            MapRouteOptional(
                routes: routes,
                name: "Newsroom[-Parent]-Category[-Type]-More",
                template: "{category}[/{parentKey}]/{key}[/{postKind?}]/more-news",
                defaults: new { controller = "Category", action = "MoreNews" },
                constraints: new { category = categoryControllerConstraint, postKind = postKindConstraint }
                );

            MapRouteOptional(
                routes: routes,
                name: "Newsroom[-Parent]-Category[-Type]-MoreArticles",
                template: "{category}[/{parentKey}]/{key}[/{postKind?}]/morearticles",
                defaults: new { controller = "Category", action = "MoreArticles" },
                constraints: new { category = categoryControllerConstraint, postKind = postKindConstraint }
                );

            //category key [postKind] archive [year [month]]
            {
                //i.e. category key [postKind] archive
                MapRouteOptional(
                    routes: routes,
                    name: "Newsroom[-Parent]-Category[-Type]-Archive",
                    template: "{category}[/{parentKey}]/{key}[/{postKind?}]/archive",
                    defaults: new { controller = "Category", action = "Archive" },
                    constraints: new { category = categoryControllerConstraint, postKind = postKindConstraint }
                    );

                //i.e. category key [postKind] archive year [month]
                MapRouteOptional(
                    routes: routes,
                    name: "Newsroom[-Parent]-Category[-Type]-Archive-Year",
                    template: "{category}[/{parentKey}]/{key}[/{postKind?}]/archive/{year}/{month?}",
                    defaults: new { controller = "Category", action = "Month" },
                    constraints: new { category = categoryControllerConstraint, year = yearConstraint, month = monthConstraint, postKind = postKindConstraint }
                    );
            }

            //category [parent] key [postKind] (feed | embed [format])
            MapRouteOptional(
                routes: routes,
                name: "Newsroom[-Parent]-Category[-Type]-Action",
                template: "{category}[/{parentKey}]/{key}[/{postKind?}]/{action}/{format?}",
                defaults: new { controller = "Category" },
                constraints: new { category = categoryControllerConstraint, postKind = postKindConstraint, action = "Feed|Embed", format = formatConstraint }
                );

            //category [parent] key [postKind]
            MapRouteOptional(
                routes: routes,
                name: "Newsroom[-Parent]-Category-Type",
                template: "{category}[/{parentKey}]/{key}/{postKind?}",
                defaults: new { controller = "Category", action = "Details" },
                constraints: new { category = categoryControllerConstraint, postKind = postKindConstraint }
                );

            //TODO: Determine if [postKind] should be present
            //category [postKind]
            routes.MapRoute(
                name: "Newsroom-Category-Index-Type",
                template: "{category}/{postKind?}",
                defaults: new { controller = "Category", action = "Index" },
                constraints: new { category = categoryControllerConstraint, postKind = postKindConstraint }
                );

            routes.MapRoute(
                name: "News-Subscribe-Index-Type",
                template: "news-subscribe/{category}/{postKind?}",
                defaults: new { controller = "Category", action = "Index" },
                constraints: new { category = categoryControllerConstraint, postKind = postKindConstraint }
                );


            #endregion

            //#region Tags

            ///* The Tags controller supports the following URL patterns:
            // *
            // *   Tag key [postKind] (feed | embed) [format]
            // *
            // */

            ////Tag key [postKind] (feed | embed) [format]
            //MapRouteOptional(
            //    context: context,
            //    name: "Newsroom-Tags[-Type]-Action",
            //    template: "Tags/{key}[/{postKind}]/{action}/{format}",
            //    defaults: new { controller = "Tags", format = UrlParameter.Optional },
            //    constraints: new { postKind = postKindConstraint, action = "Feed|Embed", format = formatConstraint }
            //);

            //#endregion

            #region Stories, Releases, Factsheets, Updates

            foreach (string postKind in postKinds.Split(","))
            {
                /* The Posts controller supports the following URL patterns:
                 *
                 *   postKind
                 *   postKind more-news
                 *   postKind (feed | embed [format])
                 *   postKind archive [year [month]]
                 *   postKind key
                 *
                 */

                //postKind
                routes.MapRoute(
                    name: "Newsroom-Type-Index" + "-" + postKind,
                    template: "{postKind}",
                    defaults: new { controller = "Posts", postKind = postKind.ToLower(), action = "Index" },
                    constraints: new { postKind = postKind }
                    );

                //postKind more-news
                routes.MapRoute(
                    name: "Newsroom-Type-More" + "-" + postKind,
                    template: "{postKind}/more-news",
                    defaults: new { controller = "Posts", postKind = postKind.ToLower(), action = "MoreNews" },
                    constraints: new { postKind = postKind }
                    );

                routes.MapRoute(
                    name: "Newsroom-Type-MoreArticles" + "-" + postKind,
                    template: "{postKind}/MoreArticles",
                    defaults: new { controller = "Posts", postKind = postKind.ToLower(), action = "MoreArticles" },
                    constraints: new { postKind = postKind }
                    );


                //postKind (feed | embed [format])
                routes.MapRoute(
                    name: "Newsroom-Type-Stories-Action" + "-" + postKind,
                    template: "{postKind}/{action}/{format?}",
                    defaults: new { controller = "Posts", postKind = postKind.ToLower() },
                    constraints: new { postKind = postKind, action = "Feed|Embed" }
                    );

                //postKind archive [year [month]]
                {
                    //i.e. postKind archive
                    routes.MapRoute(
                        name: "Newsroom-Type-Archive" + "-" + postKind,
                        template: "{postKind}/archive",
                        defaults: new { controller = "Posts", postKind = postKind.ToLower(), action = "Archive" },
                        constraints: new { postKind = postKind }
                        );

                    //i.e. postKind archive year [month]
                    routes.MapRoute(
                        name: "Newsroom-Type-Archive-Year" + "-" + postKind,
                        template: "{postKind}/archive/{year}/{month?}",
                        defaults: new { controller = "Posts", postKind = postKind.ToLower(), action = "Month" },
                        constraints: new { postKind = postKind, year = yearConstraint, month = monthConstraint }
                        );
                }

                //postKind key
                routes.MapRoute(
                    name: "Newsroom-Type-Details" + "-" + postKind,
                    template: "{postKind}/{key}",
                    defaults: new { controller = "Posts", postKind = postKind.ToLower(), action = "Details" },
                    constraints: new { postKind = postKind }
                    );

                //return the image via our server.
                routes.MapRoute(
                    name: "Newsroom-Type-Details-Image" + "-" + postKind,
                    template: "{postKind}/{key}/image",
                    defaults: new { controller = "Posts", postKind = postKind.ToLower(), action = "Image" },
                    constraints: new { postKind = postKind }
                    );
            }
            #endregion

            ////controller minstryKey key
            //context.MapRoute(
            //    name: "Newsroom-Biography",
            //    template: "{controller}/{ministryKey}/{key}",
            //    defaults: new { action = "Details" },
            //    constraints: new { controller = categoryControllerConstraint }
            //);

            #region Office of the Premier - Speeches

            /* The Categories controller supports the following URL patterns:
             *
             *   category [parentKey] [postKind]
             *   category [parentKey] key [postKind]
             *   category [parentKey] key [postKind] more-news
             *   category [parentKey] key [postKind] (feed | embed [format])
             *   category [parentKey] key [postKind] archive [year [month]]
             *
             */

            //category key [postKind] more-news
            routes.MapRoute(
                name: "Newsroom-Premier-Speeches-More",
                template: "office-of-the-premier/speeches/more-news",
                defaults: new { controller = "Category", category = "tags", action = "MoreNews", key = "speeches" },
                constraints: new { category = categoryControllerConstraint }
                );

            //category key [postKind] archive [year [month]]
            {
                //i.e. category key [postKind] archive
                routes.MapRoute(
                    name: "Newsroom-Premier-Speeches-Archive",
                    template: "office-of-the-premier/speeches/archive",
                    defaults: new { controller = "Category", category = "tags", action = "Archive", key = "speeches" },
                    constraints: new { category = categoryControllerConstraint }
                    );

                //i.e. category key [postKind] archive year [month]
                routes.MapRoute(
                    name: "Newsroom-Premier-Speeches-Archive-Year",
                    template: "office-of-the-premier/speeches/archive/{year}/{month?}",
                    defaults: new { controller = "Category", category = "tags", key = "speeches", action = "Month" },
                    constraints: new { year = yearConstraint, month = monthConstraint }
                    );
            }

            //category key [postKind] (feed | embed [format])
            routes.MapRoute(
                name: "Newsroom-Premier-Speeches-Action",
                template: "office-of-the-premier/speeches/{action}/{format?}",
                defaults: new { controller = "Category", category = "tags", key = "speeches" },
                constraints: new { action = "Feed|Embed", format = formatConstraint, category = categoryControllerConstraint }
                );

            routes.MapRoute(
                name: "Newsroom-Premier-Speeches-Action-MoreArticles",
                template: "office-of-the-premier/speeches/morearticles",
                defaults: new { controller = "Category", category = "tags", key = "speeches", action = "MoreArticles" },
                constraints: new { category = categoryControllerConstraint }
                );

            routes.MapRoute(
                name: "Newsroom-Premier-Speeches",
                template: "office-of-the-premier/speeches",
                defaults: new { controller = "Category", category = "tags", key = "speeches", action = "Details" },
                constraints: new { category = categoryControllerConstraint }
                );

            #endregion

            #region Office of the Premier

            /* The Categories controller supports the following URL patterns:
             *
             *   office-of-the-premier biography
             *   office-of-the-premier [postKind]
             *   office-of-the-premier [postKind] more-news
             *   office-of-the-premier [postKind] (feed | embed [format])
             *   office-of-the-premier [postKind] archive [year [month]]
             *
             */

            MapRouteOptional(
                routes: routes,
                name: "Newsroom-Premier-Biography",
                template: "office-of-the-premier/biography",
                defaults: new { controller = "Ministries", action = "Biography", key = "office-of-the-premier" },
                constraints: null
                );

            //category key [postKind] more-news
            MapRouteOptional(
                routes: routes,
                name: "Newsroom-Premier[-Type]-More",
                template: "office-of-the-premier[/{postKind?}]/more-news",
                defaults: new { controller = "Category", category = "ministries", key = "office-of-the-premier", action = "MoreNews" },
                constraints: new { postKind = postKindConstraint }
                );

            MapRouteOptional(
                routes: routes,
                name: "Newsroom-Premier[-Type]-MoreArticles",
                template: "office-of-the-premier[/{postKind?}]/morearticles",
                defaults: new { controller = "Category", category = "ministries", key = "office-of-the-premier", action = "MoreArticles" },
                constraints: new { postKind = postKindConstraint }
                );

            //category key [postKind] archive [year [month]]
            {
                //i.e. category key [postKind] archive
                MapRouteOptional(
                    routes: routes,
                    name: "Newsroom-Premier[-Type]-Archive",
                    template: "office-of-the-premier[/{postKind?}]/archive",
                    defaults: new { controller = "Category", category = "ministries", key = "office-of-the-premier", action = "Archive" },
                    constraints: new { postKind = postKindConstraint }
                    );

                //i.e. category key [postKind] archive year [month]
                MapRouteOptional(
                    routes: routes,
                    name: "Newsroom-Premier[-Type]-Archive-Year",
                    template: "office-of-the-premier[/{postKind?}]/archive/{year}/{month?}",
                    defaults: new { controller = "Category", category = "ministries", key = "office-of-the-premier", action = "Month" },
                    constraints: new { year = yearConstraint, month = monthConstraint, postKind = postKindConstraint }
                    );
            }

            //category key [postKind] (feed | embed [format])
            MapRouteOptional(
                routes: routes,
                name: "Newsroom-Premier[-Type]-Action",
                template: "office-of-the-premier[/{postKind?}]/{action}/{format?}",
                defaults: new { controller = "Category", category = "ministries", key = "office-of-the-premier" },
                constraints: new { postKind = postKindConstraint, action = "Feed|Embed", format = formatConstraint }
                );

            MapRouteOptional(
                routes: routes,
                name: "Newsroom-Premier-Type",
                template: "office-of-the-premier/{postKind?}",
                defaults: new { controller = "Category", category = "ministries", key = "office-of-the-premier", action = "Details" },
                constraints: new { postKind = postKindConstraint }
                );

            #endregion

            routes.MapRoute(
                name: "Newsroom-Page",
                template: "{action}",
                defaults: new { controller = "Default" },
                constraints: new { action = "Connect|Search|Privacy|Live|Contact|Contacts|Error" }
                );

            routes.MapRoute(
                name: "Subscribe",
                template: "subscribe/{action}",
                defaults: new { controller = "Subscribe", action = "Index" },
                constraints: new { action = "Index|Manage|Save|Renew" }
                );

            //context.MapRoute(
            //    name: "Newsroom-Page",
            //    template: "{key}",
            //    defaults: new { controller = "Page", action = "Single" }
            //);

            //routes.MapRoute(
            //    name: "Newsroom-NotFound",
            //    template: "{*path}",
            //    defaults: new { controller = "Default", action = "NotFound" }
            //);

            //TODO: Apply only to Index controllers

            routes.MapRoute(
                name: "Newsletters",
                template: "newsletters",
                defaults: new { controller = "Newsletters", action = "Index" }
                );

            routes.MapRoute(
                name: "Editions",
                template: "newsletters/{newsletterKey}",
                defaults: new { controller = "Newsletters", action = "Editions" }
                );

            routes.MapRoute(
                name: "GetBinaryByGuid",
                template: "newsletters/{type}/{guid}",
                defaults: new { controller = "Newsletters", action = "GetBinaryByGuid" },
                constraints: new { type = "file|image" }
                );

            routes.MapRoute(
                name: "Edition",
                template: "newsletters/{newsletterKey}/{editionKey}",
                defaults: new { controller = "Newsletters", action = "Edition" }
                );

            routes.MapRoute(
                name: "GetArticle",
                template: "newsletters/{newsletterKey}/{editionKey}/{articleKey}",
                defaults: new { controller = "Newsletters", action = "GetArticle" }
                );

            routes.MapRoute(
                name: "Default",
                template: "{controller}/{action}",
                defaults: new { },
                constraints: new { action = "MoreArticles" }
                );

            routes.MapRoute(
                name: "NotFound",
                template: "{*path}",
                defaults: new { controller = "Default", action = "NotFound" }
                //TEST: Why was the namespaces parameter set?
                //namespaces: new[] { "Gov.News.Website.Controllers" }
                );
        }
        private static IRouteConstraint GetInlineConstraint(Group constraintGroup, bool isOptional, IInlineConstraintResolver constraintResolver)
#endif
        {
#if ASPNETWEBAPI
            List<IHttpRouteConstraint> parameterConstraints = new List<IHttpRouteConstraint>();
#else
            List<IRouteConstraint> parameterConstraints = new List<IRouteConstraint>();
#endif
            foreach (Capture constraintCapture in constraintGroup.Captures)
            {
                string inlineConstraint = constraintCapture.Value;
                var constraint = constraintResolver.ResolveConstraint(inlineConstraint);
                if (constraint == null)
                {
                    throw Error.InvalidOperation(ErrorResources.HttpRouteBuilder_CouldNotResolveConstraint, constraintResolver.GetType().Name, inlineConstraint);
                }
                parameterConstraints.Add(constraint);
            }

            if (parameterConstraints.Count > 0)
            {
                var constraint = parameterConstraints.Count == 1 ?
                    parameterConstraints[0] :
                    new CompoundRouteConstraint(parameterConstraints);

                if (isOptional)
                {
                    // Constraints should match RouteParameter.Optional if the parameter is optional
                    // This prevents contraining when there's no value specified
                    constraint = new OptionalRouteConstraint(constraint);
                }

                return constraint;
            }
            return null;
        }