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); }
/// <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); }
private IParameterPolicy InitializeRouteConstraint( bool optional, IRouteConstraint routeConstraint) { if (optional) { routeConstraint = new OptionalRouteConstraint(routeConstraint); } return(routeConstraint); }
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); }
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); }
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; }