Passing muliple parameters in get method of web api - asp.net-web-api

I have web api get method with following parameters
public DataSet Get([FromUri] EloQuaParameters paramss)
{
Hive9Common obj = new Hive9Common();
obj.credentials = paramss.credentials;
obj.fromDate = paramss.fromDate;
obj.toDate = paramss.toDate;
obj.fieldMap = paramss.fieldMap;
//Credential & fieldmap always remain null
}
EloquaParameters is class as below:
public class EloQuaParameters
{
public Dictionary<string, string> credentials { get; set; }
public DateTime? fromDate { get; set; }
public DateTime? toDate { get; set; }
public Dictionary<string, string> fieldMap { get; set; }
}
I am calling this method from my application as below:
HttpClient client;
string url = "http://localhost:54371/api/values/Get?credentials=" + credentialDictionary + "&fromDate=" + fromDate + "&toDate=" + toDate + "&fieldMap=" + fieldmpa;
client = new HttpClient();
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
HttpResponseMessage responseMessage = await client.GetAsync(url);
if (responseMessage.IsSuccessStatusCode)
{
var responseData = responseMessage.Content.ReadAsStringAsync().Result;
}
In webApi method fromdate & todate parameter is receive proper value but both dictionary parameter is always remain null. how I can able to get values of that dictionary parameters.?
Please help

You really can't. A dictionary is not designed to be passed in a url. Think about what would happen if you had a large number of items in the dictionary.
You should really use a POST for this method for several reasons:
First, it will provide a way to specify your parameters in a single object, which can have its advantages. Second, sending the parameters in a POST places those parameters in the body of the request, which will allow them to be sent over HTTPS, which you should really use anyway because you are passing credentials. These days, there is no reason to NOT use HTTPS for everything.
It would really be a trivial change to send the parameters as a POST.
Hope that helps.

Related

WebApi - Passing an Array of Values

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?
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:
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:
Sidenote
The nuget package used to get the SwaggerUI generated (printscreens) can be find here. Very useful to run adhoc tests on WebApis.
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
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

WebAPI2 Model Binding not working with HTTP PUT

