Using IDictionary in controller method ASP.NET MVC 4/JSON - ajax

I'm attempting to post data using AJAX back to an ASP.NET MVC Controller with a viewModel like so:
public class FunkyThingUpdateModel
{
public int FunkyThing_ID{get;set;}
public string Name{get;set;}
public IDictionary SizesAvailable{ get; set;}
}
Unfortunately, I'm struggling to get the model binder to bind to the IDicationary.
If in the JSON passed to the controller the sizesAvailable is null then the controller method is called successfully. However if there is data in sizesAvailable then I'm getting an internal server error 500.
My JSON is formatted as follows:
{"FunkyThing_ID":1,"Name":"Pogo Stick","SizesAvailable":{"1":"Extra
Large","2":"Extra Tiddly"}}
What I'm not sure is - am I trying to do something impossible. Is there a way of binding to an IDictionary - if not what is the best alternative?
Or does my JSON just need to be formatted in a different fashion?
I found a number of similar questions on here, but most of them are quite old.
There seemed to be some indications that this was possible in MVC 4 which I'm using - but I could have been misunderstanding the context.

Not tested, But i think you have to specify Generic interface definition for the object to be created.
public IDictionary<int, string> SizesAvailable{ get; set;}
and also you have to change the data in ajax definition to notify SizesAvailable as array
$.ajax({
url:'your url',
type: 'post',
contentType : 'application/json',
data: JSON.stringify({FunkyThing_ID:1, Name:"Pogo Stick", SizesAvailable:[{key: 1, value:"Extra Large"},{key:2, value: "Extra Tiddly"}]}),
success: function(response){
console.log(response);
}
});
Edit
If your intention is to only get string array(not a dictionary) of sizes, change
public string[] SizesAvailable{ get; set;}
and send data as,
data: JSON.stringify({FunkyThing_ID:1, Name:"Pogo Stick", SizesAvailable:["Extra Large","Extra Tiddly"]}),
hope this helps.

Related

Send 2 or more Raw Body Parameters Post Request with Postman

I have an ASP.NET Core 2.0 API Method:
[HttpPost("api/days")]
GetDays([FromBody] DateTime startTime, [FromBody]DateTime endTime)
{
}
And I tried to send a Post request with Postman, but there is a problem, the parameters always have default values.
Here is my Post request looks like:
Result: Not Worked; Both parameters in API method get the default values.
If I change my API params to:
[HttpPost("api/days")]
GetDays([FromBody] Inputparam param)
{
}
public class Inputparam
{
public DateTime startTime { get; set; }
public DateTime endTime { get; set; }
}
That's worked perfectly!
But I wanna to send parameters directly and not inside wrapper object.
So, I came back with first API method and then I tried:
Result: Not Worked; Both parameters in API method get the default values.
And This one:
Result: Not Worked perfectly; Just first parameter (startTime) set it and second parameter still have default value.
And This one:
Result: Not Worked; Both parameters in API method get the default values.
I also tried [FromForm] instead of [FromBody] in API, nothings changed.
If I don't use [FromBody] in api and send the request via x-www-form-urlencoded that's worked perfectly.
But I need send a raw body with JSon.
How could I sent 2 different parameters as a raw body json?
Any idea?
Where is the problem?
I found that it's just one [FromBody] is allowed in API, and that makes sense. So probably the answer is: There is no way to have 2 or more parameters with [FromBody] attribute.
[FromUri] can do the Job.For your reference Microsoft Documentation
public class DateTimes
{
public datetime startdate { get; set; }
public datetime enddate { get; set; }
}
GetDays([FromBody] DateTimes _date)
{
//Controller action
}
URI:
api/values/?startdate=2018-06-01&endate=2018-07-01

When POST has Id in the URI - should Id also be in Body Model Parameters? Web API

I have a ViewModel used in a Web API web service.
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
Then I have an ApiController with a method like this:
[Route("api/Customer/{Id}")]
public IHttpActionResult Post(int Id, [FromBody]Customer Customer)
{
...Add to db, Id also exists in Customer
return Ok();
}
Customer Id is available in the URI - but the Customer object contains a Customer Id - which could be passed into the Post.
This seems to be redundant - and may lead to the Id being put in the wrong place.
What is best practice? If I need to remove Id from Customer body how do I do it?
Reference - "Using HTTP Verbs with the Task Resource" - level 2 in the REST Maturity Model - states the Id should be passed in the URI for updating or inserting tasks with an Id:
Generally we call a POST method when we try to create a new record, in your case "Customer" and PUT method to update an existing record. But that is not mandatory. You can create and update an existing record by using POST method too.
In general, we set auto generated field to the Id (primary key) field of a table. That means, we don't need to pass data for Id field when we try to add a record. In that case you don't need to pass Id in your URI and you don't need to write a parameter for Id in your API POST method.
So your ajax method will be like this bellow,
$.ajax({
url: 'myURL',
type: "json",
contentType: 'application/json; charset=utf-8',
data: myFormData,
success: function(data)
{
alert("success");
}
})
As I mentioned above you can use the same method (POST) for add a new record or edit an existing record, so how is that possible ?
I assume you are passing Id value in your ajax code in data parameter.
So your API Post method will be like this,
[Route("api/Customer")] // I removed Id here
public IHttpActionResult Post([FromBody]Customer Customer)
{
if(Customer!=null && Customer.Id==0) //You can check Id with null value
{
// Add a new record to Customer
}
else
{
// fetch Customer data by Customer.Id and update here
}
return Ok();
}
As simple as that. But yes, you can write this update code in a PUT method.
But if you are passing value to the Id field(that is not auto generated field) in POST method, then also you can remove the Id parameter from your POST method and your Route will be like this,
[Route("api/Customer")]
Hope it helps :)

ASP.NET WebAPI method with two parameters, one array

i'm new to WebAPI and had a few qeustion to custom method calling.
So, im working with Entity Framework and created a WebAPI with basic CRUD methods.
But now i want to add some custom methods, is it possible to call arrays as parameters? And when yes, how?
This is my method:
public void AddRoles(Guid userid, Guid[] roleids)
So how it is possible to call this method through webapi?
I tryed it with
http://localhost:60690/api/MyController/AddRoles...
And is it possible to call void method? What is the response?
thanks and greetings,
Joerg
http://localhost:60690/api/MyController/AddRoles?userid=<user id guid here>&roleids=<guid1 here>&roleids=<guid2 here>...
As for the void method, of course it is possible, response will be with 200 code and empty body.
For GET you can refer to the following SO question:
How to pass an array of integers to ASP.NET Web API?
If you want to try to use POST then continue to read:
You should create a DTO for your parameters like such:
public class AddRoleModel
{
Guid UserId { get; set; }
Guid[] RoleIds { get; set; }
}
Change your method to accept accept POST and your new AddRoleModel DTO instead of the two different parameters like so:
[HttpPost]
public void AddRoles(AddRoleModel model)
{
...
}
And POST the json for that model to the method
json could look like this:
{
UserId: "{guid}",
RoleIds: ["{some guid}", "{some other guid}"]
}

ASP.NET Web API with Decorations on Models

Technology Used: Code First,ASP.NET Web API (restful service) and HTML.
For code first I have a domain Object called User
public class User
{
[Required]
public Guid Id { get; set; }
[Required]
public string Email { get; set; }
[Required]
public byte[] PasswordHash { get; set; }
public bool IsDeleted { get; set; }
}
And I have decorated the properties with [Required].
Then I have my MVC Web Api Post Method
public string Post(Domain.User regModel)
{
return "saved";
}
and lastly I have my Ajax Call
var user = {
Id: "1",
Email: "test#test.com",
PasswordHash: "asjdlfkjals;dkjflkjsaldfjsdlkjfiovdfpoifjdsiojfoisj",
IsDeleted: true
};
$.ajax({
type: 'POST',
url: '/api/registration/post',
cache: false,
data: JSON.stringify(user),
crossDomain: true,
contentType: "application/json;charset=utf-8",
success: function (data) {
console.log(data);
}
});
Error As Requested
POST http://localhost.com:11001/api/registration/post 500 (Internal Server Error)
<Error>
<script/>
<Message>
The requested resource does not support http method 'GET'.
</Message>
</Error>
My Problem
If I decorate my Model with [Required] I get an Error 500 - No Get Method Supported
however if I remove that. Everything works well.
I just really want to understand why this is the case with MVC Web API. sure I can create view models but. I just want to understand why this is happening.
Can someone please explain
Thanks
I seem to have found a reason why abit late as I already changed from a web api to a standard MVC. (which works perfectly no work around to be done) you can find the answer in the following links:
asp net web api validation with data annotations
web api nullable required property requires datamember attribute
dataannotation for required property
Thank you all for your help
Could the problem actually be that you are trying to Post a user with Id = "1" while Domain.User specifies that Id is of type Guid. A "1" does not make a valid Guid, so when that property is marked with Required it can't make the call to your Post method. When you remove the required attribute, the Post method can be used/called, because it will just set the Id of the User object to Null or an empty Guid, as it is not required.

Is there any way to pass a whole model via html.actionlink in ASP.NET MVC 3?

How do I pass a whole model via html.actionlink or using any other method except form submission? Is there any way or tips for it?
Though it's not advisable in complex cases, you can still do that!
public class QueryViewModel
{
public string Search { get; set; }
public string Category { get; set; }
public int Page { get; set; }
}
// just for testing
#{
var queryViewModel = new QueryViewModel
{
Search = "routing",
Category = "mvc",
Page = 23
};
}
#Html.ActionLink("Looking for something", "SearchAction", "SearchController"
queryViewModel, null);
This will generate an action link with href like this,
/SearchController/SearchAction?Search=routing&Category=mvc&Page=23
Here will be your action,
public ViewResult SearchAction(QueryViewModel query)
{
...
}
No, you cannot pass entire complex objects with links or forms. You have a couple of possible approaches that you could take:
Include each individual property of the object as query string parameters (or input fields if you are using a form) so that the default model binder is able to reconstruct the object back in the controller action
Pass only an id as query string parameter (or input field if you are using a form) and have the controller action use this id to retrieve the actual object from some data store
Use session
You could use javascript to detect a click on the link, serialize the form (or whatever data you want to pass) and append it to your request parameters. This should achieve what you're looking to achieve...

Resources