ASP.NET Core'da bir get yöntemine birden çok parametre nasıl iletilir


108

Bir MVC 6 denetleyicisinde yöntemleri almak için birden çok parametreyi nasıl geçirebilirim. Örneğin, aşağıdakine benzer bir şeye sahip olmak istiyorum.

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

    }
}

Böylece sorgulayabilirim.

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

Yanıtlar:


92

Bunu da kullanabilirsiniz:

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

Not : Metalheart en ve bakın metalheartve Mark Hughesbir olasılıkla daha iyi bir yaklaşım için.


22
Aynı soyadı olan herkesi
Phillip Copley

15
Bu, API rotalarını tasarlamanın gerçekten kötü bir yolu ... Hiç RESTful değil.
Thomas Levesque

7
Yukarıdaki yaklaşım çok hantal görünüyor, neden bu kadar çok oy aldığını anlamayın.
Bernoulli IT

1
@ThomasLevesque RESTful olmamakla ne demek istediniz?
Bruno Santos

2
@BrunoSantos REST ilkelerine uymuyor. URI'lerin kaynakları benzersiz bir şekilde tanımlaması beklenir. Burada durum böyle değil (aynı ad ve soyadına sahip birden fazla kişi olabilir ve bir adres kesinlikle bir tanımlayıcı olarak kabul edilemez)
Thomas Levesque

61

Neden tek bir denetleyici eylemi kullanmıyorsunuz?

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

Diğer bir seçenek de öznitelik yönlendirmesini kullanmaktır, ancak daha sonra farklı bir URL biçimine sahip olmanız gerekir:

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

Evet, şimdi bir Kişiyi arayabilmek istediğim tüm özelliklerde tek bir işlem yaparak çözüyorum. Genel bir arama gibi. Yine de, bir denetleyicide aşırı yüklenmiş eylemlere sahip olmanın bir yolu varsa tercih ederim, ancak durum bu olmayabilir.
mstrand

3
bu .net core 2.0 ile çalışmaz, çünkü gerçekte geçerli bir url şablonu oluşturulmaz.
ZZZ

44

Arama parametrelerini URL'den ayrıştırmak için, denetleyici yöntemi parametrelerine [FromQuery]örneğin aşağıdakilerle açıklama eklemeniz gerekir :

[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
buna neden ihtiyacın var? sorgu dizesinden parametre bağlama varsayılan olarak gerçekleşir ...
metalheart

1
İkisini de denedim, ancak [FromQuery] ile veya onsuz başarısız olmaya çalıştığım için aşırı yükleme
mstrand

2
@mstrand Güncelledim - bir deneyin, ekstra [HttpGet]açıklamaları, farklı yöntem adlarını ve belirli rotayı görün [Route]- rotalar şimdi tamamen açık olmalı ve bu da birkaç olası sorunu ortadan kaldırır.
Mark Hughes

9

Bence en kolay yol basitçe kullanmaktır AttributeRouting.

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

Tercih edilen referans türünü kullanabilir miyim? Yani,int paramOne, string paramTwo
k4s

İkinci parametrenizin isteğe bağlı olmasını istiyorsanız [Route ("api / YOURCONTROLLER / {paramOne} / {paramTwo?}")]
Kullanın

8

Argüman olarak ayrı bir dto nesnesi kullanmanızı öneririm:

[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, alanları nesnenize eşleyecektir.

Bu, parametrelerinizden geçmeyi çok daha kolay hale getirecek ve çok daha net bir kodla sonuçlanacaktır.


5

Web api çekirdeğinde birden çok parametre ile almak çağırmak için

  [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

Yorumunuzda sorduğunuz aşırı yükleme hakkında başka bir cevaptan sonra biraz daha ayrıntı eklemek için, işte bir özet. ApiControllerHer GETsorgu ile hangi eylemin çağrılacağını gösterideki yorumlar :

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

Merak ettiyseniz, bunun için yalnızca tek bir rotaya ihtiyacınız olacaktır:

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

ve hepsini bu MVC görünümüyle veya benzer bir şeyle test edebilirsiniz. Evet, JavaScript ile işaretlemeyi karıştırmamanız gerektiğini biliyorum ve normalde yaptığınız gibi önyükleme kullanmıyorum, ancak bu yalnızca demo amaçlıdır.

<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

görüntü açıklamasını buraya girin

NB-FromURI'yi kaldırdım. Yine de URL'den değer aktarabilir ve sonuç alabilirim. Fromuri kullanarak benfifts'i bilen biri varsa bana bildirin


Parametre bağlama belgelerinde belirtildiği gibi [1] basit tipler, "(int, bool, double ve benzeri), artı TimeSpan, DateTime, Guid, decimal ve string" URI'den otomatik olarak okunacaktır. [FromURI] özniteliği, bu türlerden birindeki parametrenin varsayılan konumu olan gövdeden ziyade URI'den olanları okumaya zorlaması durumunda gereklidir. Tamlık uğruna [FromBody] özelliği, karmaşık türlerde esasen tersini yapar. [1] docs.microsoft.com/en-us/aspnet/web-api/overview/… )
Seb Andraos

1

Aşağıdakileri basitçe yapabilirsiniz:

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

Her bir öğeye ayrı ayrı erişmeniz gerekiyorsa, sadece bakın Request.Query.


1

Yöntemler şöyle olmalıdır:

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

İkinci yöntemin bir dizi nesne döndürdüğünü ve denetleyici adının çoğul (Persons not Person) şeklinde olduğunu unutmayın.

Öyleyse kimliğe göre kaynak almak istiyorsanız:

api/persons/1

ad vb. gibi bazı arama kriterlerine göre nesneleri almak istiyorsanız, şu şekilde arama yapabilirsiniz:

api/persons?firstName=Name&...

Ve o kişinin emirlerini (örneğin) almak istiyorsanız, ileriye doğru hareket etmek şu şekilde olmalıdır:

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

Ve aynı denetleyicideki yöntem:

    [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

En basit yol,

Denetleyici:

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

Postacı İsteği:

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

Öğrenme noktası: Kesin model talebi Kontrolör tarafından kabul edilecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.