I'm following Scott Allen's MVC4 course on PluralSight (I'm using MVC5 and WebAPI2 but they should be the same) and I am trying to pass an object via HTTP PUT. The model binder should bind it, but I am getting NULL for the parameter.
public HttpResponseMessage PutObjective(int id, [FromBody] Objective objective)
{
if (ModelState.IsValid && id == objective.ObjectiveID)
{
//todo: update - look up id, replace text
return Request.CreateResponse(HttpStatusCode.OK, objective);
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
and in my front-end javascript I am doing the following (I'm creating an object for testing, so ignore 'objective' passed in):
var updateObjective = function (objective) {
var myobj = { "ObjectiveID": "3", "ObjectiveDescription": "test" };
return $.ajax(objectiveApiUrl + "/" + objective.ObjectiveID, {
type: "PUT",
data: myobj
});
}
My class looks like this:
public class Objective
{
public int ObjectiveID { get; private set; }
public string ObjectiveDescription { get; set; }
public Objective (int Id, string Desc)
{
this.ObjectiveID = Id;
this.ObjectiveDescription = Desc;
}
}
Any thoughts on why 'objective' in the backend is always 'null' ?
I've done what Scott Allen is doing, even tried adding in [FromBody] but no luck. $.ajax should have the correct content type by default I understand, so no need to set it.
I had Fiddler2 but I'm unsure as to what I am looking at to be honest. I can see my object as JSON being sent to the backend.
Well, if you're familiar with Model Binding you'll have seen the issue in my Objective class:
public int ObjectiveID { get; private set; }
with a private set, no instance can be created of the Objective class. To make it work, the 'private' access specifier needs to be removed.
What needs to happen really is that Objective becomes ObjectiveViewModel, and we convert what comes back to an Objective domain object (which may have more properties than we need for this screen). This can have a private set.

Post Binary array to Web API Controller

I am trying to POST form data which consists of few string variable and binary array.
Below is the Model for the form data.
public class FileModel
{
public string Path { get; set; }
public byte[] File { get; set; }
}
Below is my Web API Controller.
[Route("")]
public IHttpActionResult Post([FromBody]FileModel media)
{
// Can I use ??
byte[] requestFile = media.File;
string requestFilePath = media.Path;
//Process the above variables
return Ok();
}
I would like to know Can I use the following code to de-serialize the following code snippet to to read the values from the JSON payload including the binary data?
byte[] requestFile = media.File;
string requestFilePath = media.Path;
If Yes, Do I need to define any formatter class to get it working?
I normally use POSTMAN to test my RESTful endpoints.
Is it possible to use POSTMAN still to POST binary array? May be not need to write my own client
You'll need to use a serializer to serialize complex objects (multiple fields) as content for a Http Request.
For your code snippet to read the object from the content you can use this:
var requestContent = Request.Content.ReadAsAsync<FileModel>(GetJsonSerializer()).Result;
Here's the serializer boilerplate code.
private JsonMediaTypeFormatter GetJsonSerializer()
{
JsonSerializerSettings settings = new JsonSerializerSettings()
{
PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All,
TypeNameHandling = Newtonsoft.Json.TypeNameHandling.All
};
return new JsonMediaTypeFormatter() { SerializerSettings = settings };
}
I'm not sure how to use POSTMAN to test this. A simple .net client would be:
var Client = new HttpClient();
Client.BaseAddress = new Uri("localhost"); //whatever your endpoint is
FileModel objectToSend = new FileModel();
var objectContent = new ObjectContent<FileModel>(objectToSend, GetJsonSerializer() );
var response = Client.PostAsync("uri", objectContent);
You are able to use POSTMAN to test binary file input. Selecting the body tab, you can then pick the radio button "binary" and then choose file.

Parse.com > Query Constraints > based on user Pointer

I have a class called AccountData and I would like to return all rows that relate to a particular user. In the class I have a Pointer to the User table which contains their "ObjectId"
I have tried with the following call to the API:
string url = "https://api.parse.com/1/classes/AccountData?" + WebUtility.UrlEncode("where={\"user\":\"fvJ8jPjyjx\"}");
where the fvJ8jPjyjx is the ObjectId of the user I want rows relating to...
The api doesn't throw any errors just returns:
{"results":[]}
I have also tried it using a "User Object" as follows:
public class AccountDataUser
{
public string __type { get; set; }
public string className { get; set; }
public string objectId { get; set; }
}
building the object as follows:
AccountDataUser user = new AccountDataUser();
user.__type = "Pointer";
user.className = "_User";
user.objectId = objectId;
string jsonUser = JsonConvert.SerializeObject(user);
but this throws an api error.
Can anyone help me return the rows relating to a "user" please?
Thanks
UPDATE
Based on Ryans feedback I have reverted to trying to send an object...
This is what is being sent:
GET https://api.parse.com/1/classes/AccountData?where%3D%7B%22user%22%3A%22%7B%22__type%22%3A%22Pointer%22%2C%22className%22%3A%22_User%22%2C%22objectId%22%3A%22fvJ8jPjyjx%22%7D%22%7D HTTP/1.1
Content-Type: application/json
X-Parse-Application-Id: xxxxx
X-Parse-REST-API-Key: xxxxxx
Host: api.parse.com
Connection: Keep-Alive
The url is built with this line of code:
ParseModel.AccountDataUser user = new ParseModel.AccountDataUser();
user.__type = "Pointer";
user.className = "_User";
user.objectId = objectId;
string jsonUser = JsonConvert.SerializeObject(user);
string url = "https://api.parse.com/1/classes/AccountData?" + WebUtility.UrlEncode("where={\"user\":\"" + jsonUser + "\"}"); // this doesn't work
And the error I receive from the API is:
{"code":107,"error":"invalid json: {\"user\":\"{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"fvJ8jPjyjx\"}\"}"}
I believe the issue is in building the URL. You're wrapping the JSON in a string and Parse is expecting an object. If you strip the double quote around jsonUser, I bet that'll work.
string url = "https://api.parse.com/1/classes/AccountData?" + WebUtility.UrlEncode("where={\"user\":" + jsonUser + "}");

ASP.NET MVC 3 Parse JSon object and display data

I have a class
public class ConversionResultModel
{
public string ProcessId { get; set; }
public bool Result { get; set; }
public string Message { get; set; }
}
sending it to view using JSon
public ActionResult UploadFile(IEnumerable<HttpPostedFileBase> clientUpload)
{
string destinationPath = "";
JsonResult result = null;
var fileModel = new ConversionResultModel();
fileModel.ProcessId = "4558-95559-554";
fileModel.Result = true;
fileModel.Message = "test.pdf";
result = Json(new { fileModel }, "text/plain");
return result;
}
How to parse such JSon object at client side using JS or jQuery and read values?
I have tried to parse JSon object with code below but get Undefined error in alert
var obj = $.parseJSON(e.response);
alert(e.obj);
I receive JSon object like this
{"fileModel":{"ProcessId":"4558-95559-554","Result":true,"Message":null,"SourceFile":null,"ConvertedFileName":"test.pdf","ConvertedFileSize":1233444,"DownloadUrl":"http://localhost:2008/download?path=4558-95559-554","DeleteUrl":"http://localhost:2008/download?path=4558-95559-554"}}
You do not need to parse it. Just set data type to JSON during ajax request and then use received data object like entity and you easily can access to any property:
var id = data.ProcessId;
Anyway, using jQuery you can parse JSON string:
var data = jQuery.parseJSON(stringData);
P.S:
Use the following code sample for converting object to JSON in ASP.NET MVC:
return this.Json(fileModel);
http://api.jquery.com/jQuery.parseJSON/
In your case, I think you're getting back the correct JSON, but your alert is looking at the wrong object. Try alert(obj.SomeProperty) rather than alert(e.obj). e.obj doesn't exist, which is likely why you're getting an "undefined" error. For example, alert(obj.fileModel.ProcessId); should work.

Resources