8

I need to build an API using ASP.NET Web API (version 4.5.2). To get started, I'm just trying to create a basic endpoint that adds some numbers. In an attempt to do this, I've created:

[RoutePrefix("api/test")]
public class MyController : ApiController
{
 [HttpGet]
 public IEnumerable<int> Calulate(decimal[] op1, decimal[] op2)
 {
 var results = new List<Calculation>();
 for (var i=0; i<op1.Length; i++) 
 {
 var calculation = new Calculation();
 calculation.Operand1 = op1[i];
 calculation.Operand2 = op2[i];
 calculation.Calculate();
 results.Add(calculation);
 }
 return results;
 }
 public class Calculation
 {
 public int Operand1 { get; set; }
 public int Operand2 { get; set; }
 public int Result { get; set; }
 public void Calculate()
 {
 this.Result = this.Operand1 + this.Operand2;
 }
 }
}

I am now trying to hit this endpoint via the Postman Chrome app. When I run it via Postman, I'm getting an error. Here is what I'm doing:

In Postman, I've put "http://localhost:50668/api/test/calculate" in the URL field next to the "GET" drop down. I then click "Send". I'm receiving the following error:

{
 "Message": "An error has occurred.",
 "ExceptionMessage": "Can't bind multiple parameters ('op1' and 'op2') to the request's content.",
 "ExceptionType": "System.InvalidOperationException",
 "StackTrace": "..."
} 

I think (I don't know) the cause is because I'm not passing the values to the API from Postman correctly. However, I'm not sure how to do that. How do I pass an array of values to an API?

asked Dec 16, 2015 at 14:15

3 Answers 3

14

Short answer

To send arrays of decimals, WebApi expects url signature like: GET http://localhost:50668/api/test/calculate?Operand1=1.0&Operand1=2.0&Operand2=3.0&Operand2=4.0

That url will send [1.0,2.0] as Operand1 and [3.0,4.0] as Operand2.

Long answer

By calling your api using GET http://localhost:50668/api/test/calculate, you actually send nothing to your server. (aside of headers content)

If you want to send data to your server, you have (at least) 2 options:

Option 2: Use GET method if operation is idempotent Like William Xifaras already pointed out, specify that your inputs will come from the URL so WebApi interprets properly. To do so, use [FromUri].

 [HttpGet]
 [Route("calculate")]
 public List<Calculation> CalculateWithGet([FromUri]decimal[] Operand1, [FromUri]decimal[] Operand2)
 {
 var results = new List<Calculation>();
 for (var i = 0; i < Operand1.Length; i++)
 {
 var calculation = new Calculation();
 calculation.Operand1 = Operand1[i];
 calculation.Operand2 = Operand2[i];
 calculation.Calculate();
 results.Add(calculation);
 }
 return results;
 }
 public class Calculation
 {
 public decimal Operand1 { get; set; }
 public decimal Operand2 { get; set; }
 public decimal Result { get; set; }
 public void Calculate()
 {
 Result = this.Operand1 + this.Operand2;
 }
 }

With a REST client, it should look like: Query using GET method

With GET, data is sent via the URL

Note that if you use GET Method, the server will expect to receive inputs from the URL. You should therefore send queries like: GET http://localhost:50668/api/test/calculate?op1=1.0&op1=2.0&op2=3.0&op2=4.0

Use POST method if operation is not idempotent

Since the operation does some server side calculation, I pretend it may not always be idempotent. If it is the case, POST might be more appropriate.

 [HttpPost]
 [Route("calculate")]
 public List<Calculation> CalculateWithPost(CalculationInputs inputs)
 {
 var results = new List<Calculation>();
 for (var i = 0; i < inputs.Operand2.Length; i++)
 {
 var calculation = new Calculation();
 calculation.Operand1 = inputs.Operand1[i];
 calculation.Operand2 = inputs.Operand2[i];
 calculation.Calculate();
 results.Add(calculation);
 }
 return results;
 }
 public class CalculationInputs
 {
 public decimal[] Operand1 { get; set; }
 public decimal[] Operand2 { get; set; }
 }
 public class Calculation
 {
 public decimal Operand1 { get; set; }
 public decimal Operand2 { get; set; }
 public decimal Result { get; set; }
 public void Calculate()
 {
 Result = this.Operand1 + this.Operand2;
 }
 }

With POST, data is sent via the body

With that structure, the server expects to receive inputs from the request body. WebApi will deserialize the body if it matches the signature of your function.

With a REST client, it should look like: Query using POST method

Sidenote

The nuget package used to get the SwaggerUI generated (printscreens) can be find here. Very useful to run adhoc tests on WebApis.

answered Dec 16, 2015 at 15:23

Comments

4

Add from [FromUri] before the parameter.

public IEnumerable<int> Calulate([FromUri] decimal[] op1, [FromUri] decimal[] op2)

To force Web API to read a complex type from the URI, add the [FromUri] attribute to the parameter

http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

answered Dec 16, 2015 at 15:01

Comments

1

I think you can pass as a JSON array

http://localhost:50668/api/test/calculate?op1=[1,2,3]&op2=[4,5,6]

Hope this helps

answered Dec 16, 2015 at 14:20

1 Comment

Oh - sorry abiout that....Well - seeing as this is your first test, maybe start with simple ints... eg public int Calulate(int op1, int op2) localhost:50668/api/test/calculate?op1=6&op2=7 ...and see how you get on with taht and then expand little by little. I have an API that takes in an object, which contains a list of Ids and what I said works for me. That said, it's pretty new to me too......so from experience I'd say start simple and work up..

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.