I have the following class structure. If I use the same assembly of contracts (assembly with all data classes n other stuff) used by api, I am unable to deserialize it in my application.
But I need to remove the dependency of that assembly. So I created another assembly with same namespace and contracts.
Example: I have many parts, and I can have a car out of those parts or a motorcycle.
public class Car
{
public string Name {get; set;}
public Dictionary<string,Part> SpareParts {get; set;}
}
public class Part
{
public string PartName {get; set;}
public object Value {get;set;}
public string Type {get;set}
}
Now, I have a Generic Query request and response
public class QueryRequest
{
//Stuff.. Request works fine.. i get a response
}
public class QueryResponse
{
public QueryResult[] Result;
}
public classs QueryResult
{
//Other details like entity name n stuff for car or motorcycle etc.
public Part[] Parts;
}
Remember that Part Class with Value field, that contains List
It goes like this
public class abstract Spoke
{
}
public class Spoke1 : Spoke
{
}
public class Spoke2 : Spoke
{
}
In my response I get this weird serialized string
"Value": {
"$type": "System.Collections.Generic.List`1[[namespace.Spoke, namespace]], mscorlib",
"$values": [
{
"$type": "namespace.spoke2, namespace",
//Other Properties of spoke2
}]
}
EDIT: I get the data in format of QueryResponse which contains QueryResult n Parts
I m using Newtonsoft.Json, Any ideas how to deserialize that into my namespace2.Spoke
I have the whole contract copied in another assembly.
I have tried changing the namespace same as in response but doesn't work.
Any suggestions of help please.
Related
In updating from RestSharp 106 to 108 I've been unable to come up with an elegant replacement for the following. I've looked at the migration documentation to no avail. There is a good chance I've missed something obvious.
Existing code that works in v106, which covered both XML and JSON
Class A
using RestSharp.Deserializers;
[DeserializeAs(Name = "response")]
public class ACertainResponse
{
public string SomeProp {get; set;}
//Etc
}
//JSON Payload {"response" : {"SomeProp" : "Some Value"}}
Class B
using RestSharp.Serializers;
[SerializeAs(Name = "request")]
public class SomeRequest
{
public string SomeProp {get; set;}
//Etc
}
//Resulting in :
//{"request" : { "SomeProp" : "A Value" } }
I've found [JsonPropertyName("customName")], however, as the name suggests that is for properties only.
Whilst I was unable to find a one size fits all solution as previouslt provided I was able to get it working by setting attributes for XML or JSON serialization explicitly. These attributes cover bother serialization and deserialization:
JSON
using System.Text.Json.Serialization;
[JsonSerializable(typeof(LeadspediaRequest), TypeInfoPropertyName = "response")]
public class ACertainResponse
{
public string SomeProp {get; set;}
//Etc
}
XML
using System.Xml.Serialization;
[XmlRoot(ElementName = "response")]
[XmlType("response")]
public class SomeRequest
{
public string SomeProp {get; set;}
//Etc
}
I got a bunch of conversions to make where I am converting a JSON data structure from a superset to a subset. EX:
A :
{
Name {
first: bob
middle: john
last : bobster
}
}
B :
{
Name {
first: bob
last : bobster
}
}
Both have a json schema describing their structure, and structure is exactly the same, is that B is simply missing some properties from A
Any ideas for an easy way to map A to B (essentially stripping A of properties that do not exist in B)? I am wondering if there is some library or C# language capabilities that could make this trivial.
Using C# and .NET Core.
Create an object for the subset like:
public class Name{
public string first{get;set;}
public string last {get;set;}
}
Deserialize the json to the subset object:
var test = JsonConvert.DeserializeObject<Name>(superset);
Then you can use this to convert back to json if needed:
JsonConvert.SerializeObject(subset)
You can use inheritance to cast objects from a subclass to another class.
Given the following json
{
"Name":
{
"first": "bob",
"middle": "john",
"last" : "bobster"
}
}
You can create some C# classes that match the json structure as follows:
public class Model
{
public FullName Name { get; set; }
}
public class Name
{
[JsonProperty("first")]
public string First { get; set; }
[JsonProperty("last")]
public string Last { get; set; }
}
public class FullName : Name
{
[JsonProperty("middle")]
public string Middle { get; set; }
}
Please note that:
FullName inherits from Name
class Model has a property of type FullName (i.e. the most specific object)
You can deserialize an object of type Model and then cast the Name property as follows:
string json = #"{
""Name"":
{
""first"": ""bob"",
""middle"": ""john"",
""last"" : ""bobster""
}
}";
Model model = JsonConvert.DeserializeObject<Model>(json);
Name name = model.Name as Name;
Edit
As an alternative, you can create a generic class as follows
public class Model<TName> where TName : Name
{
public TName Name { get; set; }
}
Deserializing the json:
string json = #"{
""Name"":
{
""first"": ""bob"",
""middle"": ""john"",
""last"" : ""bobster""
}
}";
var fullName = JsonConvert.DeserializeObject<Model<FullName>>(json);
var name = JsonConvert.DeserializeObject<Model<Name>>(json);
If I have a class/interface pair defined in AssemblyA under namespace AssemblyA.Entities:
public IEntity
{
string Name { get; set; }
}
[Serializable]
public Entity : IEntity
{
public string Name { get; set; }
}
And I serialize it to XML using XmlSerializer:
var myEntities = new List<IEntity>();
// myEntities is populated somehow
var data = XmlSerializationManager.Serialize(myEntities);
// 'data' gets saved to disk somewhere as a file
Then, if I duplicate the code/namespaces into AssemblyB so that I have namespace AssemblyA.Entities and the exact same code:
public IEntity
{
string Name { get; set; }
}
[Serializable]
public Entity : IEntity
{
public string Name { get; set; }
}
If I attempt to deserialize the previously serialized XML, will I get back AssemblyB's list of AssemblyA.Entities.IEntity? Or will it fail?
At what point does the serializer stop caring about what it's deserializing to? Can the assembly differ? Can the namespaces differ? Do the type names matter so long as the properties are named the same?
This will work. You will get AssembyB entity.
This is essentially how Web services work when the client would scaffold classes based on information in the wsdl, the client would then deserialise the data from the soap message into these scaffolded classes.
I have these entities:
public class Product
{
public string Code {get;set;}
public string Name {get;set;}
public ICollection<Pack> Packs {get;set;}
}
public class Pack
{
public string Colour {get;set;}
public string Moq {get;set;}
}
my json object:
var products = [{
code: 1243123,
name: "Gel",
packs: [{
color: "blue",
moq: 10
}]
}];
note the naming differences, i.e. case and american spelling of color. Will the JavaScriptConvert.DeserializeObject() deserialise that correctly?
Or will I have to do it another way?
If I can just have an object where I can access those names directly and there values that would be great!
If you use something like JSON.NET, then you can use attributes to control serialization, such as:
public class Pack
{
[JsonProperty("color")]
public string Colour {get;set;}
[JsonProperty("moq")]
public string Moq {get;set;}
}
Also, given your expected output, your Product class should look like this I think:
public class Product
{
[JsonProperty("code")]
public long Code {get;set;}
[JsonProperty("name")]
public string Name {get;set;}
[JsonProperty("packs")]
public Pack[] Packs {get;set;}
}
Note Code and Packs type.
If you use DataContractJsonSerializer instead, you can put attributes to your properties, giving them different names in generated/parsed JSON:
[DataContract]
public class Pack
{
[DataMember(Name = "color")]
public string Colour {get;set;}
[DataMember(Name = "moq")]
public string Moq {get;set;}
}
This post (https://stackoverflow.com/a/14486260/894358) suggests that Breeze does support inheritance, but my breeze manager is not able to understand the metadata being returned from the API. The server will return metadata and JSON results from other action methods, but when the manager tries to interpret the metadata it throws the error: "Cannot read propertyRef of undefined".
Here is my very simple implementation (Code First Migrations generates the database):
namespace VerySimpleVehicleModel.Models
{
public abstract class Vehicle
{
public int Id { get; set; }
public int Speed { get; set; }
}
public class Bus: Vehicle
{
public int Capacity { get; set; }
}
public class Car : Vehicle
{
public string Color { get; set; }
}
public class VehicleContext : DbContext
{
public DbSet<Car> Cars { get; set; }
public DbSet<Bus> Buses { get; set; }
public DbSet<Vehicle> Vehicles { get; set; }
}
}
namespace VerySimpleVehicleModel.Controllers
{
[BreezeController]
public class BreezeController : ApiController
{
readonly EFContextProvider<VehicleContext> _contextProvider = new EFContextProvider<VehicleContext>();
[HttpGet]
public string Metadata()
{
return _contextProvider.Metadata();
}
[HttpGet]
public IQueryable<Car> Cars()
{
return _contextProvider.Context.Cars;
}
}
}
And here is the metadata returned from the Metadata action method:
"{
\"schema\":
{
\"namespace\":\"VerySimpleVehicleModel.Models\",
\"alias\":\"Self\",
\"d4p1:UseStrongSpatialTypes\":\"false\",
\"xmlns:d4p1\":\"http://schemas.microsoft.com/ado/2009/02/edm/annotation\",
\"xmlns\":\"http://schemas.microsoft.com/ado/2009/11/edm\",
\"cSpaceOSpaceMapping\":\"
[
[
\\\"VerySimpleVehicleModel.Models.Vehicle\\\",
\\\"VerySimpleVehicleModel.Models.Vehicle\\\"
],
[
\\\"VerySimpleVehicleModel.Models.Car\\\",
\\\"VerySimpleVehicleModel.Models.Car\\\"
],
[
\\\"VerySimpleVehicleModel.Models.Bus\\\",
\\\"VerySimpleVehicleModel.Models.Bus\\\"
]
]
\",\"entityType\":
[
{
\"name\":\"Car\",
\"baseType\":\"Self.Vehicle\",
\"property\":
{
\"name\":\"Color\",
\"type\":\"Edm.String\",
\"fixedLength\":\"false\",\"maxLength\":\"Max\",
\"unicode\":\"true\",\"nullable\":\"true\"
}
},
{
\"name\":\"Bus\",
\"baseType\":\"Self.Vehicle\",
\"property\":{\"name\":\"Capacity\",
\"type\":\"Edm.Int32\",\"nullable\":\"false\"}
},
{
\"name\":\"Vehicle\",
\"abstract\":\"true\",
\"key\":{\"propertyRef\":{\"name\":\"Id\"}},
\"property\":
[
{\"name\":\"Id\",\"type\":\"Edm.Int32\",\"nullable\":\"false\",\"d4p1:StoreGeneratedPattern\":\"Identity\"},
{\"name\":\"Speed\",\"type\":\"Edm.Int32\",\"nullable\":\"false\"}
]
}
]
,\"entityContainer\":
{
\"name\":\"VehicleContext\",
\"entitySet\":
{
\"name\":\"Vehicles\",
\"entityType\":\"Self.Vehicle\"
}
}
}
}"
I can't reproduce a problem with your example. In fact, it works like a charm.
I copied it almost verbatim to the DocCode sample because it is so simple and we needed a simple one before getting into the complexities of the BillingDetails example (will publish next release).
This is a standard TPH model with an abstract base class. The key is recognized in metadata; look at the Vehicle base class for this line:
\"key\":{\"propertyRef\":{\"name\":\"Id\"}},
What is odd is that you are receiving metadata in the old string format. When I look at the payload for the metadata in my test runs I get a JSON object:
{"schema":{"namespace":"Inher ...
"entityType":[{"name":"Vehicle",
"abstract":"true",
"key":{"propertyRef":{"name":"Id"}}, ...
}]}]}}}
I suspect that you have an old copy of the Breeze.WebApi.dll. Perhaps you updated the Breeze NuGet package and the old assembly got trapped in the references or an old script file was retained. Try uninstalling and re-installing Breeze. Look carefully at the NuGet console log to make sure everything was replaced.