{"action":"closed","number":683,"pull_request":{"url":"https://api.github.com/repos/NSwag/NSwag/pulls/683","id":111341758,"html_url":"https://github.com/NSwag/NSwag/pull/683","diff_url":"https://github.com/NSwag/NSwag/pull/683.diff","patch_url":"https://github.com/NSwag/NSwag/pull/683.patch","issue_url":"https://api.github.com/repos/NSwag/NSwag/issues/683","number":683,"state":"closed","locked":false,"title":"Addressing several routing issues.","user":{"login":"Cephei","id":1054639,"avatar_url":"https://avatars0.githubusercontent.com/u/1054639?v=3","gravatar_id":"","url":"https://api.github.com/users/Cephei","html_url":"https://github.com/Cephei","followers_url":"https://api.github.com/users/Cephei/followers","following_url":"https://api.github.com/users/Cephei/following{/other_user}","gists_url":"https://api.github.com/users/Cephei/gists{/gist_id}","starred_url":"https://api.github.com/users/Cephei/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Cephei/subscriptions","organizations_url":"https://api.github.com/users/Cephei/orgs","repos_url":"https://api.github.com/users/Cephei/repos","events_url":"https://api.github.com/users/Cephei/events{/privacy}","received_events_url":"https://api.github.com/users/Cephei/received_events","type":"User","site_admin":false},"body":"#639 \r\n\r\nSeveral issues with routing.\r\nAsp.Net Core vs Owin/WebAPI\r\n\r\nResources:\r\nhttps://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing\r\nhttps://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing\r\nhttps://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2\r\nhttps://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api\r\n\r\nThe majority of changes are within `GetHttpPaths` & `ExpandOptionalHttpPathParameters`.\r\nThe logic used to be:\r\n```\r\n             .....\r\n            else if (routePrefixAttribute != null && routeAttributeOnClass != null)\r\n                httpPaths.Add(routePrefixAttribute.Prefix + \"/\" + routeAttributeOnClass.Template);\r\n            // TODO: Check if this is correct\r\n            else if (routePrefixAttribute != null && (\r\n                (method.GetParameters().Length == 0 && method.Name == \"Get\") ||\r\n                method.Name == \"Post\" ||\r\n                method.Name == \"Put\" ||\r\n                method.Name == \"Delete\"))\r\n            {\r\n                httpPaths.Add(routePrefixAttribute.Prefix);\r\n            }\r\n            else if (routeAttributeOnClass != null)\r\n                httpPaths.Add(routeAttributeOnClass.Template);\r\n            else\r\n                httpPaths.Add(Settings.DefaultUrlTemplate ?? string.Empty);\r\n```\r\n\r\nThe `Settings.DefaultUrlTemplate` should not be considered when a `RoutePrefix` is present as was in `PersonsController`. I was unable to find any routing rules that governed the following:\r\n```\r\nelse if (routePrefixAttribute != null && (\r\n                (method.GetParameters().Length == 0 && method.Name == \"Get\") ||\r\n                method.Name == \"Post\" ||\r\n                method.Name == \"Put\" ||\r\n                method.Name == \"Delete\"))\r\n```\r\n\r\nI am allowed to have a `RoutePrefix` with a `GET` method which has parameters. That's completely valid. The last else condition should allow for the MVC style of routing with `{controller}/{action}/{id?}`.\r\n\r\nAlso the default route convention in both Core and Web API has the `{id}` as optional so I changed the `DefaultUrlTemplate` to reflect that.\r\n\r\nLastly, the fix for handling `RoutePrefix`:\r\nI inverted the logic:\r\n```\r\n.Select(p =>\r\n    \"/\" + p\r\n    .Replace(\"[\", \"{\")\r\n    .Replace(\"]\", \"}\")\r\n    .Replace(\"{controller}\", controllerName)\r\n    .Replace(\"{action}\", actionName)\r\n    .Trim('/'))\r\n.SelectMany(p => ExpandOptionalHttpPathParameters(p, method))\r\n```\r\nto first expand the optional paths. \r\n```\r\n.SelectMany(p => ExpandOptionalHttpPathParameters(p, method))\r\n.Select(p =>\r\n    \"/\" + p\r\n    .Replace(\"[\", \"{\")\r\n    .Replace(\"]\", \"}\")\r\n    .Replace(\"{controller}\", controllerName)\r\n    .Replace(\"{action}\", actionName)\r\n    .Trim('/'))\r\n```\r\nBefore, if `ExpandOptionalHttpPathParameters` returned values, it would overwrite the the prior `Select` `\"/\" + p.Replace(...)` value.\r\n\r\nThen within `ExpandOptionalHttpPathParameters` it no longer does two sequential recursive operations per-optional-route-segment (ie. `?}`):\r\n```\r\nif (segment.EndsWith(\"?}\"))\r\n                {\r\n                    // Only expand if optional parameter is available in action method\r\n                    if (method.GetParameters().Any(p => segment.StartsWith(\"{\" + p.Name + \":\") || segment.StartsWith(\"{\" + p.Name + \"?\")))\r\n                    {\r\n                        foreach (var p in ExpandOptionalHttpPathParameters(string.Join(\"/\", segments.Take(i).Concat(new[] { segment.Replace(\"?\", \"\") }).Concat(segments.Skip(i + 1))), method))\r\n                            yield return p;\r\n                    }\r\n                    else\r\n                    {\r\n                        foreach (var p in ExpandOptionalHttpPathParameters(string.Join(\"/\", segments.Take(i).Concat(segments.Skip(i + 1))), method))\r\n                            yield return p;\r\n                    }\r\n\r\n                    yield break;\r\n                }\r\n```\r\n\r\nBefore, you would get back multiple paths for a single endpoint with a `RoutePrefix`. Now you get the correct amount.","created_at":"2017-03-17T18:39:25Z","updated_at":"2017-03-20T14:57:06Z","closed_at":"2017-03-20T14:57:06Z","merged_at":"2017-03-20T14:57:06Z","merge_commit_sha":"2048f13b5487435be0bc4c8f1e164a2baa5c68da","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/NSwag/NSwag/pulls/683/commits","review_comments_url":"https://api.github.com/repos/NSwag/NSwag/pulls/683/comments","review_comment_url":"https://api.github.com/repos/NSwag/NSwag/pulls/comments{/number}","comments_url":"https://api.github.com/repos/NSwag/NSwag/issues/683/comments","statuses_url":"https://api.github.com/repos/NSwag/NSwag/statuses/62092fa6b4c3ab4f1a123fc263d4c4102917a547","head":{"label":"Cephei:master","ref":"master","sha":"62092fa6b4c3ab4f1a123fc263d4c4102917a547","user":{"login":"Cephei","id":1054639,"avatar_url":"https://avatars0.githubusercontent.com/u/1054639?v=3","gravatar_id":"","url":"https://api.github.com/users/Cephei","html_url":"https://github.com/Cephei","followers_url":"https://api.github.com/users/Cephei/followers","following_url":"https://api.github.com/users/Cephei/following{/other_user}","gists_url":"https://api.github.com/users/Cephei/gists{/gist_id}","starred_url":"https://api.github.com/users/Cephei/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Cephei/subscriptions","organizations_url":"https://api.github.com/users/Cephei/orgs","repos_url":"https://api.github.com/users/Cephei/repos","events_url":"https://api.github.com/users/Cephei/events{/privacy}","received_events_url":"https://api.github.com/users/Cephei/received_events","type":"User","site_admin":false},"repo":{"id":83240701,"name":"NSwag","full_name":"Cephei/NSwag","owner":{"login":"Cephei","id":1054639,"avatar_url":"https://avatars0.githubusercontent.com/u/1054639?v=3","gravatar_id":"","url":"https://api.github.com/users/Cephei","html_url":"https://github.com/Cephei","followers_url":"https://api.github.com/users/Cephei/followers","following_url":"https://api.github.com/users/Cephei/following{/other_user}","gists_url":"https://api.github.com/users/Cephei/gists{/gist_id}","starred_url":"https://api.github.com/users/Cephei/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Cephei/subscriptions","organizations_url":"https://api.github.com/users/Cephei/orgs","repos_url":"https://api.github.com/users/Cephei/repos","events_url":"https://api.github.com/users/Cephei/events{/privacy}","received_events_url":"https://api.github.com/users/Cephei/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Cephei/NSwag","description":"The Swagger (Open API) toolchain for .NET, Web API and TypeScript. ","fork":true,"url":"https://api.github.com/repos/Cephei/NSwag","forks_url":"https://api.github.com/repos/Cephei/NSwag/forks","keys_url":"https://api.github.com/repos/Cephei/NSwag/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Cephei/NSwag/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Cephei/NSwag/teams","hooks_url":"https://api.github.com/repos/Cephei/NSwag/hooks","issue_events_url":"https://api.github.com/repos/Cephei/NSwag/issues/events{/number}","events_url":"https://api.github.com/repos/Cephei/NSwag/events","assignees_url":"https://api.github.com/repos/Cephei/NSwag/assignees{/user}","branches_url":"https://api.github.com/repos/Cephei/NSwag/branches{/branch}","tags_url":"https://api.github.com/repos/Cephei/NSwag/tags","blobs_url":"https://api.github.com/repos/Cephei/NSwag/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Cephei/NSwag/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Cephei/NSwag/git/refs{/sha}","trees_url":"https://api.github.com/repos/Cephei/NSwag/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Cephei/NSwag/statuses/{sha}","languages_url":"https://api.github.com/repos/Cephei/NSwag/languages","stargazers_url":"https://api.github.com/repos/Cephei/NSwag/stargazers","contributors_url":"https://api.github.com/repos/Cephei/NSwag/contributors","subscribers_url":"https://api.github.com/repos/Cephei/NSwag/subscribers","subscription_url":"https://api.github.com/repos/Cephei/NSwag/subscription","commits_url":"https://api.github.com/repos/Cephei/NSwag/commits{/sha}","git_commits_url":"https://api.github.com/repos/Cephei/NSwag/git/commits{/sha}","comments_url":"https://api.github.com/repos/Cephei/NSwag/comments{/number}","issue_comment_url":"https://api.github.com/repos/Cephei/NSwag/issues/comments{/number}","contents_url":"https://api.github.com/repos/Cephei/NSwag/contents/{+path}","compare_url":"https://api.github.com/repos/Cephei/NSwag/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Cephei/NSwag/merges","archive_url":"https://api.github.com/repos/Cephei/NSwag/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Cephei/NSwag/downloads","issues_url":"https://api.github.com/repos/Cephei/NSwag/issues{/number}","pulls_url":"https://api.github.com/repos/Cephei/NSwag/pulls{/number}","milestones_url":"https://api.github.com/repos/Cephei/NSwag/milestones{/number}","notifications_url":"https://api.github.com/repos/Cephei/NSwag/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Cephei/NSwag/labels{/name}","releases_url":"https://api.github.com/repos/Cephei/NSwag/releases{/id}","deployments_url":"https://api.github.com/repos/Cephei/NSwag/deployments","created_at":"2017-02-26T21:06:25Z","updated_at":"2017-02-26T21:06:28Z","pushed_at":"2017-03-17T18:37:10Z","git_url":"git://github.com/Cephei/NSwag.git","ssh_url":"git@github.com:Cephei/NSwag.git","clone_url":"https://github.com/Cephei/NSwag.git","svn_url":"https://github.com/Cephei/NSwag","homepage":"http://NSwag.org","size":16127,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"NSwag:master","ref":"master","sha":"d782b557e0c513e02f830677dbf495e3d3c199cf","user":{"login":"NSwag","id":13883346,"avatar_url":"https://avatars1.githubusercontent.com/u/13883346?v=3","gravatar_id":"","url":"https://api.github.com/users/NSwag","html_url":"https://github.com/NSwag","followers_url":"https://api.github.com/users/NSwag/followers","following_url":"https://api.github.com/users/NSwag/following{/other_user}","gists_url":"https://api.github.com/users/NSwag/gists{/gist_id}","starred_url":"https://api.github.com/users/NSwag/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/NSwag/subscriptions","organizations_url":"https://api.github.com/users/NSwag/orgs","repos_url":"https://api.github.com/users/NSwag/repos","events_url":"https://api.github.com/users/NSwag/events{/privacy}","received_events_url":"https://api.github.com/users/NSwag/received_events","type":"Organization","site_admin":false},"repo":{"id":41822320,"name":"NSwag","full_name":"NSwag/NSwag","owner":{"login":"NSwag","id":13883346,"avatar_url":"https://avatars1.githubusercontent.com/u/13883346?v=3","gravatar_id":"","url":"https://api.github.com/users/NSwag","html_url":"https://github.com/NSwag","followers_url":"https://api.github.com/users/NSwag/followers","following_url":"https://api.github.com/users/NSwag/following{/other_user}","gists_url":"https://api.github.com/users/NSwag/gists{/gist_id}","starred_url":"https://api.github.com/users/NSwag/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/NSwag/subscriptions","organizations_url":"https://api.github.com/users/NSwag/orgs","repos_url":"https://api.github.com/users/NSwag/repos","events_url":"https://api.github.com/users/NSwag/events{/privacy}","received_events_url":"https://api.github.com/users/NSwag/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/NSwag/NSwag","description":"The Swagger (Open API) toolchain for .NET, Web API and TypeScript. ","fork":false,"url":"https://api.github.com/repos/NSwag/NSwag","forks_url":"https://api.github.com/repos/NSwag/NSwag/forks","keys_url":"https://api.github.com/repos/NSwag/NSwag/keys{/key_id}","collaborators_url":"https://api.github.com/repos/NSwag/NSwag/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/NSwag/NSwag/teams","hooks_url":"https://api.github.com/repos/NSwag/NSwag/hooks","issue_events_url":"https://api.github.com/repos/NSwag/NSwag/issues/events{/number}","events_url":"https://api.github.com/repos/NSwag/NSwag/events","assignees_url":"https://api.github.com/repos/NSwag/NSwag/assignees{/user}","branches_url":"https://api.github.com/repos/NSwag/NSwag/branches{/branch}","tags_url":"https://api.github.com/repos/NSwag/NSwag/tags","blobs_url":"https://api.github.com/repos/NSwag/NSwag/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/NSwag/NSwag/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/NSwag/NSwag/git/refs{/sha}","trees_url":"https://api.github.com/repos/NSwag/NSwag/git/trees{/sha}","statuses_url":"https://api.github.com/repos/NSwag/NSwag/statuses/{sha}","languages_url":"https://api.github.com/repos/NSwag/NSwag/languages","stargazers_url":"https://api.github.com/repos/NSwag/NSwag/stargazers","contributors_url":"https://api.github.com/repos/NSwag/NSwag/contributors","subscribers_url":"https://api.github.com/repos/NSwag/NSwag/subscribers","subscription_url":"https://api.github.com/repos/NSwag/NSwag/subscription","commits_url":"https://api.github.com/repos/NSwag/NSwag/commits{/sha}","git_commits_url":"https://api.github.com/repos/NSwag/NSwag/git/commits{/sha}","comments_url":"https://api.github.com/repos/NSwag/NSwag/comments{/number}","issue_comment_url":"https://api.github.com/repos/NSwag/NSwag/issues/comments{/number}","contents_url":"https://api.github.com/repos/NSwag/NSwag/contents/{+path}","compare_url":"https://api.github.com/repos/NSwag/NSwag/compare/{base}...{head}","merges_url":"https://api.github.com/repos/NSwag/NSwag/merges","archive_url":"https://api.github.com/repos/NSwag/NSwag/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/NSwag/NSwag/downloads","issues_url":"https://api.github.com/repos/NSwag/NSwag/issues{/number}","pulls_url":"https://api.github.com/repos/NSwag/NSwag/pulls{/number}","milestones_url":"https://api.github.com/repos/NSwag/NSwag/milestones{/number}","notifications_url":"https://api.github.com/repos/NSwag/NSwag/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/NSwag/NSwag/labels{/name}","releases_url":"https://api.github.com/repos/NSwag/NSwag/releases{/id}","deployments_url":"https://api.github.com/repos/NSwag/NSwag/deployments","created_at":"2015-09-02T19:11:57Z","updated_at":"2017-03-20T10:24:20Z","pushed_at":"2017-03-20T14:57:06Z","git_url":"git://github.com/NSwag/NSwag.git","ssh_url":"git@github.com:NSwag/NSwag.git","clone_url":"https://github.com/NSwag/NSwag.git","svn_url":"https://github.com/NSwag/NSwag","homepage":"http://NSwag.org","size":16130,"stargazers_count":494,"watchers_count":494,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":121,"mirror_url":null,"open_issues_count":85,"forks":121,"open_issues":85,"watchers":494,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/NSwag/NSwag/pulls/683"},"html":{"href":"https://github.com/NSwag/NSwag/pull/683"},"issue":{"href":"https://api.github.com/repos/NSwag/NSwag/issues/683"},"comments":{"href":"https://api.github.com/repos/NSwag/NSwag/issues/683/comments"},"review_comments":{"href":"https://api.github.com/repos/NSwag/NSwag/pulls/683/comments"},"review_comment":{"href":"https://api.github.com/repos/NSwag/NSwag/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/NSwag/NSwag/pulls/683/commits"},"statuses":{"href":"https://api.github.com/repos/NSwag/NSwag/statuses/62092fa6b4c3ab4f1a123fc263d4c4102917a547"}},"merged":true,"mergeable":null,"mergeable_state":"unknown","merged_by":{"login":"rsuter","id":2603405,"avatar_url":"https://avatars2.githubusercontent.com/u/2603405?v=3","gravatar_id":"","url":"https://api.github.com/users/rsuter","html_url":"https://github.com/rsuter","followers_url":"https://api.github.com/users/rsuter/followers","following_url":"https://api.github.com/users/rsuter/following{/other_user}","gists_url":"https://api.github.com/users/rsuter/gists{/gist_id}","starred_url":"https://api.github.com/users/rsuter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rsuter/subscriptions","organizations_url":"https://api.github.com/users/rsuter/orgs","repos_url":"https://api.github.com/users/rsuter/repos","events_url":"https://api.github.com/users/rsuter/events{/privacy}","received_events_url":"https://api.github.com/users/rsuter/received_events","type":"User","site_admin":false},"comments":7,"review_comments":0,"maintainer_can_modify":false,"commits":4,"additions":205,"deletions":45,"changed_files":12}}
{"actor":{"display_login":"rsuter"}}