How should I pass multiple parameters to an ASP.Net Web API GET?

asp.netasp.net MvcRestasp.net Mvc-4asp.net Web-Api

asp.net Problem Overview


I am using the .Net MVC4 Web API to (hopefully) implement a RESTful api. I need to pass in a few parameters to the system and have it perform some action, then return a list of objects as the results. Specifically I am passing in two dates and returning records that fall between them. I'm also keeping track of the records returned so that subsequent calls do not get reprocessed in the system.

I've considered a few approaches:

  1. Serializing the params into one single JSON string and picking it apart in the API. http://forums.asp.net/t/1807316.aspx/1

  2. Pass the params in the query string.
    https://stackoverflow.com/questions/2640560/what-is-best-way-to-pass-multiple-query-parameters-to-a-restful-api

  3. Defining the params in the route: api/controller/date1/date2

  4. Using a POST that inherently lets me pass an object with params.

  5. Researching ODATA since the Web API (currently) supports it. I haven't done much with this yet so I'm not very familiar with it.

It seems that proper REST practices indicate when data is pulled, you should use a GET. However, GET should also be nullipotent (produces no side-effects), and I wonder if my specific implementation violates that since I mark records in the API system, hence I am producing side-effects.

It also led me to the question of supporting variable parameters. If the input parameter list changes, it would be tedious to have to re-define your route for Choice 3 if that happens a lot. And what might happen if the parameters are defined at run-time...

In any case, for my specific implementation, which choice (if any) seems best?

asp.net Solutions


Solution 1 - asp.net

I think the easiest way is to simply use AttributeRouting.

It's obvious within your controller, why would you want this in your Global WebApiConfig file?

Example:

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

The {} names need to match your parameters.

Simple as that, now you have a separate GET that handles multiple params in this instance.

Solution 2 - asp.net

Just add a new route to the WebApiConfig entries.

For instance, to call:

public IEnumerable<SampleObject> Get(int pageNumber, int pageSize) { ..

add:

config.Routes.MapHttpRoute(
    name: "GetPagedData",
    routeTemplate: "api/{controller}/{pageNumber}/{pageSize}"
);

Then add the parameters to the HTTP call:

GET //<service address>/Api/Data/2/10 

     

Solution 3 - asp.net

I just had to implement a RESTfull api where I need to pass parameters. I did this by passing the parameters in the query string in the same style as described by Mark's first example "api/controller?start=date1&end=date2"

In the controller I used a tip from https://stackoverflow.com/questions/1029909/url-split-in-c

// uri: /api/courses
public IEnumerable<Course> Get()
{
    NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
    var system = nvc["System"];
    // BL comes here
    return _courses;
}

In my case I was calling the WebApi via Ajax looking like:

$.ajax({
        url: '/api/DbMetaData',
        type: 'GET',
        data: { system : 'My System',
                searchString: '123' },
        dataType: 'json',
        success: function (data) {
                  $.each(data, function (index, v) {
                  alert(index + ': ' + v.name);
                  });
         },
         statusCode: {
                  404: function () {
                       alert('Failed');
                       }
        }
   });

I hope this helps...

Solution 4 - asp.net

I found exellent solution on http://habrahabr.ru/post/164945/

public class ResourceQuery
{
   public string Param1 { get; set; }
   public int OptionalParam2 { get; set; }
}

public class SampleResourceController : ApiController
{
    public SampleResourceModel Get([FromUri] ResourceQuery query)
    {
        // action
    }
}

Solution 5 - asp.net

What does this record marking mean? If this is used only for logging purposes, I would use GET and disable all caching, since you want to log every query for this resources. If record marking has another purpose, POST is the way to go. User should know, that his actions effect the system and POST method is a warning.

Solution 6 - asp.net

Using GET or POST is clearly explained by @LukLed. Regarding the ways you can pass the parameters I would suggest going with the second approach (I don't know much about ODATA either).

> 1.Serializing the params into one single JSON string and picking it apart in the API. http://forums.asp.net/t/1807316.aspx/1

This is not user friendly and SEO friendly

> 2.Pass the params in the query string. What is best way to pass multiple query parameters to a restful api?

This is the usual preferable approach.

> 3.Defining the params in the route: api/controller/date1/date2

This is definitely not a good approach. This makes feel some one date2 is a sub resource of date1 and that is not the case. Both the date1 and date2 are query parameters and comes in the same level.

In simple case I would suggest an URI like this,

api/controller?start=date1&end=date2

But I personally like the below URI pattern but in this case we have to write some custom code to map the parameters.

api/controller/date1,date2

Solution 7 - asp.net

Solution 8 - asp.net

 [Route("api/controller/{one}/{two}")]
    public string Get(int One, int Two)
    {
        return "both params of the root link({one},{two}) and Get function parameters (one, two)  should be same ";
    }

Both params of the root link({one},{two}) and Get function parameters (one, two) should be same

Solution 9 - asp.net

I know this is really old, but I wanted the same thing recently and here's what I found...

    public HttpResponseMessage Get([FromUri] string var, [FromUri] string test) {
        var retStr = new HttpResponseMessage(HttpStatusCode.OK);
        if (var.ToLower() == "getnew" && test.ToLower() == "test") {
            retStr.Content = new StringContent("Found Test", System.Text.Encoding.UTF8, "text/plain");
        } else {
            retStr.Content = new StringContent("Couldn't Find that test", System.Text.Encoding.UTF8, "text/plain");
        }

        return retStr;
    }

So now in your address/URI/...

http(s)://myURL/api/myController/?var=getnew&test=test

Result: "Found Test"


http(s)://myURL/api/myController/?var=getnew&test=anything

Result: "Couldn't Find that test"

Solution 10 - asp.net

Now you can do this by simply using

        public string Get(int id, int abc)
        {
            return "value: " + id + "  " + abc;
        }

this will return: "value: 5 10"

if you call it with https://yourdomain/api/yourcontroller?id=5&abc=10

Solution 11 - asp.net

    public HttpResponseMessage Get(int id,string numb)
    {
        //this will differ according to your entity name
        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");
            }
        }
    }

Solution 12 - asp.net

This code works for me. Then I can use the regular querystring on the url http://.../api/GetSomething?paramOne=1¶mTwo=2

.NET 6 Core

[Route("api/GetSomething")]
public IActionResult GetSomething(int paramOne, int paramTwo)
{
    ...    
    return Content(jsonData);
}

instead of doing the following [Route("api/GetSomething/{paramOne}/{paramTwo}")]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionsig606View Question on Stackoverflow
Solution 1 - asp.netMark Pieszak - Trilon.ioView Answer on Stackoverflow
Solution 2 - asp.netGraham WrightView Answer on Stackoverflow
Solution 3 - asp.netNigel FindlaterView Answer on Stackoverflow
Solution 4 - asp.netAndrew VerigaView Answer on Stackoverflow
Solution 5 - asp.netLukLedView Answer on Stackoverflow
Solution 6 - asp.netVJAIView Answer on Stackoverflow
Solution 7 - asp.netdananView Answer on Stackoverflow
Solution 8 - asp.netashwath hegdeView Answer on Stackoverflow
Solution 9 - asp.netRick RiggsView Answer on Stackoverflow
Solution 10 - asp.netRaZor1994View Answer on Stackoverflow
Solution 11 - asp.netJesse MwangiView Answer on Stackoverflow
Solution 12 - asp.netSinji YangView Answer on Stackoverflow