如何在ASP.NET Core中向GET方法传递多个参数

183
如何在MVC 6控制器中传递多个参数给Get方法?例如,我想要像下面这样的东西。
[Route("api/[controller]")]
public class PersonController : Controller
{
    public string Get(int id)
    {
    }

    public string Get(string firstName, string lastName)
    {

    }

    public string Get(string firstName, string lastName, string address)
    {

    }
}

所以我可以进行查询。

api/person?id=1
api/person?firstName=john&lastName=doe
api/person?firstName=john&lastName=doe&address=streetA
15个回答

161

你也可以使用这个:

// GET api/user/firstname/lastname/address
[HttpGet("{firstName}/{lastName}/{address}")]
public string GetQuery(string id, string firstName, string lastName, string address)
{
    return $"{firstName}:{lastName}:{address}";
}

注意:请参考metalheartMark Hughes的回答,可能有更好的方法。


30
直到你需要让每个人都有相同的姓氏为止 :) - Phillip Copley
34
这是一个设计 API 路由的非常糟糕的方式...完全不符合 RESTful 规范。 - Thomas Levesque
19
以上的方法看起来很繁琐,我不明白它为什么会有这么多点赞。 - Youp Bernoulli
1
@ThomasLevesque 你说它不符合RESTful的标准是什么意思? - Bruno Santos
4
@BrunoSantos 这不符合REST的原则。URI应该能够唯一标识资源。但这并非此处的情况(可能会有多个人具有相同的名字和姓氏,地址显然不能被视为标识符)。 - Thomas Levesque
显示剩余4条评论

104

为什么不只使用一个控制器动作?

public string Get(int? id, string firstName, string lastName, string address)
{
   if (id.HasValue)
      GetById(id);
   else if (string.IsNullOrEmpty(address))
      GetByName(firstName, lastName);
   else
      GetByNameAddress(firstName, lastName, address);
}

另一个选项是使用属性路由,但这样您需要有不同的URL格式:

//api/person/byId?id=1
[HttpGet("byId")] 
public string Get(int id)
{
}

//api/person/byName?firstName=a&lastName=b
[HttpGet("byName")]
public string Get(string firstName, string lastName, string address)
{
}

1
是的,我现在解决了这个问题,只需使用一个操作来获取我想要搜索Person的所有属性。就像一般搜索一样。不过,我更喜欢在控制器中有重载操作的方式,但可能并非如此。 - mstrand
3
在.NET Core 2.0中无法使用此功能,因为实际上没有生成有效的URL模板。 - ZZZ

73

为了从URL解析搜索参数,您需要在控制器方法的参数上注释[FromQuery],例如:

[Route("api/person")]
public class PersonController : Controller
{
    [HttpGet]
    public string GetById([FromQuery]int id)
    {

    }

    [HttpGet]
    public string GetByName([FromQuery]string firstName, [FromQuery]string lastName)
    {

    }

    [HttpGet]
    public string GetByNameAndAddress([FromQuery]string firstName, [FromQuery]string lastName, [FromQuery]string address)
    {

    }
}

9
为什么需要这个?默认情况下,查询字符串中的参数绑定是自动进行的... - metalheart
1
我已经尝试过两种方式,但是无论是否使用 [FromQuery],重载都会失败。 - mstrand
2
@mstrand 我已经更新了 - 试一下,看看额外的 [HttpGet] 注释、不同的方法名称和 [Route] 中的特定路由 - 现在路由应该是完全明确的,这消除了一些可能的问题。 - Mark Hughes
1
@metalheart 如果没有使用[FromQuery],有时第一个参数的值会作为RouteName传递。 - Sabir Hossain

50

我建议使用一个独立的DTO对象作为参数:

[Route("api/[controller]")]
public class PersonController : Controller
{
    public string Get([FromQuery] GetPersonQueryObject request)
    {
        // Your code goes here
    }
}

public class GetPersonQueryObject 
{
    public int? Id { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public string Address { get; set; }
}

Dotnet会将这些字段映射到您的对象中。

这将使通过参数变得更加容易,也会产生更清晰的代码。


如何在链接中传递值? - Arie
3
你的意思是什么?你可以将值作为查询参数提供,例如 /api/controller?firstname={firstname}&lastname={lastname} - Sebastian
好的和简单的一个 :) - Naveen Kumar V
你的解决方案应该有一个经过检查的标记。它很简单,而且正好符合要求。 - ZecosMAX

16

我认为最简单的方法就是直接使用AttributeRouting

[Route("api/YOURCONTROLLER/{paramOne}/{paramTwo}")]
    public string Get(int paramOne, int paramTwo)
    {
        return "The [Route] with multiple params worked";
    }

我可以使用首选引用类型吗?也就是说,int paramOne,string paramTwo - k4s
如果你想让第二个参数变成可选的,可以使用[Route("api/YOURCONTROLLER/{paramOne}/{paramTwo?}")]。 - Anytoe

14

最简单的方式,

控制器:

[HttpGet("empId={empId}&startDate={startDate}&endDate={endDate}")]
 public IEnumerable<Validate> Get(int empId, string startDate, string endDate){}

Postman 请求:

{router}/empId=1&startDate=2020-20-20&endDate=2020-20-20

学习要点:控制器将接受精确模式的请求。


14

在Web API Core中使用多个参数调用get方法

  [ApiController]
    [Route("[controller]")]
    public class testController : Controller
    {
    
      [HttpGet]
        [Route("testaction/{id:int}/{startdate}/{enddate}")]
        public IEnumerable<classname> test_action(int id, string startdate, string enddate)
        {

            return List_classobject;
        }
    
    }

In web browser
https://Yourdomain/test/testaction/3/2010-09-30/2012-05-01

我简直不敢相信这样的回答会得到这么多赞。你真的是用这种方式构建你的API吗? - Oleg Ivanov
5
@OlegIvanov,您能分享您的答案吗?或者提供任何有用的贡献? - Chris Fremgen

11

方法应该像这样:

[Route("api/[controller]")]
public class PersonsController : Controller
{
    [HttpGet("{id}")]
    public Person Get(int id)

    [HttpGet]
    public Person[] Get([FromQuery] string firstName, [FromQuery] string lastName, [FromQuery] string address)
}

请注意第二种方法返回一个对象数组,控制器名称为复数形式(Persons而不是Person)。

因此,如果您想通过ID获取资源,应该这样写:

api/persons/1

如果您想通过某些搜索条件(例如名字等)获取对象,可以按照以下方式进行搜索:

api/persons?firstName=Name&...

并且,如果您想继续处理该人员的订单(例如),请按以下方式进行:

Translated text:

而今后,如果您想处理那个人的订单(例如),应该像这样:

api/persons/1/orders?skip=0&take=20

同一控制器中的方法:

    [HttpGet("{personId}/orders")]
    public Orders[] Get(int personId, int skip, int take, etc..)

4

这对我很有效

[HttpGet("{data}/{whereList}")]
    public JsonResult GetFieldsData([FromQuery]  string data, [FromQuery]  string whereList)

4
您只需简单地执行以下操作:
    [HttpGet]
    public async Task<IActionResult> GetAsync()
    {
        string queryString = Request.QueryString.ToString().ToLower();

        return Ok(await DoMagic.GetAuthorizationTokenAsync(new Uri($"https://someurl.com/token-endpoint{queryString}")));
    }

如果你需要单独访问每个元素,只需引用 Request.Query

当您拥有一个不断增长且长列表的筛选器和排序条件,并且希望保持端点简单并将查询的验证和解析卸载到另一个类或服务时,这很有用。 - RedRose

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