Cara melewatkan beberapa parameter ke metode get di ASP.NET Core

108

Bagaimana saya bisa meneruskan beberapa parameter untuk mendapatkan metode dalam pengontrol MVC 6. Misalnya saya ingin bisa memiliki sesuatu seperti berikut ini.

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

    }
}

Jadi saya bisa menanyakan seperti.

api/person?id=1
api/person?firstName=john&lastName=doe
api/person?firstName=john&lastName=doe&address=streetA
mstrand.dll
sumber

Jawaban:

92

Anda juga bisa menggunakan ini:

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

Catatan : Silakan merujuk ke metalheart dan metalheartdan Mark Hughesuntuk pendekatan yang mungkin lebih baik.

antlas
sumber
22
Sampai Anda perlu mendapatkan semua orang dengan nama belakang yang sama :)
Phillip Copley
15
Itu cara yang sangat buruk untuk merancang rute API ... Tidak tenang sama sekali.
Thomas Levesque
7
Pendekatan di atas terlihat sangat rumit, jangan mengerti mengapa ini memiliki begitu banyak suara positif.
Bernoulli IT
1
@ThomasLevesque Apa yang Anda maksud dengan tidak tenang?
Bruno Santos
2
@BrunoSantos tidak mengikuti prinsip REST. URI seharusnya mengidentifikasi resource secara unik. Ini tidak terjadi di sini (mungkin ada beberapa orang dengan nama depan dan belakang yang sama, dan alamat pasti tidak dapat dianggap sebagai pengenal)
Thomas Levesque
61

Mengapa tidak menggunakan hanya satu tindakan pengontrol?

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

Opsi lainnya adalah menggunakan perutean atribut, tetapi Anda harus memiliki format URL yang berbeda:

//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)
{
}
metalheart
sumber
Ya, saya menyelesaikannya sekarang hanya dengan menggunakan satu tindakan yang mengambil semua atribut yang saya inginkan untuk dapat mencari Person. Seperti pencarian umum. Saya lebih suka jika ada di mana cara untuk memiliki tindakan kelebihan beban dalam pengontrol tetapi itu mungkin tidak terjadi.
mstrand
3
ini tidak bekerja dengan .net core 2.0, karena tidak ada template url valid yang dibuat.
ZZZ
44

Untuk mengurai parameter pencarian dari URL, Anda perlu memberi anotasi parameter metode pengontrol dengan [FromQuery], misalnya:

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

    }
}
Mark Hughes
sumber
6
mengapa kamu membutuhkan ini? pengikatan parameter dari string kueri terjadi secara default ...
metalheart
1
Saya telah mencoba keduanya tetapi kelebihan beban saat saya coba lakukan gagal dengan atau tanpa [FromQuery]
mstrand
2
@mstrand Saya telah memperbarui - cobalah, lihat [HttpGet]penjelasan tambahan , nama metode yang berbeda, dan rute spesifik di [Route]- rute harus sepenuhnya eksplisit sekarang yang menghilangkan beberapa kemungkinan masalah.
Mark Hughes
9

Menurut saya cara termudah adalah dengan menggunakan AttributeRouting.

[Route("api/YOURCONTROLLER/{paramOne}/{paramTwo}")]
    public string Get(int paramOne, int paramTwo)
    {
        return "The [Route] with multiple params worked";
    }
Sunil Dhappadhule
sumber
Bisakah saya menggunakan tipe referensi yang disukai? Yaitu,int paramOne, string paramTwo
k4s
Gunakan [Route ("api / YOURCONTROLLER / {paramOne} / {paramTwo?}")] Jika Anda ingin parameter kedua menjadi opsional
Anytoe,
8

Saya akan menyarankan untuk menggunakan objek dto terpisah sebagai argumen:

[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 akan memetakan bidang ke objek Anda.

Ini akan membuatnya lebih mudah untuk melewati parameter Anda dan akan menghasilkan kode yang lebih jelas.

Sebastian
sumber
5

Untuk memanggil get dengan beberapa parameter di inti 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
Prash9002
sumber
3

Untuk menambahkan beberapa detail lebih lanjut tentang kelebihan beban yang Anda tanyakan dalam komentar Anda setelah jawaban lain, berikut adalah ringkasannya. Komentar di ApiControlleracara mana yang akan dipanggil dengan setiap GETkueri:

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

Anda hanya memerlukan satu rute untuk ini, jika Anda bertanya-tanya:

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

dan Anda bisa menguji semuanya dengan tampilan MVC ini, atau sesuatu yang serupa. Ya, saya tahu Anda tidak seharusnya mencampur JavaScript dengan markup dan saya tidak menggunakan bootstrap seperti biasanya, tetapi ini hanya untuk tujuan 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>
Kent Weigel
sumber
1

masukkan deskripsi gambar di sini

NB-Saya menghapus FromURI. Masih saya bisa meneruskan nilai dari URL dan mendapatkan hasil. Jika ada yang tahu manfaat menggunakan fromuri beri tahu saya

saktiprasad swain
sumber
Seperti yang ditetapkan dalam dokumentasi untuk parameter binding [1] tipe sederhana, "(int, bool, double, dan sebagainya), ditambah TimeSpan, DateTime, Guid, desimal, dan string" akan secara otomatis dibaca dari URI. Atribut [FromURI] diperlukan ketika parameter di bukan salah satu dari jenis ini untuk memaksa pembacaan dari URI daripada lokasi defaultnya, yaitu body. Demi kelengkapan, atribut [FromBody] pada dasarnya melakukan kebalikan dari tipe kompleks. [1] docs.microsoft.com/en-us/aspnet/web-api/overview/… )
Seb Andraos
1

Anda cukup melakukan hal berikut:

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

Jika Anda perlu mengakses setiap elemen secara terpisah, cukup lihat Request.Query.

SpiritBob
sumber
1

Caranya harus seperti ini:

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

Perhatikan bahwa metode kedua mengembalikan array objek dan nama pengontrol dalam bentuk jamak (Persons not Person).

Jadi jika Anda ingin mendapatkan sumber daya dengan id itu akan menjadi:

api/persons/1

jika Anda ingin mengambil objek dengan beberapa kriteria pencarian seperti nama depan dan lain-lain, Anda dapat melakukan pencarian seperti ini:

api/persons?firstName=Name&...

Dan bergerak maju jika Anda ingin menerima pesanan orang itu (misalnya), akan seperti ini:

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

Dan metode dalam pengontrol yang sama:

    [HttpGet("{personId}/orders")]
    public Orders[] Get(int personId, int skip, int take, etc..)
Paulius K.
sumber
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");
            }
        }
    }
Jesse Mwangi
sumber
0

Cara termudah,

Pengontrol:

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

Permintaan Tukang Pos:

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

Poin pembelajaran: Permintaan pola yang tepat akan diterima oleh Controller.

Thushara Buddhika
sumber