So I am using one of the google Id API; https://developers.google.com/instance-id/reference/server#manage_registration_tokens_for_push_subscriptions
I have previously been fortunate to have API that had WDSL or similar and been easy to parse into a class.
But the JSON I got back I can not parse easily.
{
"connectDate":"2018-02-12",
"application":"com.chrome.windows",
"subtype":"wp:https://xxxxxxxxxxxxxxxxxxx",
"authorizedEntity":"xxxxxx",
"rel":{
"topics":{
"movies":{
"addDate":"2018-01-26"
},
"anotherTopic":{
"addDate":"2018-02-12"
}
}
},
"connectionType":"WIFI",
"platform":"WEBPUSH"
}
Movies and anotherTopics are the topics I created so I can't add them to my class . Or can I?
There are of course ways to do it treating the json as string and using regex or going through the node as a dynamic object (dynamic dyn = JsonConvert.DeserializeObject(content);) but ideally I think it should be a dictionary (I think at least) but can not see how.
And as this is Google I assume there is more standard way to handle this kind of JSON.
I have tried creating a dictionary which I couldn't get working.
Stepping through the nodes I can get the data but end up with code like
DateTime.Parse(((Newtonsoft.Json.Linq.JValue)((Newtonsoft.Json.Linq.JProperty)((Newtonsoft.Json.Linq.JContainer)(obj.First)).First).Value).Value.ToString())
I have tried to look for similar JSON parsing exampels but I can not find any.
I did not share my attempt to extract the data in my first edit as I don't think that is the way to do it; it is a hack.
I created a class for it
public class SubscriptionDetails
{
public DateTime connectDate { get; set; }
public string application { get; set; }
public string subtype { get; set; }
public string authorizedEntity { get; set; }
public string connectionType { get; set; }
public string platform { get; set; }
public topics rel { get; set; }
}
But I am stuck when it comes to defining the subclass topics.
So I tried
public class topics : Dictionary<string, object>
which results in one dictionary entry with key topics?
the other option requires a dictionary name
public class topics
{
public Dictionary<string, Dictionary<string, string>> DUMMY { get; set; }
}
So thanks to the suggestion from Jamiec I got on the right track.
Of course already the node rel is a dictionary with one item called topics.
So need a few classes to parse the entire thing:
public class SubscriptionDetails
{
public DateTime connectDate { get; set; }
public string application { get; set; }
public string subtype { get; set; }
public string authorizedEntity { get; set; }
public string connectionType { get; set; }
public string platform { get; set; }
public Dictionary<string, topicItems> rel { get; set; }
}
public class topicItems : Dictionary<string, topicData> { }
public class topicData
{
public DateTime addDate { get; set; }
}
But if they add another node to rel in addition to 'topics' this most likely will crash.
Just doesn't seem to be a very good way to structure the data and the deserialised class isn't very user friendly either..
Anyway it works (for now)
Related
I am a bit stuck, hoping for guidance. I have 2 tables, Header and Details. However, the details is a bit different than most, and allows for a way to dynamically store data.: Yes, I am aware that I can create a table storing the details in the standard fashion, but the nature of the app needs to be more dynamic on the database side. I also realize I will have to modify the DTOs for different incarnations of the app, but this model is what I need to accomplish.
public class Header
{
public int Id { get; set; }
public string HeaderName { get; set; }
public ICollection<Detail> Details { get; set; }
}
public class Detail
{
public int Id { get; set; }
public int HeaderId { get; set; }
public string FieldName { get; set; }
public string FieldProperty { get; set; }
}
I want to use the following DTOs:
public class DataForDisplayDto
{
public int Id { get; set; }
public string HeaderName { get; set; }
public string TaskToPerform { get; set; }
public string Location { get; set; }
}
public class DataForCreationDto
{
public string HeaderName { get; set; }
public string TaskToPerform { get; set; }
public string Location { get; set; }
}
The data would be stored in the details in this fashion:
{
"FieldName": "tasktoperform",
"FieldProperty": "Thing to Do"
},
{
"FieldName": "location",
"FieldProperty": "Over there"
}
I am trying to use the Automapper to make it so I can read and write to the database using the DTOs, but I think I may be trying something it can't do.
Is there an article or something that anyone knows about that can point me in the direction to go? Or even the right keywords to search online for it. Is it even possible?
I suppose if it is not possible, I will have to do things a bit more manually, which is the last option, I am just hoping to do this with Automapper.
Thanks!
How about deriving your DTO from a base class that uses reflection to generate a mapping, and cache that mapping.
This way your DTO need only inherit a base class.
I'm new to C# and I face a problem that I couldn't resolve.
I listen to my Xiaomi gateway to get informations. These informations came as two type, report or heartbeat.
Report is when something trigger the sensor, as for plug, when you turn it on or off :
{"cmd":"report","model":"plug","sid":"158d000123f0c9","short_id":11119,"data":"{\"status\":\"off\"}"}
Heartbeat is send every x minutes to say sensor is still there :
{"cmd":"heartbeat","model":"plug","sid":"158d000123f0c9","short_id":11119,"data":"{\"voltage\":3600,\"status\":\"on\",\"inuse\":\"0\",\"power_consumed\":\"48\",\"load_power\":\"0.00\"}"}
As you can see, report and heartbeat doesn't contain the same parameters as data.
Here my plug class :
[XiaomiEquipement("plug")]
public class Plug
{
public string Model { get; set; } = "plug";
public string Sid { get; set; }
public string Battery { get; set; } = "CR2450";
public int BatteryLevel { get; set; }
public PlugReport Report { get; set; }
}
[XiaomiEquipement("plug_report")]
public class PlugReport
{
public int Voltage { get; set; }
public string Status { get; set; }
public int InUse { get; set; }
public float Power_Consume { get; set; }
public float Load_Power { get; set; }
}
Ok, when I start my app, I ask gateway for all sensor and I enter them inside a double dictionary :
dynamic Equipements = new Dictionary<string, Dictionary<string, dynamic>>();
And when I receive report or heartbeat, I search for the dictionary entry, modify it and send to my home automation system :
Type modelReportType = Assembly.GetExecutingAssembly().GetTypes().SingleOrDefault(t => t.GetCustomAttribute<Response.XiaomiEquipementAttribute>()?.Model == data.Model + "_report");
dynamic test = Equipements[data.Model][data.Sid].Report;
dynamic data = JsonConvert.DeserializeObject(Convert.ToString(data.Data), modelReportType);
If data doesn't contain all property, it write them as default.
What I want is that if a property isn't exist on the report/heartbeat, use dictionary value.
For example, my dictionary contain :
{"model":"plug","sid":"158d000123f0c9","short_id":11119,"data":"{\"voltage\":3600,\"status\":\"on\",\"inuse\":\"1\",\"power_consumed\":\"48\",\"load_power\":\"3.56\"}"}
And I receive :
{"cmd":"report","model":"plug","sid":"158d000123f0c9","short_id":11119,"data":"{\"status\":\"off\"}"}
I want :
{"model":"plug","sid":"158d000123f0c9","short_id":11119,"data":"{\"voltage\":3600,\"status\":\"off\",\"inuse\":\"1\",\"power_consumed\":\"48\",\"load_power\":\"3.56\"}"}
And I get for the moment :
{"model":"plug","sid":"158d000123f0c9","short_id":11119,"data":"{\"voltage\":3600,\"status\":\"off\",\"inuse\":\"0\",\"power_consumed\":\"00\",\"load_power\":\"0.00\"}"}
I tried PopulateObject but it didn't work :
dynamic data = JsonConvert.PopulateObject(Convert.ToString(data.Data), test);
Anyone have an idea to modify my dynamic var without touching others properties ?
Edit : some reports example :
>
{"cmd":"report","model":"weather.v1","sid":"158d0001a231ab","short_id":39499,"data":"{\"humidity\":\"5262\"}"}
{"cmd":"report","model":"magnet","sid":"158d000159febe","short_id":40805,"data":"{\"status\":\"close\"}"}
And for heartbeat :
{"cmd":"heartbeat","model":"sensor_ht","sid":"158d0001a2c3e9","short_id":42820,"data":"{\"voltage\":3015,\"temperature\":\"2644\",\"humidity\":\"5454\"}"}
{"cmd":"heartbeat","model":"magnet","sid":"158d000159febe","short_id":40805,"data":"{\"voltage\":3025,\"status\":\"open\"}"}
As I said, I don't know in advance wich sensor it will be so everything must work in every case.
That's why when I receive report/heartbeat, I searched for the report class base on model name, deserialize data part to an instance of this class.
As for me, you shouldn't use dynamic. Instead of this, try to something like that.
public class Data
{
[JsonProperty("status")]
public string Status { get; set; }
}
public class ReportResponse
{
[JsonProperty("cmd")]
public string Cmd { get; set; }
[JsonProperty("model")]
public string Model { get; set; }
[JsonProperty("sid")]
public string Sid { get; set; }
[JsonProperty("short_id")]
public int Short_id { get; set; }
[JsonProperty("data")]
public Dictionary<string, string> Data { get; set; }
//public Data Data { get; set; }
}
var deserializeReponse = JsonConvert.DeserializeObject<ReportResponse>(rawResponse);
When you are writing in this style, your code will be cleaner and exceptions, you're getting, will be more understandable
P.S.
When I need to generate objects from json, I use these two sites:
Getting formatted json
POCO generator
I am working in C#, Visual Studio 2015, targeting .NET 4.5. We have existing systems (some written in Java, some legacy code in C++, etc.) that already exchange XML in particular formats. I have studied XMLSerializer, DataContractSerializer, and looked briefly at the ISerializable Interface. While I think I already know the answer (ISerializable), I figured I would see if anyone has any clever ideas or solutions for duplicating the XML format we need without coding it all ourselves. We have four different XML messages to duplicate, here is just one of them:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE message SYSTEM "work_request_20.dtd">
<message message_id="1005" message_dt="01/21/2008 09:50:23.221 AM" message_type="Work_Request" message_sub_type="New" message_dtd_version_number="2.0">
<header>
<from_application_id>3367e115-c873-4ac9-a1dd-7e45231dc3d5</from_application_id>
<to_application_id>35e0cca2-e423-4ffe-ba07-7d056775c228</to_application_id>
</header>
<body>
<work_request requisition_number="REQ44">
<client client_id="44">
<first_name>Barak</first_name>
<last_name>Obama</last_name>
</client>
<patient patient_id="4444" patient_species="CANINE" patient_gender="MALE_INTACT">
<patient_name>Bo</patient_name>
<patient_breed>Portuguese Water Dog</patient_breed>
<patient_birth_dt>04/04/2004</patient_birth_dt>
<patient_weight patient_weight_uom="lbs">
<weight>44.4</weight>
</patient_weight>
</patient>
<doctor>
<first_name>Surgeon</first_name>
<last_name>General</last_name>
</doctor>
<service_add>
<service_cd>ALB</service_cd>
<service_cd>GLU</service_cd>
<service_cd>BUN</service_cd>
</service_add>
</work_request>
</body>
</message>
If anyone can suggest any brilliant shortcuts as compared to the obvious solution, we would be forever grateful.
Thanks in advance.
Serializing with XmlSerializer is likely going to be the easiest solution. If classes auto-generated by xsd.exe are too bloated, you can use another code generation tool such as https://xmltocsharp.azurewebsites.net/ to generate them for you -- or even do it yourself manually.
For instance, I generated the following types using https://xmltocsharp.azurewebsites.net/ then made a few manual tweaks that are mentioned in comments:
[XmlRoot(ElementName="header")]
public class Header {
// I modified the types of these properties from string to Guid
[XmlElement(ElementName="from_application_id")]
public Guid From_application_id { get; set; }
[XmlElement(ElementName="to_application_id")]
public Guid To_application_id { get; set; }
}
[XmlRoot(ElementName="client")]
public class Client {
[XmlElement(ElementName="first_name")]
public string First_name { get; set; }
[XmlElement(ElementName="last_name")]
public string Last_name { get; set; }
[XmlAttribute(AttributeName="client_id")]
public string Client_id { get; set; }
}
[XmlRoot(ElementName="patient_weight")]
public class Patient_weight {
// I changed weight from string to decimal
[XmlElement(ElementName="weight")]
public decimal Weight { get; set; }
[XmlAttribute(AttributeName="patient_weight_uom")]
public string Patient_weight_uom { get; set; }
}
[XmlRoot(ElementName="patient")]
public class Patient {
[XmlElement(ElementName="patient_name")]
public string Patient_name { get; set; }
[XmlElement(ElementName="patient_breed")]
public string Patient_breed { get; set; }
[XmlElement(ElementName="patient_birth_dt")]
public string Patient_birth_dt { get; set; }
[XmlElement(ElementName="patient_weight")]
public Patient_weight Patient_weight { get; set; }
[XmlAttribute(AttributeName="patient_id")]
public string Patient_id { get; set; }
[XmlAttribute(AttributeName="patient_species")]
public string Patient_species { get; set; }
[XmlAttribute(AttributeName="patient_gender")]
public string Patient_gender { get; set; }
}
[XmlRoot(ElementName="doctor")]
public class Doctor {
[XmlElement(ElementName="first_name")]
public string First_name { get; set; }
[XmlElement(ElementName="last_name")]
public string Last_name { get; set; }
}
[XmlRoot(ElementName="work_request")]
public class Work_request {
[XmlElement(ElementName="client")]
public Client Client { get; set; }
[XmlElement(ElementName="patient")]
public Patient Patient { get; set; }
[XmlElement(ElementName="doctor")]
public Doctor Doctor { get; set; }
// I simplied this into a list of strings.
[XmlArray(ElementName="service_add")]
[XmlArrayItem("service_cd")]
public List<string> Service_add { get; set; }
[XmlAttribute(AttributeName="requisition_number")]
public string Requisition_number { get; set; }
}
[XmlRoot(ElementName="body")]
// I renamed this to WorkRequestBody
public class WorkRequestBody
{
[XmlElement(ElementName="work_request")]
public Work_request Work_request { get; set; }
}
[XmlRoot(ElementName="message")]
// I made this generic to account for multiple types of messge.
public class Message<T> where T : class, new()
{
[XmlElement(ElementName="header")]
public Header Header { get; set; }
[XmlElement(ElementName="body")]
public T Body { get; set; }
[XmlAttribute(AttributeName="message_id")]
public string Message_id { get; set; }
[XmlAttribute(AttributeName="message_dt")]
public string Message_dt { get; set; }
[XmlAttribute(AttributeName="message_type")]
public string Message_type { get; set; }
[XmlAttribute(AttributeName="message_sub_type")]
public string Message_sub_type { get; set; }
[XmlAttribute(AttributeName="message_dtd_version_number")]
public string Message_dtd_version_number { get; set; }
}
Using these types, I can now deserialize and re-serialize your XML into a Message<WorkRequestBody> and the resulting re-serialized XML is equivalent to the original XML, according to XNode.DeepEquals(). Sample fiddle.
To include a <!DOCTYPE ...> in the re-serialized XML, see this question.
Implementing IXmlSerializable for the root object is roughly the same difficulty as manually reading and writing your entire object graph with an XmlReader and XmlWriter. It's certainly possible but will require more work that using XmlSerializer. You'll still need to design POCOs to hold the data in memory, so it will be easier to use a serializer to read and write those POCOs automatically whenever possible. See here for a guide on how to do it correctly.
Reading and writing with LINQ to XML would represent an intermediate level of difficulty.
Finally, DataContractSerializer is not appropriate since there is no way to indicate that certain c# properties should be serialized as XML attributes (source).
I'm hooking up to a pretty extensive online service using JSON in C# and have noticed they use the same name with different values (and types).
In creating the JSON models I'm running into an issue where the different models require different value types.
For example.
namespace Mylibrary
{
// event
public class event
{
public Item item { get; set; }
public string type { get; set; }
}
public class Item
{
public string url { get; set; }
public string icon { get; set; }
}
// context
public class context
{
public Item item { get; set; }
public string creator { get; set; }
}
public class Item
{
public int index { get; set; }
public string name { get; set; }
}
}
If I rename the above item class I can no longer use the json deserializer. However, of course I get a compiler error because of the duplicate class name "Item".
There are somewhere above 30 data models that I need to generate for this service. In looking closer at their schema, this is going to be an issue for over 90% of those models. The models themselves are very large, the example above is a simplified example of what I'm running into to illustrate the problem.
In thinking about this issue, I'm betting this would be a rather common occurrence. How is this dealt with?
As #mecek points out, it's the property names that matter, not the class names. So just give the classes unique names:
EventItem
ContextItem
Then you can use JsonProperty to rename the properties:
public class Context
{
[JsonProperty("item")]
public ContextItem Item { get; set; }
[JsonProperty("creator")]
public string Creator { get; set; }
}
I have a class like this:
public class Empresa
{
public string Nombre { get; set; }
public string NIT { get; set; }
public string NombreRepresentanteLegal { get; set; }
public string TelefonoRepresentanteLegal { get; set; }
public string NombreContacto { get; set; }
public string TelefonoContacto { get; set; }
}
However in my app, I want the users to be able to add custom properties, for example twitter handle, however I havent found documentation in how to do that, I heard about the EAV model, but thats not performant
You could store the additional data as XML into an XML column, and have the client deserialize / serialize the meta-data appropriately. Xml can be a viable solution for when you don't know the structure of the data, or if the structure can be altered at run-time.
You're also able to INDEX the XML to help with shredding / querying, so performance can be maintained while processing large xml documents.
Your class could contain, an ExtraPropertiesElement, that takes the XML string, and parses it into an XElement, which you could then utilize XPath, to query for the requested xml element/attribute.
One problem with this approach, is that all additional properties are stored in XML in the database, and it's not as easy to perform queries against the data. It's straightforward to do so, but it's not as simple as selecting a column name from a table.
You can read more about the XML Data Type and the uses here.
You can also read up on how to query XML column stores here.
public class Empresa
{
public string Nombre { get; set; }
public string NIT { get; set; }
public string NombreRepresentanteLegal { get; set; }
public string TelefonoRepresentanteLegal { get; set; }
public string NombreContacto { get; set; }
public string TelefonoContacto { get; set; }
[Column(TypeName="xml")]
public string ExtraProperties { get; set; }
[NotMapped]
public XElement ExtraPropertiesElement
{
get { return XElement.Parse(ExtraProperties ); }
set { ExtraProperties = value.ToString(); }
}
}