{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/176","repository_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server","labels_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/176/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/176/comments","events_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/176/events","html_url":"https://github.com/Microsoft/ApplicationInsights-dotnet-server/issues/176","id":183751678,"number":176,"title":"Make better names for Web API attributes based routing","user":{"login":"SergeyKanzhelev","id":9950081,"avatar_url":"https://avatars.githubusercontent.com/u/9950081?v=3","gravatar_id":"","url":"https://api.github.com/users/SergeyKanzhelev","html_url":"https://github.com/SergeyKanzhelev","followers_url":"https://api.github.com/users/SergeyKanzhelev/followers","following_url":"https://api.github.com/users/SergeyKanzhelev/following{/other_user}","gists_url":"https://api.github.com/users/SergeyKanzhelev/gists{/gist_id}","starred_url":"https://api.github.com/users/SergeyKanzhelev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SergeyKanzhelev/subscriptions","organizations_url":"https://api.github.com/users/SergeyKanzhelev/orgs","repos_url":"https://api.github.com/users/SergeyKanzhelev/repos","events_url":"https://api.github.com/users/SergeyKanzhelev/events{/privacy}","received_events_url":"https://api.github.com/users/SergeyKanzhelev/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/labels/enhancement","name":"enhancement","color":"84b6eb"}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2016-10-18T17:26:15Z","updated_at":"2016-10-18T17:29:14Z","closed_at":null,"body":"When attribute-based routing is used by Web API application - Web SDK collects request names as Path. It doesn't recognize the templates.\r\n\r\n@gardnerjr suggested the following code to fix it: \r\n\r\n``` csharp\r\nif (routeValues != null && routeValues.Count > 0)\r\n{\r\n    object controller;                    \r\n    routeValues.TryGetValue(\"controller\", out controller);\r\n    string controllerString = (controller == null) ? string.Empty : controller.ToString();\r\n\r\n    if (!string.IsNullOrEmpty(controllerString))\r\n    {\r\n        object action;\r\n        routeValues.TryGetValue(\"action\", out action);\r\n        string actionString = (action == null) ? string.Empty : action.ToString();\r\n\r\n       name = controllerString;\r\n        if (!string.IsNullOrEmpty(actionString))\r\n        {\r\n            name += \"/\" + actionString;\r\n        }\r\n        else\r\n        {\r\n            if (routeValues.Keys.Count > 0)\r\n            {\r\n                // We want to include arguments because in WebApi action is usually null \r\n                // and action is resolved by controller, http method and number of arguments\r\n                var sortedKeys = routeValues.Keys\r\n                    .Where(key => !string.Equals(key, \"controller\", StringComparison.OrdinalIgnoreCase))\r\n                    .OrderBy(key => key, StringComparer.OrdinalIgnoreCase)\r\n                    .ToArray();\r\n\r\n                string arguments = string.Join(@\"/\", sortedKeys);\r\n                name += \" [\" + arguments + \"]\";\r\n            }\r\n        }\r\n    }\r\n    else // try to find the applicable asp.net webapi route if possible\r\n    {\r\n        object val;\r\n        object[] routes = null;\r\n\r\n        // at runtime this can't cast directly to IHttpRouteData because there are multiple versions of webapi\r\n        if (routeValues.TryGetValue(\"MS_SubRoutes\", out val) && (routes = val as object[]) != null && routes.Length > 0)\r\n        {\r\n            object first = routes.OrderBy(GetPrecedenceForRoute).FirstOrDefault();\r\n\r\n            // take the first route's template. if we could link with system.web.http, it would be this:\r\n            /*\r\n            if (!string.IsNullOrEmpty(first.Route.RouteTemplate))\r\n            {\r\n                string routeTemplate= first.Route.RouteTemplate;\r\n                if (!string.IsNullOrEmpty(routeTemplate))\r\n                {\r\n                    name = routeTemplate;\r\n                }\r\n            }\r\n            */\r\n\r\n            // through reflection:\r\n            var getter = first?.GetType().GetProperty(\"Route\")?.GetGetMethod();\r\n            if (getter != null)\r\n            {\r\n                var route = getter.Invoke(first, null);\r\n                var templateGetter = route?.GetType().GetProperty(\"RouteTemplate\")?.GetGetMethod();\r\n                if (templateGetter != null)\r\n                {\r\n                    var routeTemplate = templateGetter.Invoke(route, null) as string;\r\n                    if (!string.IsNullOrEmpty(routeTemplate))\r\n                    {\r\n                        name = routeTemplate;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\nThis code can be improved by:\r\n1. Caching methods you took via reflection as delegates. \r\n2. Do not try to get ms_route if delegates are undefined\r\n3. For consistency the logic for older apps can/should be changed to use `var url = ((System.Web.Routing.Route)ctx.RouteData.Route).Url;`\r\n\r\nNeed to clean up code and implement functional tests."},"comment":{"url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/comments/254579998","html_url":"https://github.com/Microsoft/ApplicationInsights-dotnet-server/issues/176#issuecomment-254579998","issue_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/176","id":254579998,"user":{"login":"gardnerjr","id":10158007,"avatar_url":"https://avatars.githubusercontent.com/u/10158007?v=3","gravatar_id":"","url":"https://api.github.com/users/gardnerjr","html_url":"https://github.com/gardnerjr","followers_url":"https://api.github.com/users/gardnerjr/followers","following_url":"https://api.github.com/users/gardnerjr/following{/other_user}","gists_url":"https://api.github.com/users/gardnerjr/gists{/gist_id}","starred_url":"https://api.github.com/users/gardnerjr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gardnerjr/subscriptions","organizations_url":"https://api.github.com/users/gardnerjr/orgs","repos_url":"https://api.github.com/users/gardnerjr/repos","events_url":"https://api.github.com/users/gardnerjr/events{/privacy}","received_events_url":"https://api.github.com/users/gardnerjr/received_events","type":"User","site_admin":false},"created_at":"2016-10-18T17:29:14Z","updated_at":"2016-10-18T17:29:14Z","body":"Yes, and the snag i ran into (hence all the reflection above) is that there are multiple distinct major versions of WebAPI, so if i used any of the actual interfaces, the code here would only work for one or another version of WebAPI.  \r\n\r\nSomething similar probably also needs to be done in the .net Core version of ASP.Net WebAPI as well?"}}
{"actor":{"display_login":"gardnerjr"}}