【问题标题】:How to get controller name when Web API versioning with routing attributes使用路由属性进行 Web API 版本控制时如何获取控制器名称
【发布时间】:2014-02-07 01:44:38
【问题描述】:

我需要从我的路由中获取控制器名称,如果在 WebApiConfig 中使用标准路由代码,我可以做到这一点。

但是,如果我使用路由属性,它开始变得有点困难,尤其是在尝试版本时。

示例:如果我调用 api/terms/bonuses 并且我有 BonusController 和 BonusV2Controller 以及 BonusV3Controller,此代码将返回最新的控制器版本 3。没关系,我可以接受返回最新和最好的版本作为默认。

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;

现在,如果我请求版本 1,为简单起见,我将使用查询字符串并调用 api/terms/bonuses?v=2

所以这段代码不再有效(显然)。

如何获取 V2 控制器名称?

如果我放弃路由属性而只使用 WebApiConfig 路由,这段代码可以正常工作。

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

更新:

这是我的完整选择器代码。

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;

【问题讨论】:

  • 您能否分享您的控制器选择器的 SelectController 的完整实现,以获得一个好主意?
  • 你也可以看看下面的帖子:stackoverflow.com/questions/19835015/…
  • 有了那个更新,我现在得到一个错误。 {"$id":"1","message":"发生错误。","exceptionMessage":"给定的键不在字典中。","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 CandidateFound)\r\n at ......

标签: c# asp.net-web-api asp.net-web-api-routing


【解决方案1】:
 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;
  }
}

【讨论】:

  • 所以,直截了当。如果我想要控制器名称,在控制器内部,我必须使用:((HttpActionDescriptor[]) Request.GetRouteData().GetSubRoutes().Last().Route.DataTokens["actions"])[0].ControllerDescriptor.ControllerName 在什么时候这会被适当地归类为 rube goldberg 系统?
【解决方案2】:

终于找到了:

filterContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerName

【讨论】:

  • 我希望您的答案更清晰,但这看起来确实可以帮助某人。它类似于另一个答案,但更简洁。
猜你喜欢
  • 2014-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-19
  • 2017-06-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多