ASP.NET Web Api路由自定义化

13

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

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”后缀添加到控制器名称。

4个回答

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”,这会容易得多。但是你的想法是正确的。很高兴看到这个问题解决了 :) - Youssef Moussaoui
我同意,那会更加简洁。没想到呢。 :) - muruge
我一定漏掉了什么,这对我不起作用。我看到我的控制器选择器被调用,并在末尾返回api,但我的控制器从未被调用。 - Aaron Stainback

8
现在 ASP.NET Web API 2 已经发布,有一种更简便的方法来处理像你建议的那样更复杂的路由,即使用 属性路由

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

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

然后在每个API方法之前:

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

需要进行一些设置,但以这种方式进行路由的好处很多。首先,您可以将路由与执行实际工作的控制器和方法放在一起,因此您永远不必搜索以确定是否具有正确的路由。其次,更重要的是,更容易进行更复杂的路由,例如使控制器名称与路由名称不同(如所需)或具有非常复杂的匹配模式。


它仍需要使用属性路由的“Controller”后缀。 - angularsen

7

我认为你需要的可扩展点是控制器选择器。你可以创建一个派生自DefaultHttpControllerSelector的类,并重写GetControllerName方法以剥离掉“api”部分。然后,你可以在服务的配置Services中注册这个控制器选择器。


听起来是一个不错的研究方向。我会尝试一下并告诉你结果的。 - muruge

1

根据Youssef对muruug答案的评论,应该是这样的

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接