4

I need to get the controller name from my route and this I can do if using standard routing code in WebApiConfig.

However, if I am using routing attributes it starts to get a little difficult, especially when trying to version.

Example: If I call an api/terms/bonuses and I have a BonusController and BonusV2Controller and a BonusV3Controller, this code returns the latest controller version 3. That's ok, I can live with that returning the latest and greatest version as a default.

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

var actions = (ReflectedHttpActionDescriptor[])subRouteData.Route.DataTokens["actions"];
//This seems to get latest controller name. ie. V2
controllerName = actions[0].ControllerDescriptor.ControllerName;

Now if I request a version 1, for simplicity I'll use a querystring and call api/terms/bonuses?v=2

So this code no longer works (obviously).

How do I get the V2 controller name?

If I abandon routing attributes and just use WebApiConfig routing, this code works happily.

HttpControllerDescriptor controllerDescriptor = null; 
var controllers = GetControllerMapping();
var routeData = request.GetRouteData();
var controllerName = (string)routeData.Values["controller"];

UPDATE:

Here is my full selector code.

IDictionary<string, HttpControllerDescriptor> controllers = GetControllerMapping();                                             

var attributedRoutesData = request.GetRouteData().GetSubRoutes();
var subRouteData = attributedRoutesData.LastOrDefault(); //LastOrDefault() will get PeopleController, FirstOrDefault will get People{version}Controller which we don't want

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


//For controller name without attribute routing
//var controllerName = (string)routeData.Values["controller"];

HttpControllerDescriptor oldControllerDescriptor;
if (controllers.TryGetValue(controllerName, out oldControllerDescriptor))
{
    //TODO: Different techniques for handling version api requests.
    var apiVersion = GetVersionFromQueryString(request);
    //var version = GetVersionFromHeader(request);
    //var version = GetVersionFromAcceptHeaderVersion(request);
    //var version = GetVersionFromMediaType(request);

    if (!String.IsNullOrEmpty(apiVersion))
    {
        var newControllerName = String.Concat(controllerName, "V", apiVersion);

        HttpControllerDescriptor newControllerDescriptor;
        if (controllers.TryGetValue(newControllerName, out newControllerDescriptor))
        {
            return newControllerDescriptor;
            }
        }
        return oldControllerDescriptor;
    }
    return null;
3
  • Could you share your complete implementation of SelectController of your controller selector to get a good idea? Commented Jan 17, 2014 at 16:29
  • you can also take a look at the following post: stackoverflow.com/questions/19835015/… Commented Jan 17, 2014 at 16:35
  • 2
    With that UPDATE, I now get an error. {"$id":"1","message":"An error has occurred.","exceptionMessage":"The given key was not present in the dictionary.","exceptionType":"System.Collections.Generic.KeyNotFoundException","stackTrace":" at System.Collections.Generic.Dictionary2.get_Item(TKey key)\r\n at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.FindActionMatchRequiredRouteAndQueryParameters(IEnumerable1 candidatesFound)\r\n at ...... Commented Jan 17, 2014 at 16:55

2 Answers 2

2
 var subRouteData = request.GetRouteData().GetSubRoutes().LastOrDefault();

 if (subRouteData != null && subRouteData.Route != null)
 {
  var actions = subRouteData.Route.DataTokens["actions"] as HttpActionDescriptor[];

  if (actions != null && actions.Length > 0)
  {
     controllerName = actions[0].ControllerDescriptor.ControllerName;
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

So, to get this straight. If I want the controller name, while inside the controller, I have to use: ((HttpActionDescriptor[]) Request.GetRouteData().GetSubRoutes().Last().Route.DataTokens["actions"])[0].ControllerDescriptor.ControllerName At what point would this be appropriately classified as a rube goldberg system?
0

At last I found it:

filterContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerName

1 Comment

I would have liked to have seen more clarity on your answer but this does look like it could help someone. It's similar to another answer, but is more concise.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.