Cách truyền nhiều tham số cho một phương thức get trong ASP.NET Core


107

Làm cách nào để tôi có thể chuyển nhiều tham số cho các phương thức Nhận trong bộ điều khiển MVC 6. Ví dụ tôi muốn có thể có một cái gì đó như sau.

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

    }
}

Vì vậy, tôi có thể truy vấn như thế nào.

api/person?id=1
api/person?firstName=john&lastName=doe
api/person?firstName=john&lastName=doe&address=streetA

Câu trả lời:


91

Bạn cũng có thể sử dụng cái này:

// 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}";
}

Lưu ý : Vui lòng tham khảo metalheart's và metalheartMark Hughesđể có cách tiếp cận tốt hơn.


21
Cho đến khi bạn cần để có được tất cả mọi người cùng tên cuối cùng :)
Phillip Copley

14
Đó là một cách thực sự tồi để thiết kế các tuyến API ... Không RESTful chút nào.
Thomas Levesque

7
Cách làm trên trông rất rườm rà, không hiểu sao lại có nhiều lượt ủng hộ đến vậy.
Bernoulli IT

1
@ThomasLevesque Ý bạn là gì khi nó không RESTful?
Bruno Santos

2
@BrunoSantos nó không tuân theo các nguyên tắc của REST. URI được cho là xác định duy nhất các tài nguyên. Đây không phải là trường hợp ở đây (có thể có nhiều người có tên đầu tiên và cuối cùng giống nhau, và một địa chỉ có thể chắc chắn không thể được coi là một định danh)
Thomas Levesque

60

Tại sao không chỉ sử dụng một thao tác điều khiển?

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

Một tùy chọn khác là sử dụng định tuyến thuộc tính, nhưng sau đó bạn cần có định dạng URL khác:

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

Có, tôi giải quyết vấn đề này ngay bây giờ chỉ bằng một thao tác thực hiện trong tất cả các thuộc tính mà tôi muốn để có thể tìm kiếm một Người. Giống như một cuộc tìm kiếm chung. Mặc dù vậy, tôi sẽ thích hơn nếu có cách để có các hành động quá tải trong bộ điều khiển nhưng điều đó có thể không đúng.
mstrand

3
điều này không hoạt động với .net core 2.0, vì không có mẫu url hợp lệ nào thực sự được tạo.
ZZZ

44

Để phân tích cú pháp các tham số tìm kiếm từ URL, bạn cần chú thích các tham số phương thức bộ điều khiển với [FromQuery], ví dụ:

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

    }
}

6
tại sao bạn cần cái này? tham số ràng buộc từ chuỗi truy vấn xảy ra theo mặc định ...
metalheart

Tôi đã thử cả nhưng quá tải như tôi cố gắng làm không có hoặc không có [FromQuery]
mstrand

2
@mstrand Tôi đã cập nhật - hãy thử đi, xem các [HttpGet]chú thích bổ sung , các tên phương thức khác nhau và tuyến đường cụ thể trong [Route]- các tuyến đường bây giờ phải hoàn toàn rõ ràng để loại bỏ một số vấn đề có thể xảy ra.
Mark Hughes

9

Tôi nghĩ cách đơn giản nhất là sử dụng AttributeRouting.

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

Tôi có thể sử dụng loại tham chiếu ưa thích không? Đó là,int paramOne, string paramTwo
k4s

Sử dụng [Route ("api / YOURCONTROLLER / {paramOne} / {paramTwo?}")] Nếu bạn muốn thông số thứ hai là tùy chọn
Anytoe

8

Tôi đề nghị sử dụng một đối tượng dto riêng biệt làm đối số:

[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 sẽ ánh xạ các trường tới đối tượng của bạn.

Điều này sẽ làm cho việc chuyển qua các tham số của bạn dễ dàng hơn rất nhiều và dẫn đến mã rõ ràng hơn nhiều.


5

Để gọi get với nhiều tham số trong lõi api web

  [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://localhost:44338/test/testaction/3/2010-09-30/2012-05-01

3

Để thêm một số chi tiết hơn về tình trạng quá tải mà bạn đã hỏi trong nhận xét của mình sau một câu trả lời khác, đây là bản tóm tắt. Các nhận xét trong ApiControllerchương trình hiển thị hành động nào sẽ được gọi với mỗi GETtruy vấn:

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 };
    }
}

Bạn sẽ chỉ cần một tuyến đường duy nhất cho việc này, trong trường hợp bạn tự hỏi:

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

và bạn có thể kiểm tra tất cả bằng chế độ xem MVC này hoặc một cái gì đó mô phỏng. Có, tôi biết bạn không nên kết hợp JavaScript với đánh dấu và tôi không sử dụng bootstrap như bạn thường làm, nhưng điều này chỉ dành cho mục đích demo.

<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>

1

nhập mô tả hình ảnh ở đây

NB-Tôi đã xóa FromURI. Vẫn có thể chuyển giá trị từ URL và nhận kết quả. Nếu ai biết benfifts sử dụng fromuri, hãy cho tôi biết


Như đã quy định trong tài liệu về ràng buộc tham số [1] các kiểu đơn giản, "(int, bool, double, v.v.), cộng với TimeSpan, DateTime, Guid, decimal và string" sẽ tự động được đọc qua URI. Thuộc tính [FromURI] là bắt buộc khi tham số không thuộc một trong các loại này buộc đọc các tham số đó từ URI thay vì vị trí mặc định của chúng, phần thân. Vì lợi ích của sự hoàn chỉnh, thuộc tính [FromBody] về cơ bản ngược lại với các loại phức tạp. [1] docs.microsoft.com/en-us/aspnet/web-api/overview/… )
Seb Andraos

1

Bạn chỉ cần làm như sau:

    [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}")));
    }

Nếu bạn cần truy cập từng phần tử riêng biệt, chỉ cần tham khảo Request.Query.


1

Các phương thức phải như thế này:

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

Hãy lưu ý rằng phương thức thứ hai trả về một mảng các đối tượng và tên bộ điều khiển nằm trong plurar (Người không phải Người).

Vì vậy, nếu bạn muốn lấy tài nguyên bằng id, nó sẽ là:

api/persons/1

nếu bạn muốn lấy các đối tượng theo một số tiêu chí tìm kiếm như tên và v.v., bạn có thể thực hiện tìm kiếm như sau:

api/persons?firstName=Name&...

Và tiếp tục nếu bạn muốn người đó đặt hàng (ví dụ), nó sẽ như thế này:

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

Và phương pháp trong cùng một bộ điều khiển:

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

0
    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");
            }
        }
    }

0

Cách đơn giản nhất,

Bộ điều khiển:

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

Yêu cầu người đưa thư:

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

Điểm học tập: Yêu cầu mẫu chính xác sẽ được Người điều khiển chấp nhận.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.