This question can be very easy for you but I cannot find the solution anywhere, I've searched on SO as well. How can I send a collection of objects inside an object to a C# API method, here is my code that I try to send
{
"Question":"sdvsdv",
"PollQuestions":
[
{
"QuestionText":"Question Text"
}
]
}
I've tried with Advanced REST client as well (not only from JS), I can see value of parent object's parameters but PollQuestions objects parameters are all empty.
Please suggest a work around. Its been couple of days and I cannot get through it. Thanks in advance.
EDIT:
Here is how API method looks like:
Advanced Rest client request:
JS request:
Poll is a simple class like this:
[Serializable]
[DataContract(Namespace = "")]
public class Poll
{
[DataMember]
public string Question
{
get;
set;
}
[DataMember]
public Collection<PollQuestion> PollQuestions { get; set; }
}
PollQuestion object:
[Serializable]
public class PollQuestion : AnotherClass
{
public string QuestionText
{
get;
set;
}
}
In your case if the problem is to Map the request JSON in C# then try below code:
Class structure:
public class PollQuestion
{
public string QuestionText { get; set; }
}
public class RootObject
{
public string Question { get; set; }
public List<PollQuestion> PollQuestions { get; set; }
}
In Post use [FromBody] attribute to map JSON to C# class:
public void YourMethod([FromBody] RootObject data)
{
// your code to use request data
}
If you are using WebAPI version="5.2.3" (Or might be supported in the lower version also) no need to serialize requested JSON to C# class. Use this to generate C# classes for JSON.
For JSON structure C# treats,
this:
{
}
as Object and
this:
[]
to List<> OR Array.
I set up a simple sample project in .NET Core and it seems to be working fine for me with your JSON data.
These are the classes I used:
public class PollQuestion
{
public string QuestionText { get; set; }
}
public class Poll
{
public string Question { get; set; }
public List<PollQuestion> PollQuestions { get; set; }
}
And here is the API call function:
[HttpPost]
public void Post([FromBody]Poll value)
{
}
When I make a postman request the Poll class is filled as expected.
Here is also a link to my sample project: https://bitbucket.org/alleskapaul/ld42/downloads/JsonExample.zip
Could you change your models in your project to match mine and see if that works? My guess would be that your model is incorrect as the JSON request works for me as well. If it is not working could you upload a sample project so I can see if I can modify it to work?
I was inheriting a class that was using [DataContract] and [DataMember] attributes, so I had to use DataMember for all parameters of the child class as well.
Thanks everyone for your answers but [FromBody] is not required in an API method when parameter is of complex type.
It works without DataContract and DataMember as well if you have not used DataMember anywhere in the class and also not inheriting any class that uses it.
You can get more info here: When to use DataContract and DataMember attributes?
Related
I'm implementing the "Save Draft" functionality on my dynamically generated page and trying to make it as generic as possible. All my controllers and pages should support it and that's why I thought about creating a SaveDraft() POST action in my base controller which will receive a serialized form as a string which can be directly saved into the database and deserialized to a view model later in the specific get action using specific view model
[HttpPost]
public ActionResult SaveDraft(string jsonData, long id)
My first idea was to create the generic base controller and pass the view model type to it but the problem is that some controllers have multiple differently named POST actions and using different view model types, I cant change it now.
Some view models are complex and looking like
public class CollateralsDataModel
{
//...
public List<Applicant> Applicants { get; set; }
}
public class Applicant
{
public long ApplicantId { get; set; }
public IList<RealEstateSecurityCollateralsDTO> RealEstateSecurityCollaterals { get; set; }
public IList<AdditionalCollateralDTO> AdditionalCollaterals { get; set; }
}
public class RealEstateSecurityCollateralsDTO
{
[Required]
[Display(ResourceType = typeof(CollateralsData), Name = nameof(CollateralsData.RealEstateSecurityType))]
public int? RealEstateSecurityTypeId { get; set; }
//...
}
The input names on the form are looking like
"Applicants[0].MortgageApplicantId": "11595",
"Applicants[0].RealEstateSecurityCollaterals[0].Id": "17",
"Applicants[1].MortgageApplicantId": "11596",
"Applicants[1].RealEstateSecurityCollaterals.Index": "0",
"Applicants[1].AdditionalCollaterals[0].Id": "138",
"Applicants[1].AdditionalCollaterals[0].AdditionalCollateralTypeId": "4",
My question is - how can I serialize them to the string so I can deserialize it later?
I tried using different combinations of
$('.draft-data-form').serializeArray()
$('.draft-data-form').serialize()
JSON.stringify($('.draft-data-form').serializeArray());
but in my Action I get the flat JSON structure and I can't deserialize it
var obj = JsonConvert.DeserializeObject<CollateralsDataModel>(jsonData);
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type '...CollateralsDataModel' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
I've also tried to deserialize it as a list but then I get the List of 115 entries
var obj = JsonConvert.DeserializeObject<List<CollateralsDataModel>>(jsonData);
So my question is - how can I serialize them to the string so I can deserialize it later?
You do not want to serialize/deserialize a List. Only a single instance of the model.
I would guess that the error is in instantiating the list within the model. I know that the DataContractSerializer has an issue where if the List is not instantiated to an empty list when the model is constructed then the deserialization is unable to add to it.
Not sure if this is the same problem you are facing but could be worth a try.
eg. use:
public List<Applicant> Applicants { get; set; } = new List<Applicant>();
I have a class like this:
public class MyData
{
public int Id { get; set; }
public String Name { get; set; }
public ThirdPartyClass { get; set; } // non serializable
}
I said "non-serializable" because when I pass my class to a SignalR client function in this way:
var hub = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
var myData = new MyData();
// fill fields
hub.Clients.All.data(myData);
the call return error 500.
Removing the offending field it work as expected.
Please, note I'm not interested to pass to the client that field.
Right now I know two ways to solve this:
write a custom json serializer
create a shadow class with only the relevant fields, copy the values, and send this class to the clients
Both are uncomfortable when you have dozen of fields.
I'm wondering if there's some DataAnnotation I might use to exclude a field from serialization.
You can use IgnoreDataMemberAttribute() but I'm not sure if that would work with SignalR.
Your alternative if that doesn't work is the JsonIgnore annotation.
Lastly, there is also ScriptIgnore.
IgnoreDataMember Class Reference
I tried using
var myobject = JsonConvert.SerializeObject(Customer);
but problem is in Customer properties are like
FirstName and my service expecting json input like firstName
{"firstName":"Neo"}
statement JsonConvert.SerializeObject(Customer); gives me {"FirstName":"Neo"} which is wrong.
So How can I change first letter when JsonConvert.SerializeObject happened ?
Or How to take only one parameter as input json firstname instead if using Customer object.
You should use the Json.NET attribute support to customize the naming:
public class Customer
{
[JsonProperty("firstName")]
public string FirstName { get; set; }
}
You can define how data need to be serialized.
When using webapi, we can define a CamelCasePropertyNamesContractResolver (part of json.net library) as formatter in the register method of the webapi config.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
The code above is especially for webapi, nevertheless I believe a simular approach can be a solution when not using webapi.
You can use like this. Use DataMember property, it'll serailize as mentioned.
[DataContract(Namespace = "")]
public class Customer
{
[DataMember(Name = "firstName")]
public string FirstName { get; set; }
}
I'm trying make a jquery.ajax call to the following controller action:
public ActionResult Handler(SemanticPart[] semanticParts, string first, string last)
I have the following data JSON object with the corresponding server side model having public { get; set; } properties:
var data = {
semanticParts: [{ hasLabel: "label", hasType: "type", hasIndex : 0 }],
first: "first",
last : "last"
};
The problem is jQuery.param seems to have no serialization option for the default MVC model binder.
decodeURIComponent($.param(data)) produces:
"semanticParts[0][hasLabel]=label&semanticParts[0][hasType]=type&semanticParts[0][hasIndex]=0&first=first&last=last"
while setting the traditional flag like so decodeURIComponent($.param(data, true)) produces:
"semanticParts=[object+Object]&first=first&last=last"
MVC's default model binder for complex arrays needs the following to bind correctly (tested in Fiddler Composer):
"semanticParts[0].hasLabel=label&semanticParts[0].hasType=type&semanticParts[0].hasIndex=0&first=first&last=last"
Which simply used: array[0].property= instead of array[0][property]=
I understand there's no universal specification for param strings agreed-upon by all web frameworks but why jQuery.param with traditional flag set true returns a [object+Object] is beyond me... that is absolutely useless in any framework.
It there any way to patch this?
Perhaps a regex to replace the pattern [#][text] with [#].text? (actually the encoded version of this is more relevant)
You should implement a model to hold this parameters:
public class SemanticPartViewModel
{
public List<SemanticPart> semanticParts { get; set;}
public string first { get; set; }
public string last { get; set;}
}
And change the controller to receive this as parameter
public ActionResult Handler(SemanticPartViewModel semanticParts)
{
/*Do stuff*/
}
You should use JSON.stringify(mydata) as well to create the data for the $.ajax call
This way the default modelbinder will take care about the rest.
I m using ASP.Net MVC 3.0. My model has a list of telephone. I want to preserve that in some way, so that I can manipulate & display later using Jquery in my script.
I tried saving the list in a hidden field, but I am not able to retrieve that in my JavaScript.
Please help me finding a way out. Thx in advance.
You could create a property on your viewmodel which holds a json serialized version of the phonenumbers like this:
public class Person
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public IList<string> PhoneNumbers { get; set; }
public IHtmlString SerializedPhoneNumbers
{
get { return MvcHtmlString.Create(new JavaScriptSerializer().Serialize(PhoneNumbers)); }
}
}
You can use that in the view like:
<script type="text/javascript">
var phoneNumbers = #Model.SerializedPhoneNumbers
</script>
You now can manipulate the collection in your clientside script.