Deserializing with a json file with inner classes with JSON.NET C# - c#-4.0

I have the following structure in my json file
"missionName": "missionname",
"thumb_image": "pics/mission-info.png",
"uplinkPage": [
{
"RPC": {
"name": "RPC",
"rpc": "",
"args": ""
},
"EXE": {
"name": "app1",
"prog": "",
"args": ""
},
"VM": {
"name": "VM",
"name": "",
"args": ""
},
"JAR": {
"name": "JAR",
"prog": "",
"args": ""
},
"link": {
"name": "somelink",
"url": ""
}
}
],
for this I have the following class
public class EXE
{
public string name { get; set; }
public string prog { get; set; }
public string args { get; set; }
}
public class RPC
{
public string name { get; set; }
public string rpc { get; set; }
public string args { get; set; }
}
public class VM
{
public string name { get; set; }
public string args { get; set; }
}
public class JAR
{
public string name { get; set; }
public string prog { get; set; }
public string args { get; set; }
}
public class Link
{
public string name { get; set; }
public string url { get; set; }
}
public class UplinkPage
{
public VM[] vmList { get; set; }
public EXE[] exeList { get; set; }
public RPC[] rpcList { get; set; }
public JAR[] jarList { get; set; }
public Link[] linkList { get; set; }
}
public class Rootobject
{
public string missionName { get; set; }
public string thumb_image { get; set; }
public Uplinkpage[] uplinkPage { get; set; }
}
the uplinkPage section can have one or many of each of the EXE, RPC, VM .. sections. I have tried to add multiply sections like this
"EXE": {
"1": {
"name": "app1",
"data-prog": "",
"data-args": ""
},
"2": {
"name": "app2",
"data-prog": "",
"data-args": ""
}
}
when I do the deserialization as so
Rootobject page = JsonConvert.DeserializeObject<Rootobject>(File.ReadAllText("mission1.json"));
I get an object and I can read everything except if I have multiply values of the same type, I will only get one of them. If I declare sections as array
public EXE[] exeList { get; set; }
I will get the last one and if as
Dictionary<string,EXE> exeList {get; set;}
I will get the first one. I have noticed that when I use the dictionary the type of the EXE changes to EXE1.
So I was wondering what am I doing wrong? am I mission some thing here?
cheers,
es

Whenever you have a JSON property that might be duplicated, it will be easiest to represent the value of that property as JSON array, rather than multiple properties with duplicated names. I.e. instead of
{
"EXE" : {"id":1},
"RPC" : {"name":"a"},
"EXE" : {"id":2},
}
You want to do:
{
"EXE" : [{"id":1}, {"id":2}],
"RPC" : [{"name":"a"}]
}
Similarly, in the VM class, name appears multiple times, so name should be an array as well:
public class VM
{
public string [] name { get; set; }
public string args { get; set; }
}
(It's not impossible to deserialize duplicated property names, just difficult, and requires a custom converter. See How to deserialize JSON with duplicate property names in the same object. Since you control your JSON format, I'd recommend avoiding this. Using a nested object with indexed properties as you propose in your question is also an option; it is less difficult but still requires custom conversion. See How to parse this JSON using Newton Soft for nested object. But using a JSON array is easiest.)
Next, you need to tell Json.NET how to map c# property names to JSON property names when they are inconsistent. For instance, in your JSON you have a property "EXE" but in c# the property name is public EXE[] exeList { get; set; }. You can either rename the JSON properties, rename the c# properties, or make the mapping using [JsonProperty]:
public class UplinkPage
{
[JsonProperty("VM")]
public VM[] vmList { get; set; }
[JsonProperty("EXE")]
public EXE[] exeList { get; set; }
[JsonProperty("RPC")]
public RPC[] rpcList { get; set; }
[JsonProperty("JAR")]
public JAR[] jarList { get; set; }
[JsonProperty("link")]
public Link[] linkList { get; set; }
}
I notice also that your EXE object sometimes has a "data-prog" property, and sometimes just a "prog". You should standardize on one.
Thus your JSON should look like:
{
"missionName": "missionname",
"thumb_image": "pics/mission-info.png",
"uplinkPage": [
{
"RPC": [
{
"name": "RPC",
"rpc": "",
"args": ""
}
],
"EXE": [
{
"name": "app1",
"prog": "prog1",
"args": "args1"
},
{
"name": "app2",
"prog": "prog2",
"args": "args2"
}
],
"VM": [
{
"name": [
"VM",
""
],
"args": ""
}
],
"JAR": [
{
"name": "JAR",
"prog": "",
"args": ""
}
],
"link": [
{
"name": "somelink",
"url": ""
}
]
}
]
}
And your classes should look like:
public class EXE
{
public string name { get; set; }
public string prog { get; set; }
public string args { get; set; }
}
public class RPC
{
public string name { get; set; }
public string rpc { get; set; }
public string args { get; set; }
}
public class VM
{
public string [] name { get; set; }
public string args { get; set; }
}
public class JAR
{
public string name { get; set; }
public string prog { get; set; }
public string args { get; set; }
}
public class Link
{
public string name { get; set; }
public string url { get; set; }
}
public class UplinkPage
{
[JsonProperty("VM")]
public VM[] vmList { get; set; }
[JsonProperty("EXE")]
public EXE[] exeList { get; set; }
[JsonProperty("RPC")]
public RPC[] rpcList { get; set; }
[JsonProperty("JAR")]
public JAR[] jarList { get; set; }
[JsonProperty("link")]
public Link[] linkList { get; set; }
}
public class Rootobject
{
public string missionName { get; set; }
public string thumb_image { get; set; }
public UplinkPage[] uplinkPage { get; set; }
}
prototype fiddle.

