I've tried several different string formats and json serializer settings but can not come up with the right combination; my date always comes out as the default min date value.
I'm doing:
_flashMessage = JsonConvert.DeserializeObject<FlashMessage>(msoSite.FlashMessage, settings);
Where FlashMessage is:
public class FlashMessage
{
public string Device { get; set; }
DateTime Expires { get; set; }
public List<string> Message { get; set; }
}
And my Json string is:
{
"Device": "Mobile",
"Expires": "2015-03-13T11:35:35",
"Message": [
"This is a test message..."
]
}
The date result I'm getting is:
The answer is: my DateTime Expires property wasn't defined as public, therefore out of scope and not getting set.
Related
I have applications with a simple [HttpPost] method in controller that should accept an object from the query body (query from postman).
However, I have an error every time because null comes to the method - not object.
Model:
public class MeetupDto
{
public string Name { get; set; }
public string Organizer { get; set; }
public DateTime Date { get; set; }
public bool IsPrivate { get; set; }
}
Method:
[HttpPost]
public ActionResult Post([FromBody]MeetupDto model)
{
...
}
The method works fine when I shrink the model down to the name and organizer only. When there's a date or a bool, it doesn't work.
Postman (body raw+json):
https://localhost:44398/api/meetup/
"name": "JsEvent",
"organizer": "chrome",
"date": "2020-07-26 15:20:00",
"isPrivate": "false"
You have two problems:
You're sending a string for IsPrivate, when it's expecting a bool
You're not using the correct date format
Change your JSON to this:
// Note the 'T' in the date
{
"name": "JsEvent",
"organizer": "chrome",
"date": "2020-07-26T15:20:00",
"isPrivate": false
}
and it should bind your model correctly.
I have pretty much the same question as this one:
Get Raw json string in Newtonsoft.Json Library
but now using the Text.Json.Serialization in .NET Core 3.1, I struggle to find the equivalent of JRaw.
I want to have an extensible object like:
{
"id": "myId",
"name": "name",
"description": "my description",
"extensions": {
"unit": "C°",
"minVal": "0",
"maxVal": "100",
"precision": "1",
"enum": ["str1", "str2"],
...
}
}
I want to get the Id, Name and Description set in an object, but the extensions is a bunch of properties which can be whatever. So I want to keep the RAW Json for this extensions.
public class MyData
{
public string id { get; set; }
public string name { get; set; }
public string description { get; set; }
[JsonConverter(typeof(RawJsonStringConverter))]
public string extensions { get; set; }
}
I am fighting with a custom converter as documented here:
https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to
I tried with string, JsonElement, object.
No success so far.
Any idea?
Using JsonElement seems to be enough, without any custom converter:
public class MyData
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public JsonElement? Extensions { get; set; }
}
edit: JsonElement? as nullable is better: it allows JsonElement to be fully optional, if you have the corresponding settings in JsonSerializerOptions.
I am working with the following JsonSerializerOptions:
public static JsonSerializerOptions UpdateJsonSerializerOptions(this JsonSerializerOptions options, bool enumAsString = true)
{
if (options == null)
options = new JsonSerializerOptions();
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.IgnoreNullValues = true;
options.WriteIndented = true;
if (enumAsString)
{
// convert enums as strings
options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
}
return options;
}
IgnoreNullValues is the important part to have the proper conversion when no extensions at all in the input.
And CamelCase allows to stay with .NET property names (e.g 'Name') while the JSON will be with 'name'
I have a JSON response like the following
{
"msg": "1",
"code": "2",
"data": [
{
"a": "3",
"b": "4"
}
],
"ts": "5"
}
I would like to create a generic class
public class DTWSResponse<T>
{
public string msg { get; set; }
public string code { get; set; }
public T data { get; set; }
public long ts { get; set; }
}
so this class will map each of the variable. But the data portion can be generic, i.e. it might have different format rather than 2 variables a and b.
So I create another class
public class DTProf
{
public string a { get; set; }
public string b { get; set; }
}
and in my code, I call as
DTWSResponse<DTProf> prof = JsonConvert.DeserializeObject<DTWSResponse<DTProf>>(json);
But I'm getting the following error
An exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll but was not handled in user code
Additional information: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'DataTransfer.DTProfile' 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<T> 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.
Path 'data', line 1, position 40.
Any ideas?
Use the correct type for the generic type argument
the JSON shown has a collection for the data property. So use a collection as the type argument. No need to change the generic class.
var prof = JsonConvert.DeserializeObject<DTWSResponse<IList<DTProf>>>(json);
var a = prof.data[0].a;
Make data a generic list and you should be fine...
public class DTWSResponse<T>
{
public string msg { get; set; }
public string code { get; set; }
public IList<T> data { get; set; }
public long ts { get; set; }
}
Ok there are a lot of questions and answers with this, if you know an exact duplicate of this please point me there but I am too dumb to understand how to make it work.
I want to add a worker to a job and everything is good until reaches ModelState. Here are the steps I am doing.
Filling the form
I submit the form and console breakpoint.
Name = "test", Description = "test",
worker = {Id: 21, FirstName: "Will", LastName: "Smith", Job: null}
Angular service in console
jobs = {Name: "test", Description: "test", worker: {…}}
Not sure why the dots in the brackets.
Reaches API method and fails modelstate.
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
In browser console I get:
Message:"The request is invalid."
ModelState:job.worker.Id:["Cannot deserialize the current JSON object (e.g. {…N object. Path 'worker.Id', line 1, position 16."]
Full error message from ModelState is:
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type
'System.Collections.Generic.ICollection`1[TestRotaru.Models.Worker]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly. To fix this error either change the JSON to a JSON array
(e.g. [1,2,3]) or change the deserialized type so that it is a normal
.NET type (e.g. not a primitive type like integer, not a collection
type like an array or List) that can be deserialized from a JSON
object. JsonObjectAttribute can also be added to the type to force it
to deserialize from a JSON object. Path 'worker.Id', line 1, position
51.
Alright so far this is like a duplicate question but I tried few things and I don't understand some things in answers.
I tried to decorate my models with attributes such as:
These on top of the class
//[Serializable]
//[DataContract(IsReference = true)]
//[JsonObject(MemberSerialization.OptIn)]
On properties
//[JsonProperty]
Now the thing I have no clue and I don't understand:
var dict = JsonConvert.DeserializeObject
<Dictionary<string, Item>>(*Where this string comes from*);
This is just an example, I am concerned about that string in brackets not about if is a Dictionary or something else.
Here is my method:
[ResponseType(typeof(Job))]
public IHttpActionResult PostJob(Job job)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
job.DueDate = DateTime.Now;
db.Job.Add(job);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = job.Id }, job);
}
In all the answers about this everyone has that random json string in the round brackets... From where I am supposed to have that?
Here are my models:
Job Model:
//[Serializable]
//[DataContract(IsReference = true)]
//[Serializable()]
//[JsonObject(MemberSerialization.OptIn)]
public class Job
{
[JsonProperty]
public int Id { get; set; }
[JsonProperty]
public string Name { get; set; }
[JsonProperty]
public string Description { get; set; }
[JsonProperty]
public DateTime DueDate { get; set; }
[JsonProperty]
public bool IsCompleted { get; set; }
//[JsonProperty]
//[System.Runtime.Serialization.IgnoreDataMember]
public virtual ICollection<Worker> Worker { get; set; }
}
Worker Model:
//[Serializable]
//[DataContract(IsReference = true)]
//[JsonObject(MemberSerialization.OptIn)]
public class Worker
{
[JsonProperty]
public int Id { get; set; }
[JsonProperty]
public string FirstName { get; set; }
[JsonProperty]
public string LastName { get; set; }
//[JsonProperty]
//[System.Runtime.Serialization.IgnoreDataMember]
public virtual ICollection<Job> Job { get; set; }
}
Angular component and service:
add(Name: string, Description: string, worker): void {
this.jobsServices.addJob({Name, Description, worker } as Jobs)
.subscribe(jobs => {
this.jobs.push(jobs);
});
}
addJob(jobs: Jobs): Observable<Jobs> {
return this.http.post<Jobs>(this.apiURL, jobs, httpOptions);
}
div class="row">
<div class="col-md-12">
<label class="labelInputs">Select Worker</label><br>
<select [(ngModel)]="worker" class="form-control">
<option [value]="0">Select Worker</option>
<option *ngFor="let worker of workers" [ngValue]="worker">{{worker.FirstName}} {{worker.LastName}}</option>
</select>
</div>
<button class="brn btn-lg btn-block btn-change" (click)="add(name.value, desc.value, worker)">Add Job</button>
Alright is a long question but I wanted to prove myself I did my research and I just didn't thrown the error message and ask for solutions but this is really getting on my nerves.
Since I am posting relational data and my console shows ModelState{job.worker.Id: [,…]} how do I deserialize this? Plus my ModelState shows the worker as null when reaches the API, I can guess because is not converted from json, but worth to know.
Thank you for help.
So, the issue is that on your SPA you are sending worker as a single object and your API expects a list (array) of workers. Now I don't know what you want.. but you can either fix it by changing your API model to expect a single worker or change your SPA to send a list of workers. That no one can answer you.. depends on your app's requirements. But, my best guess is that a Job might have several workers. So:
Api Models (mostly the same.. just removed the attributes and changed Worker to Workers):
public class Job
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime DueDate { get; set; }
public bool IsCompleted { get; set; }
public virtual ICollection<Worker> Workers { get; set; }
}
public class Worker
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
// This is an "array". your spa needs to send in this format.
public virtual ICollection<Job> Job { get; set; }
}
Spa Code:
export class Job {
id: int;
name: string;
// other fields here..
// Workers property that maps API model
workers: Array<Worker>;
constructor(id: int, name: string [other fields..]) {
this.id = id;
// and so on..
}
public addWorker(worker) {
this.workers.push(worker);
}
}
export class Worker {
id: int;
firstName: string;
// other fields here.. No need for array of jobs here!
}
With this model, you can do this before calling the API (on add function):
add(Name: string, Description: string, worker: Worker): void {
// creates a job using constructor
const job = new Job(name, description);
// add Job via function(can even be more complex and add validation and so on..)
job.addWorker(worker);
this.jobsServices.addJob(job)
.subscribe(jobs => {
this.jobs.push(jobs);
});
}
This will call the api with a json like this:
{
"id": 1,
"name": "some name",
[ other fields..]
"workers": [
{ "id:" 1, "name": "some worker name" }
]
}
I need to turn this beutifull default JSON from Service Stack :
{
"Status": "ok",
"LanguageArray": [{
"Id": 1,
"Name": "English"
}, {
"Id": 2,
"Name": "Chinese"
}, {
"Id": 3,
"Name": "Portuguese"
}]
}
To this monstrosity of abomination:
{"status":"ok","language":{
"0":{"id":"1", "name":"English"},
"1":{"id":"2", "name":"Chinese"},
"2":{"id":"3", "name":"Portuguese"},
}
For reasons beyond my control or ration or logic.
My question is what are the simplest way of achieving this?
I need to do this to almost all Arrays ( they are IEnumerables implemented using List in C#)
I don't think I have a 'simplest way' and it kind of depends on where you need the serialization to happen as well as how strict the format is (case sensitive?, spacing?)
If place your example text and turn it into classes like this
public class Language
{
public int Id { get; set; }
public string Name { get; set; }
}
public class OuterLanguage
{
public string Status { get; set; }
public IEnumerable<Language> LanguageArray { get; set; }
}
A pretty straightforward way would be having a Dto that adds a property for serialization of the Array and ignores the original Array.
public class OuterLanguageDto
{
public string Status { get; set; }
[IgnoreDataMember]
public IEnumerable<Language> LanguageArray { get; set; }
public IDictionary<string, Language> language
{
get { return this.LanguageArray.ToDictionary(x => (x.Id - 1).ToString()); }
}
}
When you need to serialize your class (OuterLanguage) you use TranslateTo (or your preferred Mapper) and copy the values over to the Dto.
var jsonObj = obj.TranslateTo<OuterLanguageDto>();
var jsonStr = new JsonSerializer<OuterLanguageDto>().SerializeToString(jsonObj);
You could also look into Custom Serialization. That would give you to have a way to serialize all your Arrays into the correct format.
JsConfig<IEnumerable<Language>>.SerializeFn = ToJson
private string ToJson(IEnumerable<Language> arr)
{
var dict = arr.ToDictionary(x => x.Id - 1);
var str = JsonSerializer.SerializeToString<Dictionary<int, Language>>(dict);
return str;
}
However, I'm guessing you may have to do some "magic string work" to take your custom serialized Array's json string and format it properly when outer class (OuterLanguage in this example) is the one being serialized.