简体   繁体   中英

How to pass multiple parameters to Get Method and Route them in .NET Core Web API?

I'm making a (restful) Web API in .NET Core and stumbled among some problems.

I cannot seem to find how to pass multiple subscription ID's... I need to be able to show multiple periods(invoices) of multiple subscriptions.

My route at the moment is [Route("tenants/{tenantId:long}/subscriptions/{subscriptionId:long}/invoices/{invoiceId:long}/categories")]

From this way it seems impossible for me to pass more subscription IDs. Some terms I found but not fully understand are:

  • Model Binding
  • [FromQuery]

My classes:

    public class Subscription
    {
    public string Name { get; set; }
    public long TenantId { get; set; }
    public string Guid { get; set; }
    }

    public class Invoice
    {
    public long SubscriptionId { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public long PortalId { get; set; }
    }

My controllers with routes [Route("tenants/{tenantId:long}/subscriptions")] and [Route("tenants/{tenantId:long}/subscriptions/{subscriptionId:long}/invoices")]

    [HttpGet]
    public IEnumerable<SubscriptionViewModel> Find(long tenantId)
    {
        var subscriptionList = _subscriptionManager.Find(tenantId);
        ...
        return subscriptionViewModels;
    }

    [HttpGet]
    public IEnumerable<InvoiceViewModel> Find(long subscriptionId)
    {
        var invoiceList = _invoiceManager.Find(subscriptionId);
        ...
        return invoiceViewModels;
    }
  • Please note that i'm using a Mapper for my data (which is why i'm using ViewModels).
  • The currently written code is for a specific subscription.

I am looking for a Route like /api/invoices?subscriptionId=x,y,z

I understand(?) I need the [FromQuery] for that, but I cannot seem to find out how, especially if my parameter (subscriptionId) stays the same.

for the requirement which you have mentioned as:

I am looking for a Route like /api/invoices?subscriptionId=x,y,z

You can do couple of things:

  1. pass the subscriptionIds one after the other separated by & in the query string of the URL and change the input parameter of action method to accept array of subscriptionIds example of route:
/api/invoices/find?subscriptionId=x&subscriptionId=y&subscriptionId=z

example of action method parameter accepting array of subscriptionIds:

public IEnumerable<InvoiceViewModel> Find([FromQuery]long[] subscriptionId)
  1. pass the comma separated string as querystring in the URL and write a piece of logic in the action method to split the string based on comma to get an array of subscriptionIds example of route:
/api/invoices/find?subscriptionIds=x,y,z

example of action method:

public IEnumerable<InvoiceViewModel> Find([FromQuery]string subscriptionIds)
{
    var ids = subscriptionIds.Split(',').Select(int.Parse).ToArray();
    // do the logic on multiple subscriptionIds
}

Apart from this, you can go for creating custom model binders as well as suggested in other answers.

Hope this helps.

You can create a specific Request view model which accepts a collection of invoice ids:

public class InvoiceRequestModel
{
    IEnumerable<long> InvoiceIDS { get; set; }
}

and use it for your action method:

[Route("tenants/{tenantId:long}/subscriptions/{subscriptionId:long}/invoices")]
[HttpGet]
public IEnumerable<InvoiceViewModel> Get(InvoiceRequestModel requestModel)
{

}

In the case you want to use query parameters, mark your action parameter with the [FromQuery] attribute:

[Route("tenants/{tenantId:long}/subscriptions/{subscriptionId:long}/invoices")]
[HttpGet]
public IEnumerable<InvoiceViewModel> Get([FromQuery]IEnumerable<long> invoiceIDs)
{

}

and on creating the request, pass each value with the same key in the query string:

invoiceIDs=1&invoiceIDs=2&invoiceIDs=3

Finally, it will look like this:

tenants/{tenantId}/subscriptions/{subscriptionId}/invoices?invoiceIDs=1&invoiceIDs=2&invoiceIDs=3

There can be many ways to achieve this task (I can think of two-three for now).

1) instead of long subscriptionid take a string as an input and validate it before proceeding further.

[HttpGet]
public IEnumerable<InvoiceViewModel> Find(string subscriptionIds)
{
    var list = validateInput(subscriptionIds);
    var invoiceList = _invoiceManager.FindList(list);
    ...
    return invoiceViewModels;
}

public IList<long> validateInput(string subscriptionIds)
{
    var list = subscriptionIds.Split(",");
    ... // Code to convert each element in long and throw if it is not long
    return longlist;
}

2) Create custom model binders.

Steps are mentioned here:

https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

=> [FromUri] attribute can be used to bind the Complex types from query string parameters but i am not sure how i would use that.

If you ask me, i would go for approach-1 (not to increase complexity).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM