WebAPI - 控制器上找不到操作方法。

3

我将尝试在我的RESTapi中创建层级链接。例如:

以下URL将提供演员ID为1的详细信息:

/api/v1/actor/id/1/

以下URL应该会给我演员ID为1的所有电影:

/api/v1/actor/1/movies

我的路由:

 config.Routes.MapHttpRoute(
           name: "DefaultCAApi",
           routeTemplate: "api/v1/{controller}/{action}/{id}",
           defaults: new { id = RouteParameter.Optional }
       );

 config.Routes.MapHttpRoute(
                name: "DefaultOneLevelNested",
                routeTemplate: "api/v1/{controller}/{levelOneId}/{action}",
                defaults: new { id = RouteParameter.Optional }
            );

ActorController 中我的操作:

        [HttpGet]
        public HttpResponseMessage Id(int id)
        {
            // logic

            return Request.CreateResponse(HttpStatusCode.OK, actor);
        }

        [HttpGet]
        public HttpResponseMessage Movies(int levelOneId)
        {
            // logic
            return Request.CreateResponse(HttpStatusCode.OK, movies);
        }

但是这个设置对我不起作用。

/api/v1/actor/id/1/ 给我正确的响应。

但是 /api/v1/actor/1/movies 抛出以下错误:

No action was found on the controller 'Actor' that matches the name '1'."

我确实遵循了这个帖子,但对于我来说却没有起作用。

请问有人能为我指出哪里出错了吗?我正在使用MVC 4、WebAPI。


/api/v1/actor/movies/1 看起来更自然,用于获取演员1的电影。而且它也可以在同样的路由上与其他URL一起使用。 - Mihai Caracostea
那么我猜这看起来更自然,对吧?/api/v1/actor/1/id - Mihai Caracostea
1
@Mihai Caracostea:不是,而是这个:/api/v1/actor/1/ - Arry
这是可行的,我会在一秒钟内发布路线。 - Mihai Caracostea
根据引用的示例,您的第一个路由应该是“api/v1/{controller}/{id}/{action}”,而您的第二个路由指定了一个不在路由字符串中的参数的默认值。 - Biscuits
显示剩余2条评论
3个回答

1
尝试交换您的路由顺序:

 config.Routes.MapHttpRoute(
                name: "DefaultOneLevelNested",
                routeTemplate: "api/v1/{controller}/{levelOneId}/{action}",
                defaults: new { id = RouteParameter.Optional }
            );

 config.Routes.MapHttpRoute(
           name: "DefaultCAApi",
           routeTemplate: "api/v1/{controller}/{action}/{id}",
           defaults: new { id = RouteParameter.Optional }
       );

创建路由时,顺序很重要。按照你的方式,它首先匹配第一个(默认路由),而没有找到名称为“1”的操作。

您可能还想了解MVC属性路由,我认为它更容易使用:http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx


感谢您的回答 @BFree。我已经尝试过了,但它并没有起作用。如果我改变顺序,另一条路线就会停止工作。我的意思是这个 /api/v1/actor/id/1/。 - Arry
啊,我误读了你的问题。如果你想遵循REST,你应该把你的路由设置为:/api/v1/actor/1,然后将你的Id操作改为只叫做Get。这应该可以与我提出的路由配置一起工作。 - BFree
这是因为两个URL都匹配了两个路由。请看我在问题中的评论。如果适合您的需求,我会将其发布为答案。 - Mihai Caracostea
@BFree:我已经将 Id 改成 Get(int id),但是还是不行。改成只有 Get() 也不行,因为我需要像这样 /api/v1/actor/1 的 id。 你能否详细解释一下你的解决方案? - Arry
1
使用属性路由,你会少遇到很多问题。记得使用参数约束。 - Carles Company

1
这个解决方法对我有用:

 config.Routes.MapHttpRoute(
               name: "DefaultCAApi",
               routeTemplate: "api/v1/{controller}/{action}/{id}",
               defaults: new { id = RouteParameter.Optional }
           );


            config.Routes.MapHttpRoute(
              name: "LevelOneNested",
              routeTemplate: "api/v1/{controller}/{id}/details/{action}",
              defaults: new { id = RouteParameter.Optional }
          ); 

基本上,我已将我的URL增加了1个路径级别。 它最终变成:
/api/v1/actor/4/details/movies

0
请使用以下路由:

config.Routes.MapHttpRoute(
   name: "DefaultOneLevelNested", 
   routeTemplate: "api/v1/{controller}/{id}/{action}", 
   constraints: new { controller = "actor", action ="movies" }
);

config.Routes.MapHttpRoute(
   name: "DefaultCAApi", 
   routeTemplate: "api/v1/{controller}/{action}/{id}", 
   defaults: new { id = RouteParameter.Optional }
); 

它们应该与您的初始URL匹配。


感谢 @Mihai 的回答。通过您的解决方案,这个问题已经得到了解决:api/v1/actor/1/movies。 但是,访问 /api/v1/actor/id/1/ 仍然报错:控制器上没有找到操作。 - Arry
/api/v1/actor/1 也应该可以正常工作并路由到 Id 操作。 - Mihai Caracostea
请确保您已删除其他路由。 - Mihai Caracostea
移除后,仍然出现对/api/v1/actor/id/1/的相同错误。在控制器'Actor'上找不到与名称'1'匹配的操作。 最终路由: config.Routes.MapHttpRoute( name: "DefaultOneLevelNested", routeTemplate: "api/v1/{controller}/{id}/{action}", defaults: new { id = "id" } ); - Arry
这正是我的问题 :) 但它并不起作用。也许你可以再次发布两个路由,这样我就可以按照你的建议从头开始尝试。然后我会分享结果。 - Arry
显示剩余4条评论

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