【问题标题】:How to pass multiple parameters to a get method in ASP.NET Core如何将多个参数传递给 ASP.NET Core 中的 get 方法
【发布时间】:2016-07-16 19:27:18
【问题描述】:

如何将多个参数传递给 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

【问题讨论】:

    标签: c# asp.net-core asp.net-core-routing


    【解决方案1】:

    你也可以用这个:

    // 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 的答案,以获得更好的方法。

    【讨论】:

    • 直到你需要让每个人都使用相同的姓氏:)
    • 那是设计 API 路由的一种非常糟糕的方式......根本不是 RESTful。
    • 上面的方法看起来很麻烦,不明白为什么会有这么多的点赞。
    • @ThomasLevesque 你说它不是 RESTful 是什么意思?
    • @BrunoSantos 它不遵循 REST 原则。 URI 应该唯一标识资源。这里不是这样(可能有多个人的名字和姓氏相同,地址当然不能被视为标识符)
    【解决方案2】:

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

    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)
    {
    }
    

    【讨论】:

    • 是的,我现在只使用一个操作来解决它,该操作包含我希望能够搜索出 Person 的所有属性。像一般搜索一样。如果有一种方法可以在控制器中进行重载操作,我更愿意,但情况可能并非如此。
    • 这不适用于 .net core 2.0,因为实际上没有生成有效的 url 模板。
    【解决方案3】:

    从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)
        {
    
        }
    }
    

    【讨论】:

    • 你为什么需要这个?查询字符串中的参数绑定默认发生...
    • 我都试过了,但是我尝试做的重载不管有没有[FromQuery]都会失败
    • @mstrand 我已经更新了 - 试一试,查看额外的 [HttpGet] 注释、不同的方法名称以及 [Route] 中的特定路由 - 路由现在应该是完全明确的消除了一些可能的问题。
    • @metalheart 没有[FromQuery] 有时第一个参数值是RouteName
    【解决方案4】:

    我建议使用单独的 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 会将字段映射到您的对象。

    这将使传递参数变得更加容易,并且会产生更清晰的代码。

    【讨论】:

    • 以及如何在链接中传递值?
    • 这是什么意思?您可以将值作为查询参数提供,例如 /api/controller?firstname={firstname}&lastname={lastname}
    • 又好又简单的一个:)
    【解决方案5】:

    我认为最简单的方法是简单地使用AttributeRouting

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

    【讨论】:

    • 我可以使用首选参考类型吗?即int paramOne, string paramTwo
    • 如果您希望第二个参数是可选的,请使用 [Route("api/YOURCONTROLLER/{paramOne}/{paramTwo?}")]
    【解决方案6】:

    在 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 吗?
    • @OlegIvanov 愿意分享您的答案吗?或者贡献什么有用的东西?
    【解决方案7】:

    最简单的方法,

    控制器:

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

    邮递员请求:

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

    学习点:Controller 会接受请求的精确模式。

    【讨论】:

      【解决方案8】:

      方法应该是这样的:

      [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 not Person)。

      因此,如果您想通过 id 获取资源,它将是:

      api/persons/1
      

      如果您想通过一些搜索条件(例如名字等)来获取对象,您可以像这样进行搜索:

      api/persons?firstName=Name&...
      

      如果你想接受那个人的命令(例如),那么应该是这样的:

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

      和方法在同一个控制器中:

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

      【讨论】:

        【解决方案9】:

        要在另一个答案之后添加有关您在评论中询问的重载的更多详细信息,这里是一个摘要。 ApiController 中的 cmets 显示每个 GET 查询将调用哪个操作:

        public class ValuesController : ApiController
        {
            // EXPLANATION: See the view for the buttons which call these WebApi actions. For WebApi controllers, 
            //          there can only be one action for a given HTTP verb (GET, POST, etc) which has the same method signature, (even if the param names differ) so
            //          you can't have Get(string height) and Get(string width), but you can have Get(int height) and Get(string width).
            //          It isn't a particularly good idea to do that, but it is true. The key names in the query string must match the
            //          parameter names in the action, and the match is NOT case sensitive. This demo app allows you to test each of these
            //          rules, as follows:
            // 
            // When you send an HTTP GET request with no parameters (/api/values) then the Get() action will be called.
            // When you send an HTTP GET request with a height parameter (/api/values?height=5) then the Get(int height) action will be called.
            // When you send an HTTP GET request with a width parameter (/api/values?width=8) then the Get(string width) action will be called.
            // When you send an HTTP GET request with height and width parameters (/api/values?height=3&width=7) then the 
            //          Get(string height, string width) action will be called.
            // When you send an HTTP GET request with a depth parameter (/api/values?depth=2) then the Get() action will be called
            //          and the depth parameter will be obtained from Request.GetQueryNameValuePairs().
            // When you send an HTTP GET request with height and depth parameters (/api/values?height=4&depth=5) then the Get(int height) 
            //          action will be called, and the depth parameter would need to be obtained from Request.GetQueryNameValuePairs().
            // When you send an HTTP GET request with width and depth parameters (/api/values?width=3&depth=5) then the Get(string width) 
            //          action will be called, and the depth parameter would need to be obtained from Request.GetQueryNameValuePairs().
            // When you send an HTTP GET request with height, width and depth parameters (/api/values?height=7&width=2&depth=9) then the 
            //          Get(string height, string width) action will be called, and the depth parameter would need to be obtained from 
            //          Request.GetQueryNameValuePairs().
            // When you send an HTTP GET request with a width parameter, but with the first letter of the parameter capitalized (/api/values?Width=8) 
            //          then the Get(string width) action will be called because the case does NOT matter.
            // NOTE: If you were to uncomment the Get(string height) action below, then you would get an error about there already being  
            //          a member named Get with the same parameter types. The same goes for Get(int id).
            //
            // ANOTHER NOTE: Using the nullable operator (e.g. string? paramName) you can make optional parameters. It would work better to
            //          demonstrate this in another ApiController, since using nullable params and having a lot of signatures is a recipe
            //          for confusion.
        
            // GET api/values
            public IEnumerable<string> Get()
            {
                return Request.GetQueryNameValuePairs().Select(pair => "Get() => " + pair.Key + ": " + pair.Value);
                //return new string[] { "value1", "value2" };
            }
        
            //// GET api/values/5
            //public IEnumerable<string> Get(int id)
            //{
            //    return new string[] { "Get(height) => height: " + id };
            //}
        
            // GET api/values?height=5
            public IEnumerable<string> Get(int height) // int id)
            {
                return new string[] { "Get(height) => height: " + height };
            }
        
            // GET api/values?height=3
            public IEnumerable<string> Get(string height)
            {
                return new string[] { "Get(height) => height: " + height };
            }
        
            //// GET api/values?width=3
            //public IEnumerable<string> Get(string width)
            //{
            //    return new string[] { "Get(width) => width: " + width };
            //}
        
            // GET api/values?height=4&width=3
            public IEnumerable<string> Get(string height, string width)
            {
                return new string[] { "Get(height, width) => height: " + height + ", width: " + width };
            }
        }
        

        如果您想知道,您只需要一条路线即可:

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

        你可以用这个 MVC 视图或类似的东西来测试它。是的,我知道您不应该将 JavaScript 与标记混合使用,而且我没有像往常那样使用引导程序,但这仅用于演示目的。

        <div class="jumbotron">
            <h1>Multiple parameters test</h1>
            <p class="lead">Click a link below, which will send an HTTP GET request with parameters to a WebAPI controller.</p>
        </div>
        <script language="javascript">
            function passNothing() {
                $.get("/api/values", function (data) { alert(data); });
            }
        
            function passHeight(height) {
                $.get("/api/values?height=" + height, function (data) { alert(data); });
            }
        
            function passWidth(width) {
                $.get("/api/values?width=" + width, function (data) { alert(data); });
            }
        
            function passHeightAndWidth(height, width) {
                $.get("/api/values?height=" + height + "&width=" + width, function (data) { alert(data); });
            }
        
            function passDepth(depth) {
                $.get("/api/values?depth=" + depth, function (data) { alert(data); });
            }
        
            function passHeightAndDepth(height, depth) {
                $.get("/api/values?height=" + height + "&depth=" + depth, function (data) { alert(data); });
            }
        
            function passWidthAndDepth(width, depth) {
                $.get("/api/values?width=" + width + "&depth=" + depth, function (data) { alert(data); });
            }
        
            function passHeightWidthAndDepth(height, width, depth) {
                $.get("/api/values?height=" + height + "&width=" + width + "&depth=" + depth, function (data) { alert(data); });
            }
        
            function passWidthWithPascalCase(width) {
                $.get("/api/values?Width=" + width, function (data) { alert(data); });
            }
        </script>
        <div class="row">
            <button class="btn" onclick="passNothing();">Pass Nothing</button>
            <button class="btn" onclick="passHeight(5);">Pass Height of 5</button>
            <button class="btn" onclick="passWidth(8);">Pass Width of 8</button>
            <button class="btn" onclick="passHeightAndWidth(3, 7);">Pass Height of 3 and Width of 7</button>
            <button class="btn" onclick="passDepth(2);">Pass Depth of 2</button>
            <button class="btn" onclick="passHeightAndDepth(4, 5);">Pass Height of 4 and Depth of 5</button>
            <button class="btn" onclick="passWidthAndDepth(3, 5);">Pass Width of 3 and Depth of 5</button>
            <button class="btn" onclick="passHeightWidthAndDepth(7, 2, 9);">Pass Height of 7, Width of 2 and Depth of 9</button>
            <button class="btn" onclick="passHeightWidthAndDepth(7, 2, 9);">Pass Height of 7, Width of 2 and Depth of 9</button>
            <button class="btn" onclick="passWidthWithPascalCase(8);">Pass Width of 8, but with Pascal case</button>
        </div>
        

        【讨论】:

          【解决方案10】:

          这对我有用

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

          【讨论】:

            【解决方案11】:

            NB-我删除了 FromURI 。我仍然可以从 URL 传递值并获得结果。如果有人知道使用 fromuri 的好处,请告诉我

            【讨论】:

            • 参数绑定[1]简单类型的文档中规定,“(int、bool、double等),加上TimeSpan、DateTime、Guid、decimal和string”会自动读取 URI。当参数不是这些类型之一时,属性 [FromURI] 是必需的,以强制从 URI 而不是它们的默认位置(正文)中读取这些参数。为了完整起见,[FromBody] 属性对复杂类型的作用基本上相反。 [1]docs.microsoft.com/en-us/aspnet/web-api/overview/…)
            【解决方案12】:

            您可以简单地执行以下操作:

                [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

            【讨论】:

              【解决方案13】:
                  public HttpResponseMessage Get(int id,string numb)
                  {
              
                      using (MarketEntities entities = new MarketEntities())
                      {
                        var ent=  entities.Api_For_Test.FirstOrDefault(e => e.ID == id && e.IDNO.ToString()== numb);
                          if (ent != null)
                          {
                              return Request.CreateResponse(HttpStatusCode.OK, ent);
                          }
                          else
                          {
                              return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Applicant with ID " + id.ToString() + " not found in the system");
                          }
                      }
                  }
              

              【讨论】:

                【解决方案14】:

                如果你允许我,我想自己回答(我正在使用 .NET 5 + React)

                控制器:

                namespace MyProject.Controllers
                {
                    [Route("[controller]")]
                    public class ExampleController : Controller
                    {
                        public string Get(string param1, string param2, string param3)
                        {
                            //your code here
                        }
                    }
                }
                

                JS(反应):

                fetch(`example?param1=${val1}&param2=${val2}&param3=${val3}`)
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-01-27
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-06-30
                  • 2019-02-02
                  • 2015-02-02
                  • 2012-06-11
                  相关资源
                  最近更新 更多