Come passare più parametri a un metodo get in ASP.NET Core


108

Come posso passare più parametri ai metodi Get in un controller MVC 6. Ad esempio, voglio essere in grado di avere qualcosa come il seguente.

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

    }
}

Quindi posso interrogare come.

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

Risposte:


92

Puoi anche usare questo:

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

Nota : si prega di fare riferimento a metalheart e metalhearte Mark Hughesper un approccio possibilmente migliore.


22
Fino a quando non avrai bisogno di ottenere tutti con lo stesso cognome :)
Phillip Copley

15
Questo è un modo davvero brutto per progettare percorsi API ... Per niente RESTful.
Thomas Levesque

7
L'approccio di cui sopra sembra molto macchinoso, non capisci perché ha così tanti voti positivi.
Bernoulli IT

1
@ThomasLevesque Cosa intendevi con questo non essere RESTful?
Bruno Santos

2
@BrunoSantos non segue i principi di REST. Gli URI dovrebbero identificare in modo univoco le risorse. Questo non è il caso qui (potrebbero esserci più persone con lo stesso nome e cognome e un indirizzo non può certamente essere considerato un identificatore)
Thomas Levesque,

61

Perché non utilizzare una sola azione del controller?

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

Un'altra opzione è utilizzare il routing degli attributi, ma poi dovresti avere un formato URL diverso:

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

Sì, lo risolvo ora utilizzando una sola azione che include tutti gli attributi su cui voglio essere in grado di cercare una persona. Come una ricerca generale. Preferirei però se ci fosse un modo per avere azioni sovraccariche in un controller, ma potrebbe non essere il caso.
mstrand

3
questo non funziona con .net core 2.0, poiché non viene effettivamente generato alcun modello di URL valido.
ZZZ

44

Per analizzare i parametri di ricerca dall'URL, è necessario annotare i parametri del metodo del controller con [FromQuery], ad esempio:

[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
perché avresti bisogno di questo? l'associazione dei parametri dalla stringa di query avviene per impostazione predefinita ...
metalheart

1
Ho provato entrambi ma il sovraccarico come cerco di fare non riesce con o senza [FromQuery]
mstrand

2
@mstrand ho aggiornato - provaci, guarda le [HttpGet]annotazioni extra , i diversi nomi dei metodi e il percorso specifico in [Route]- le rotte dovrebbero essere completamente esplicite ora, il che elimina alcuni possibili problemi.
Mark Hughes

9

Penso che il modo più semplice sia semplicemente usare AttributeRouting.

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

Posso utilizzare il tipo di riferimento preferito? Cioè,int paramOne, string paramTwo
k4s

Utilizza [Route ("api / YOURCONTROLLER / {paramOne} / {paramTwo?}")] Se desideri che il secondo parametro sia facoltativo
Anytoe

8

Suggerirei di utilizzare un oggetto dto separato come argomento:

[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 mapperà i campi al tuo oggetto.

Questo renderà molto più facile passare attraverso i tuoi parametri e risulterà in un codice molto più chiaro.


5

Per chiamare get con più parametri in web api core

  [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

Per aggiungere qualche dettaglio in più sul sovraccarico che hai chiesto nel tuo commento dopo un'altra risposta, ecco un riepilogo. I commenti nella ApiControllermostra quale azione verrà chiamata con ogni GETquery:

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

Avresti bisogno di un solo percorso per questo, nel caso ti chiedessi:

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

e potresti testare tutto con questa vista MVC, o qualcosa di simile. Sì, so che non dovresti combinare JavaScript con markup e non sto usando bootstrap come faresti normalmente, ma questo è solo a scopo dimostrativo.

<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

inserisci qui la descrizione dell'immagine

NB-Ho rimosso FromURI. Tuttavia posso passare il valore dall'URL e ottenere il risultato.Se qualcuno conosce benfifts usando fromuri fammelo sapere


Come stabilito nella documentazione per l'associazione di parametri [1] tipi semplici, "(int, bool, double e così via), più TimeSpan, DateTime, Guid, decimal e string" verranno letti automaticamente dall'URI. L'attributo [FromURI] è richiesto quando il parametro non è in uno di questi tipi per forzare la lettura di quelli dall'URI piuttosto che la loro posizione predefinita, il corpo. Per motivi di completezza l'attributo [FromBody] fa essenzialmente l'opposto con i tipi complessi. [1] docs.microsoft.com/en-us/aspnet/web-api/overview/… )
Seb Andraos

1

Puoi semplicemente fare quanto segue:

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

Se è necessario accedere a ciascun elemento separatamente, fare semplicemente riferimento a Request.Query.


1

I metodi dovrebbero essere così:

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

Tieni presente che il secondo metodo restituisce un array di oggetti e il nome del controller è in plurar (Persons not Person).

Quindi, se vuoi ottenere la risorsa dall'ID, sarà:

api/persons/1

se vuoi prendere gli oggetti con alcuni criteri di ricerca come il nome e così via, puoi fare la ricerca in questo modo:

api/persons?firstName=Name&...

E andando avanti se vuoi prendere gli ordini di quella persona (ad esempio), dovrebbe essere così:

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

E metodo nello stesso controller:

    [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

Il modo più semplice,

Controller:

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

Richiesta postino:

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

Punto di apprendimento: la richiesta del modello esatto sarà accettata dal Controller.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.