2013-01-23 169 views
12

我有WebApi控制器以它们名称中的“Api”后缀结尾(例如:StudentsApiController,InstructorsApiController)。我这样做是为了轻松区分我的MVC控制器和WebApi控制器。我希望我的WebApi路线看起来类似于ASP.NET Web Api路由定制

http://localhost:50009/api/students/5而不是http://localhost:50009/api/studentsapi/5

目前实现这一目标,我设置路由像

routes.MapHttpRoute(
name: "GetStudents", 
routeTemplate: "api/students/{id}", 
defaults: new { controller = "StudentsApi", id = RouteParameter.Optional }); 

routes.MapHttpRoute(
name: "GetInstructors", 
routeTemplate: "api/instructors/{id}", 
defaults: new { controller = "InstructorsApi", id = RouteParameter.Optional }); 

这是谈到了将非常麻烦,因为我必须添加的路由在我的控制器的每个方法。我希望应该有一个简单的方法来设置路由模板,在处理路由时自动添加“api”后缀控制器名称。

回答

7

我认为您要查找的可扩展性点是控制器选择器。您可以创建一个从DefaultHttpControllerSelector派生的类,并重写GetControllerName以去除“api”部分。然后,您可以在服务的配置服务上注册该控制器选择器。

+0

听起来像一个好地方看看。我会给你一个镜头,让你知道那是怎么回事。 – muruge

9

正在关注@Youssef Moussaoui的指导我最终编写了解决此问题的以下代码。

public class ApiControllerSelector : DefaultHttpControllerSelector 
{ 
    public ApiControllerSelector(HttpConfiguration configuration) 
     : base(configuration) 
    { 
    } 

    public override string GetControllerName(HttpRequestMessage request) 
    { 
     if (request == null) 
      throw new ArgumentNullException("request"); 

     IHttpRouteData routeData = request.GetRouteData(); 

     if (routeData == null) 
      return null; 

     // Look up controller in route data 
     object controllerName; 
     routeData.Values.TryGetValue("controller", out controllerName); 

     if (controllerName != null) 
      controllerName += "api"; 

     return (string)controllerName; 
    } 
} 

而且在Global.asax中注册为

GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), 
      new ApiControllerSelector(GlobalConfiguration.Configuration)); 
+1

muruge,如果你只是调用base.GetControllerName,然后添加“api”,它会容易得多。但这是正确的想法。很高兴看到这个解决:) –

+0

我同意,这将是更清洁。没有打到我身上。 :) – muruge

+0

我一定错过了一些东西,这不适合我。我看到我的控制器选择器被调用,并且在最后使用api返回,但是我的控制器从未被调用。 –

7

现在的ASP.NET Web API 2已经出来了,还有一个更麻烦的方式去做那些你认为比较复杂的路由,通过使用attribute routing

在控制器的顶部只需添加以下属性:

[RoutePrefix("api/students")] 
public class StudentsApiController : ApiController 
{ 
    ... 
} 

,然后将每个API方法之前:

[Route("{id}"] 
public HttpResponseMessage Get(int id) 
{ 
    ... 
} 

有需要进行一些设置的,但这样做的阳性这种方式的路线很多。首先,您可以将路由与执行实际工作的控制器和方法相关联,这样您就不会四处搜寻,无法知道您是否拥有正确的路线。其次,更重要的是,做更复杂的路由要容易得多,比如让控制器名称与路由名称不同(像你想的那样)或者有非常复杂的模式匹配。

+0

它仍需要具有属性路由的“控制器”后缀。 – angularsen

1

继muruug的回答优素福的评论会是这个样子

public class ApiControllerSelector : DefaultHttpControllerSelector 
{ 
    public ApiControllerSelector (HttpConfiguration configuration) : base(configuration) { } 

    public override string GetControllerName(HttpRequestMessage request) 
    { 
     return base.GetControllerName(request) + "api"; 
    } 
}