Related

How To Return only Child Model property in wep api response

here Is my Models ,here in my model PK is decorated with Key becoz in EF it must be . But as it is aslo available in base class. if I removed PK from Person it gives error as model has not assign a Key IN EF which is strange to me .
public class Person:TBase
{
[Key]
public long PK { get; set; }
public string NAME { get; set; }
public string ADDRESS { get; set; }
}
public class TBase: Base
{
public virtual long? FKTenant { get; set; }
public virtual bool IsDefault { get; set; }
}
public class Base
{
[Key]
public long PK { get; set; }
public virtual string GlobalID { get; set; }
}
and Controller
[EnableQuery]
public IHttpActionResult Get()
{
try
{
IQueryable<Person> result;
var result = DbContext.Persons.Where(x => x.FKTenant == context.FKTenant).ToList();
return Ok(result);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
i am getting response in postman is
"value": [
{
"#odata.etag": "W/\"bnVsbA==\"",
"PK": 1001,
"NAME": "VIVEK",
"ADDRESS": "DELHI",
"FKTenant":null,
"IsDefault ":null,
"GlobalID ":null
}]
But my Intention to get ouput response as below which should contain onlly name and address
"value": [
{
"#odata.etag": "W/\"bnVsbA==\"",
"NAME": "VIVEK",
"ADDRESS": "DELHI"
}]
Any guide will be appreciable.
You should use a ViewModel
write another class as ViewModel and when you want return object first map to new ViewModel then return it.

How to deserialize below json array

// Json
{
"application": [
"java.util.arraylist",
[
{
"applicationId": "XXXX"
}
]
],
"applicationType": "ZZZZ",
"functionType": "YYYY"
}
I have created the below property for above JSON
public class Root
{
public Application[] Application { get; set; }
public string ApplicationType { get; set; }
public string FunctionType { get; set; }
}
public class Application
{
public string something { get; set; }
public SubApplication[] SubApplicationItem { get; set; }
}
public class SubApplication
{
public string applicationId { get; set; }
}
Not sure how should I create a property for below part of the JSON, Can someone please share your thoughts on this
[
"java.util.arraylist",
[

Sending different entity types to same Blazor component

I have a blazor component that I want to pass data retreived from a backend. Each set of data has a different entity name so I'm having trouble converting the entity to a generic type when it gets to the component. Where is my error? Thanks
Getting the following error on ChildData=#sysList in the parent:
Argument1: Cannot convert from Test2.Shared.Models.MeasurementSystem[] to System.Collections.Generic.IReadOnlyList[]
Parent
<ChildComponent ChildData=#sysList TItem=#Test2.Shared.Models.MeasurementSystem</ChildComponent>
<ChildComponent ChildData=#unitList TItem=#Test2.Shared.Models.MeasurementUnit</ChildComponent>
<ChildComponent ChildData=#groupList TItem=#Test2.Shared.Models.MeasurementGroup</ChildComponent>
#functions {
private Test2.Shared.Models.MeasurementSystem[] sysList { get; set; }
private Test2.Shared.Models.MeasurementUnit[] unitList { get; set; }
private Test2.Shared.Models.MeasurementGroup[] groupList { get; set; }
protected override async Task OnInitAsync()
{
sysList = await Http.GetJsonAsync<Test2.Shared.Models.MeasurementSystem[]>("/api/System/Index");
unitList = await Http.GetJsonAsync<Test2.Shared.Models.MeasurementUnit[]>("/api/Unit/Index");
groupList = await Http.GetJsonAsync<Test2.Shared.Models.MeasurementGroup[]>("/api/Group/Index");
}
}
Child
#typeparam TItem
#foreach (var data in ChildData)
{
<p #data.Name>
}
#functions {
[Parameter] private IReadOnlyList<TItem>[] ChildData { get; set; }
}
Classes
public class MeasurementSystem
{
public int SystemId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}
public class MeasurementUnit
{
public int UnitId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int Factor { get; set; }
public int Magnitude { get; set; }
}
}
public class MeasurementGroup
{
public int GroupId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}

Loading multiple levels of nested navigation and collection properties with proxy disabled

I'm having a hard time figuring out how to do queries with levels of alternating collection and navigation properties with proxy and lazy loading disabled to serialize the result.
public ApplicationDbContext()
: base("Debug")
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
The entities look like this (omitting non-navigation or non-collections):
public class Comprobante: ComprobanteGeneric
{
}
public class ComprobanteGenericStructure
public int Id { get; set; }
[Required]
public virtual Conceptos Conceptos { get; set; }
}
public class Conceptos
{
public Conceptos()
{
Concepto = new List<Concepto>();
}
[ForeignKey("Comprobante")]
public int Id { get; set; }
[Required]
public virtual ICollection<Concepto> Concepto { get; set; }
public virtual Comprobante Comprobante { get; set; }
}
public class Concepto :RelatedComprobante
{
[Key]
public int Id { get; set; }
public virtual OrderOfImpuestosForConceptos Impuestos { get; set; }
public virtual Conceptos Conceptos { get; set; }
}
public class RelatedComprobante
{
[ForeignKey("Comprobante")]
public int ComprobanteId { get; set; }
public virtual Comprobante Comprobante { get; set; }
}
public class OrderOfImpuestosForConceptos : RelatedComprobante
{
public int Id { get; set; }
public virtual TrasladosNode Traslados { get; set; }
public virtual Retenciones Retenciones { get; set; }
}
public class TrasladosNode : RelatedComprobante
{
public TrasladosNode()
{
Traslado = new HashSet<Traslado>();
}
[Key]
public int Id { get; set; }
[Required]
public virtual ICollection<Traslado> Traslado { get; set; }
}
public class Traslado : RelatedComprobante
{
public int Id { get; set; }
public virtual TrasladosNode TrasladosNode { get; set; }
}
public class Retenciones : RelatedComprobante
{
public Retenciones()
{
Retencion = new List<Retencion>();
}
public int Id { get; set; }
[Required]
public virtual ICollection<Retencion> Retencion { get; set; }
}
public class Retencion : RelatedComprobante
{
public int Id { get; set; }
public virtual Retenciones Retenciones { get; set; }
}
I need the whole graph. With lazy loading enabled it returns it all eventually but serialization takes several seconds and several queries to DB. I disabled it and tried the following query:
comprobantes = _db.Comprobante
.Include(c => c.Conceptos.Concepto.Select(co => co.Impuestos.Retenciones).Select(r=>r.Retencion))
.Include(c => c.Conceptos.Concepto.Select(co => co.Impuestos.Traslados).Select(t => t.Traslado));
However I get an empty concepto list:
[{
"id": 324,
"conceptos": {
"concepto": []
}
},
{
"id": 340,
"conceptos": {
"concepto": []
}
}
}]
Even simpler queries like the following yield the exact same results:
comprobantes = _db.Comprobante
.Include(c => c.Conceptos.Concepto.Select(co => co.Impuestos));
I know is not the serialization for when I inspect the object while debugging is empty:
What am I doing wrong?
Thanks to David comment I was able to build a working query(es):
var comprobantes = _db.Comprobante
.Include(b => b.Conceptos.Concepto.Select(c => c.Impuestos.Retenciones.Retencion))
.Include(b => b.Conceptos.Concepto.Select(c => c.Impuestos.Traslados.Traslado));
foreach (var comprobante in comprobantes)
{
_db.ComprobanteTraslado.Where(t => t.ComprobanteId == comprobante.Id);
_db.ComprobanteRetencion.Where(r => r.ComprobanteId == comprobante.Id);
}

Is there a way to have a ServiceStack metadata page show all the options for an enum request or response property

I'd like to be able to have the code below
[Route("/Incidents", "Get")]
public class GetViewConfig
{
public List<Filter> Filters { get; set; }
}
public class Filter
{
public string Property { get; set; }
public FilterType Type { get; set; }
public string Value { get; set; }
}
public enum FilterType
{
IsBetween,
Is,
IsNot
}
public class GetViewConfigResponse
{
public List<Filter> Filters { get; set; }
}
public class ViewConfigService : Service
{
public object Get(GetViewConfig request)
{
return null;
}
}
Show all the values for the FilterType on the metadata page. Is there a way to do this?
Not on the metadata pages, but you can view this using the Swagger API and the [ApiAllowableValues] attribute, e.g:
[Api("Service Description")]
[Route("/swagger/{Name}", "GET", Summary = #"GET Summary", Notes = "GET Notes")]
public class MyRequestDto
{
[ApiMember(Name="Name", Description = "Name Description",
ParameterType = "path", DataType = "string", IsRequired = true)]
[ApiAllowableValues("Name", typeof(Color))] //Enum
public string Name { get; set; }
}

Resources