选择操作时,ASP.NET Web Api会忽略RouteParameter.Optional

时间:2012-11-23 09:17:22

标签: c# asp.net-mvc asp.net-mvc-4 asp.net-web-api

我通过以下步骤找到了这个问题:

  1. 使用已安装的项目模板

  2. 创建一个新的WebApi项目
  3. 转到Controllers / ValuesController.cs,有两个 Get 方法,如下所示:

    public IEnumerable<string> Get() //这个提供 GetAll 功能

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

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

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

  5. 我也修改了路线:

        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参数声明为可选两次

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

2 个答案:

答案 0 :(得分: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
}

答案 1 :(得分: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 /付款/的GetValues /?IDS = 123
  2. / API /付款/的GetValues /
  3. 注意:除了默认

    之外没有任何特殊路由