11

In WebApiConfig.cs i have the following

public static void Register(HttpConfiguration config)
{

   config.MapHttpAttributeRoutes(); 

   config.Services.Replace(typeof(IHttpControllerSelector),
               new MyApiControllerSelector(config));

   //code omitted for brevity
}

then in the MyApiControllerSelector.cs i want to get the controller

public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
        {           
            var routeData = request.GetRouteData();           

            var controllerName = (string)routeData.Values["controller"];

            //code omitted for brevity
        }

Pretty simple and it worked great but now using attribute routing i think it needs a different approach? - as i can't seem to find a simple way

I've tried

var controllerName = request.GetActionDescriptor().ControllerDescriptor.ControllerName;

which doesn't work.

Then reading the source with debugging lead me to request.GetRouteData().Values["MS_SubRoutes"]

So now I have

string subRoutesKey = "MS_SubRoutes";

var attributedRoutesData = routeData.Values[subRoutesKey] as IEnumerable<IHttpRouteData>; 
var subRouteData = attributedRoutesData.FirstOrDefault();

var actions = (ReflectedHttpActionDescriptor[])subRouteData.Route.DataTokens["actions"];
var controllerName = actions[0].ControllerDescriptor.ControllerName;

which works but it has to be a simpler way?

UPDATE

@KiranChalla asked what's my use case so i'm posting the remaining code. Basically i'm parsing version media type Accept: application/vnd.app.{resource}.v{version}+json from request and returning a HttpControllerDescriptor depending on the version.

            HttpControllerDescriptor oldControllerDescriptor;
            if (controllers.TryGetValue(controllerName, out oldControllerDescriptor))
            {
                var apiVersion = GetVersionFromMediaType(request);

                var newControllerName = String.Concat(controllerName, "V", apiVersion);

                HttpControllerDescriptor newControllerDescriptor;
                if (controllers.TryGetValue(newControllerName, out newControllerDescriptor))
                {                    
                    return newControllerDescriptor;
                }               
                return oldControllerDescriptor;
            }
            return null;
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Matija Grcic
  • 12,963
  • 6
  • 62
  • 90
  • 2
    I believe there is no other simpler way that I am aware of. Just fyi...a small improvement, you can do `request.GetRouteData().GetSubRoutes()` to get list attribute routes... – Kiran Oct 23 '13 at 17:42
  • By the way, Can you describe what your scenario is? I am curious to know how you intend to use custom controller selector with attribute routing. – Kiran Oct 23 '13 at 17:48
  • @KiranChalla Thanks for the suggestion. I've explained my scenario and added the remaining code so please take a look and correct me if i'm doing anything wrong. – Matija Grcic Oct 24 '13 at 06:55
  • @KiranChalla can you take a look at http://stackoverflow.com/questions/19835015/versioning-asp-net-web-api-2-with-media-types – Matija Grcic Nov 08 '13 at 15:02
  • Curiously, DefaultHttpControllerSelector has a GetControllerName method that also fails on sub routes. – Jamie Ide Mar 30 '14 at 18:34

2 Answers2

14

As confirmed by @KiranChalla there is no simpler way then the one I've already implemented, except the minor suggestion to use GetSubRoutes()

var attributedRoutesData = request.GetRouteData().GetSubRoutes();
var subRouteData = attributedRoutesData.FirstOrDefault();

var actions = (ReflectedHttpActionDescriptor[])subRouteData.Route.DataTokens["actions"];
var controllerName = actions[0].ControllerDescriptor.ControllerName;
Matija Grcic
  • 12,963
  • 6
  • 62
  • 90
  • 1
    @ainteger No, it's just a different approach to get the necessary data (controller name) from the pipeline. – Matija Grcic Nov 15 '13 at 08:44
  • The suggestion of using `GetSubRoutes()` is an excellent one. It's the approach I've taken because using `MS_SubRoutes` is reliance on an undocumented string literal that could easily change without warning in the future. – BitMask777 Jun 24 '15 at 18:06
0

its old ticket but i get controller name this way,

 var ControllerName = context.Request.RouteValues.Keys.FirstOrDefault();
Ali CAKIL
  • 383
  • 5
  • 21