1

我正在尝试访问以下网址:

http://localhost:2727/api/SiteApi/Get?campaignId=2

这是配置:

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

尝试映射到的操作

public class SiteApiController : ApiController
{
    ...
    public IEnumerable<Site> GetByCampaignId(int campaignId)
    {
        ...
        return sites;   
    }      
}

这当前返回“未找到任何操作”。但是,如果交换路线的顺序,Url 将起作用。这意味着有一场比赛。

问:我对路由的理解是,如果不匹配第一个路由,就会回退到第二个路由。我可以理解它是否映射到错误的路线,但无论我如何订购它们,它都不应该是指示“未找到匹配”之类的错误。

我错过了什么吗?

4

4 回答 4

4

更新

好资源: http: //msdn.microsoft.com/en-us/library/cc668201 (v=vs.100).aspx

从集合中的第一个路由到最后一个路由尝试路由匹配。当匹配发生时,不再评估路由。通常,按照从最具体的路由定义到最不具体的路由定义的顺序将路由添加到 Routes 属性。

您获得“未找到操作”的原因是您的第一条路线匹配。它根本找不到动作 Get - 因为你已经命名了你的方法GetByCampaignId

http://localhost:2727/api/SiteApi/Get?campaignId=2

所以您的理解是正确的 - 但是您的 URL 确实与第一条路线匹配(它只是找不到操作)。

这会将操作映射到您的方法

[ActionName("Get")]
public IEnumerable<Site> GetByCampaignId(int campaignId)
{

}

或者只是将您的网址更改为

http://localhost:2727/api/SiteApi/GetByCampaignId?campaignId=2

如何为您的路线建模

从网址中删除“获取”。

您似乎希望在查询字符串中指定campaignId。

您已经声明了没有该属性的 GetByCampaignId(intcampaignId),[FromUri]因此假定该campaignId 在路径中,即,就目前而言,此方法与/api/siteapi/1 匹配。

如果campaignId 是可选的,像这样改变你的方法签名:

public IEnumerable<Site> GetByCampaignId([FromUri]int? campaignId = null)
{
    if(campaignId.HasValue)
    {
       //....
    }
    return sites;   
}   

如果campaignId 对您的路线是强制性的,请更改您的方法签名,如下所示:

public IEnumerable<Site> GetByCampaignId([FromUri]int campaignId)
{
    return sites;   
}   
于 2012-12-06T09:51:59.163 回答
2

我认为你把事情复杂化了。只需使用默认路由即可。

您的 URL 不需要 Get 部分:

http://localhost:2727/api/SiteApi/Get?campaignId=2

有可能

http://localhost:2727/api/SiteApi/?campaignId=2

因为您的方法的名称中有 Get 这意味着它将响应 HTTP GET 请求(约定很好:http ://www.asp.net/web-api/overview/web-api-routing-and-actions/routing -in-aspnet-web-api)。它会看到动作参数“campaignId”并说“啊哈,我会去那个动作”

public IEnumerable<Site> GetByCampaignId(int campaignId)

当您交换路线时,默认路线启动 - 并获胜。

恕我直言,不需要额外的“DetailedApi”路线。

于 2012-12-06T01:59:39.540 回答
1

我建议使用这个:

http://nuget.org/packages/routedebugger

帮助调试您的路线。

我知道您没有问,但您的示例 URI 不是 RESTful。

要匹配第二条路线,您应该尝试点击此 URI:

http://localhost:2727/api/SiteApi/Get/2

您的第一个映射不应该捕获这条路线,因为没有“2”动作,它会退回到第二个映射。但是,我可以看到这会造成麻烦:我不会使用您的映射。恕我直言,您正在尝试实现与以下相同的效果:

        config.Routes.MapHttpRoute(
          name: "DetailedApi",
          routeTemplate: "api/{controller}/{id}/{action}",
          defaults: new { id = RouteParameter.Optional }
        );
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
于 2012-12-06T01:25:53.630 回答
0

感谢上面给出的所有答案。其中一些很有趣,但是,那些并不是我真正想要的。

基本上,我的问题不是我应该如何映射 URI,而是为什么它没有映射到正确的路由。幸运的是,经过一些测试,我已经找到了答案。

那么为什么“未找到任何操作”?仅仅因为它匹配了我没想到的第一条路线。因为 Id 设置为可选,所以它匹配任何带有两个参数的路由。这就是为什么“SiteAPI”映射到控制器而“Get”映射到 Action。由于campaignId 在查询字符串中,因此在这种情况下尝试映射url 时会被忽略。

我没有提到路由中的其他点点滴滴,但这应该足够了。如果您想了解更多详细信息,请参阅 Mark Jones 的回答。

于 2012-12-06T10:39:29.990 回答