5

我通过以下步骤发现了这个问题:

  1. 使用已安装的项目模板创建一个新的 WebApi 项目

  2. 转到 Controllers/ValuesController.cs,有两个Get方法,如下所示:

    public IEnumerable<string> Get() // 这个提供GetAll函数

    public string Get(int id) // 这个是GetOneById

  3. 我不喜欢这种设计,因为我认为这两种api方法可以合二为一:

    public IEnumerable<string> Get(string ids)当 ids 为 null 时,返回所有记录,否则按 ids 返回结果(看起来像 id1,id2,id3...)

我也修改了路线:

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

现在我想一切都准备好了。但是,当我/values在浏览器中访问时(未指定 ids 参数),我被告知“未找到任何操作”,直到我为以下添加默认值ids

public IEnumerable<string> Get(string ids = null)

从现在开始,一切都按我的预期工作。我仍然无法defaults在路线中移动参数。这意味着:代码将 ids 参数声明为可选两次

查看位于方法的 MVC4 的源代码System.Web.Http.Controllers.ActionSelectorCacheItem.FindActionUsingRouteAndQueryParameters,我可以看到在找到正确的操作时忽略了路由中定义的可选参数。我个人认为这真的很糟糕,即使解决方法也很容易。还是我误解了路线和动作方法之间的关系?我认为路由是用于帮助请求找到其相应操作的规则,而“参数是可选的”正是规则的一部分。

4

2 回答 2

4

您可能有一个论点,这对于相对直接的事情来说感觉像是一个尴尬的解决方案,但我认为根本原因是因为您试图将 'GetAll' 和 'GetOneById' 滚动到同一个方法中。

如果您愿意拆分控制器中的方法,则可以将路由配置排除在外。恕我直言,这不是一件坏事;它符合关注点分离原则。这也不意味着代码的任何重复,因为您可以集中逻辑来访问要返回的对象。

这些控制器方法应该为您提供所需的路由,而无需调整路由配置:

[HttpGet]
public IEnumerable<string> GetAll()
{
    return GetStrings(new int[]{});
}

[HttpGet]
public string GetOneById(int id)
{
    return GetStrings(new int[]{id}).FirstOrDefault();
}

private IEnumerable<string> GetStrings(int[] ids)
{
     return // fetch strings using int array
}
于 2012-11-23T10:04:40.157 回答
1

您可以选择将值作为查询字符串

public class PaymentsController : ApiController {
        [HttpGet]
        public Person GetValues(string ids = null)
        {
            return new Person() { FirstName = "Michael" };
        }
    }

    public class Person
    {
        public string FirstName { get; set; }
    }
}

我能够通过以下两种方式访问​​这条路线:

  1. /api/payments/getvalues/?ids=123
  2. /api/payments/getvalues/

注意:除默认路由外,没有任何特殊路由

于 2012-11-23T10:00:45.887 回答