I'm having trouble understanding serialization of one of my objects.
Scenario:
I'm receiving data from a service which is in a given format. I want to take the data in as is. Due to naming conventions I have to use DataMember properties to match the incoming data to properly named class properties. I use System.Runtime.Serialization for this. Example:
[DataContract]
public class IncomingData
{
[DataMember(Name = "$Filename")]
public string Filename { get; set; }
}
This works fine and the data is mapped to the internal property name.
At some point I have to serialize this object again and I naively thought that it would serialize to the internal property name e.g.
{ "Filename":"C:\temp\lala.txt"}
however that is not true and the original propertyname "$Filename" is used instead. I assume this is because DataMember works both ways.
Is there an elegant way to have this object serialize to the propertynames and ignore DataMember? I tried if using a different serialization library works (JSON.NET) but it also seems to follow DataMember.
Do I have to wrap this object to another to acchieve?
Thanks for any hints!
blu
You could define an interface for keeping these objects in sync...
public interface IData
{
string Filename { get; set; }
}
// deserialize me.
[DataContract]
public class IncomingData : IData
{
[DataMember(Name = "$Filename")]
public string Filename { get; set; }
}
// serialize me.
public class Data : IData
{
public string Filename { get; set; }
}
...or you could use virtual properties and override them with the serialization attributes...
// serialize me.
class Data
{
public virtual string Filename { get; set; }
}
// deserialize me.
[DataContract]
class IncomingData : Data
{
[DataMember(Name = "$Filename")]
public override string Filename { get => base.Filename; set => base.Filename = value; }
}
...both of these methods would require the use of a mapper like AutoMapper to clone the IncomingData into the attribute-free Data class...
mapper.Map<IncomingData, Data>(user);
...so I appreciate this feels less than ideal.
Related
I'm creating objects to store the JSON data I will be receiving and cannot figure out the right way to structure the objects. Basically, I can be receiving two different objects that only have differences in the body, so I wish to make a base class.
public class SampleBase
{
public string url { get; set; }
public string resource { get; set; }
public string Body body { get; set; }
}
This is an example of the base, with the Body object declared below
public abstract class Body{ }
I then have two separate files for the versions of the base object I can receive, with an example below:
public class SampleObject : SampleBase
{
public class Body
{
public string bodyproperty { get; set; }
}
}
I am doing this just to be efficient with the classes since they share some properties. The SampleBase class will never be called, instead incoming json will be deserialized into SampleObject. Is this best practice?
Edit: Going by this example, the JSON is received as
{
"url": "xxxxxxxxxx",
"resource": "xxxxxxx",
"body": {
"bodyproperty": "xxxx",
}
}
Your class structure can heavily depend on your choice of serializer. For example, the DataContractJsonSerializer can technically handle inherited classes, but it does it in somewhat of a clunky way. You need to define all the known inheritors of your base type on the base type.
Personally, I would use composition rather than inheritance in your case. Here's an example using the DataContractJsonSerializer:
[DataContract]
public class Wrapper<T> where T : Body
{
[DataMember(Name = "url")]
public string Url { get; set; }
[DataMember(Name = "resource")]
public string Resource { get; set; }
[DataMember(Name = "body")]
public string T Body { get; set; }
}
[DataContract]
public class Body
{
[DataMember(Name = "bodyproperty")]
public string BodyProperty { get; set; }
}
Then you'd use the class like any other generic.
Wrapper<Body> obj = new Wrapper<Body>();
Edit: Since this is a MVC application, you'll likely be working with the JavascriptSerializer. The DataContract and DataMember can be ignored but the structure of the classes is still relevant.
var serializer = new JavaScriptSerializer();
var data = serializer.Deserialize<Wrapper<Body>>(json);
Scenario
I have some XML come down from a service that I want to deserialize.
Depending on what is returned from the service, the XML can vary slightly (with the element names); but the XML always follows a common structure.
Here is a sample of what the XML might look like:
<ATemplate>
<Name>SomeTemplate</Name>
<TemplateItems>
<ATemplateItem>
<Name>SomeTemplateItem</Name>
<TemplateFields>
<ATemplateField>
<Name>SomeTemplateField</Name>
<Colour>Blue</Colour>
</ATemplateField>
... more template fields
</TemplateFields>
</ATemplateItem>
... more template items
</TemplateItems>
</ATemplate>
Using the above XML as an example, I have created a ATemplate class that will deserialize nicely from the XML, using the ATemplateItem and ATemplateField classes accordingly:
public class ATemplate
{
public string Name { get; set; }
public List<ATemplateItem> TemplateItems { get; set; }
}
public class ATemplateItem
{
public string Name { get; set; }
public List<ATemplateField> TemplateFields { get; set; }
}
public class ATemplateField
{
public string Name { get; set; }
public string Colour { get; set; }
}
I use this code to deserialize:
ATemplate template;
using (TextReader reader = new StringReader(xmlString))
{
template = (ATemplate)new XmlSerializer(typeof(ATemplate)).Deserialize(reader);
}
All good, so far.
Curveball
The same scenario might occur where the XML contains BTemplate, BTemplateItems and BTemplateFields; still following the structure as above.
So I created other classes for this situation:
public class BTemplate { ... }
public class BTemplateItem { ... }
public class BTemplateField { ... }
And made the relevant classes inherit respectively from ITemplate, ITemplateItem and ITemplateField I created, also:
Interfaces
public class ITemplate
{
public string Name { get; set; }
public List<ITemplateItem> TemplateItems { get; set; }
}
public class ITemplateItem
{
public string Name { get; set; }
public List<ITemplateField> TemplateFields { get; set; }
}
public class ITemplateField
{
public string Name { get; set; }
public string Colour { get; set; }
}
This is so I can then create one function, which is able to loop through the ITemplateItems and their ITemplateFields and perform some cool stuff:
public void Foo(ITemplate template)
{
foreach (var item in template.TemplateItems)
{
// do cool stuff
foreach (var field in item.TemplateFields)
{
// do more cool stuff
}
}
}
Some things to note:
In the object that contains the XML, I know what "type" the XML contains - given an Enum I use to identify
I then use a switch statement to run different methods, depending on the said "type"
Generic Method?
Now, rather than deserializing the XML differently in each of those method cases, I would like to use a Generic method to deserialize.
So I created one, like this:
public ITemplate DeserializeTemplate<T>(string xmlString) where T : ITemplate
{
using (TextReader reader = new StringReader(xmlString))
{
return (T)new XmlSerializer(typeof(T)).Deserialize(reader);
}
}
And call it from within the specific methods like so:
var template = DeserializeTemplate<ATemplate>(xmlString);
Then, I can use the ITemplate that it returns, and pass it to Foo(ITemplate template) to go and perform some magic and wizardry.
But...
No compilation errors, as yet - however I get a RunTime error, because it cannot deserialize an Interface.
I gather this is because it's trying to then deserialize the ITemplate's TemplateItems as ITemplateItems.
Can I do the above?
My question is:
How can I get around this issue?
Can I use this Generic deserialize method?
Will I need to treat each one differently in the separate methods?
Will I need to make the Interface generic also, with the types to expect?
I'm banging my head against the desk, so I really hope you lovely SO people can help.
As always, your comments, answers and suggestions are much appreciated :)
I am writing a set of data structures to ingest third-party JSON into (no writing out) using JSON.NET.
I have a case for reading some of the top-level JSON elements into a member object of the object being deserialized into.
My JSON:
{
"Id":1
"Checksum":42
"Name":"adam",
"Hair":true
}
My ideal object structure:
public class EntityHeader
{
int Id { get; set; }
int Checksum { get; set; }
}
public class Entity
{
[HeroicJsonAttribute( "Id", "Checksum" )]
public EntityHeader Header { get; set; }
public string Name { get; set; }
public bool Hair { get; set; }
}
Is there a simple way to achieve this? I will have a number of types which will need this, and I'd hate to have to write a JsonConverter for each.
This question has been asked before, here, but the accepted answer doesn't address the question.
Thanks!
An alternative approach would be to use an EntityHeader field in the Entity class as a backing store for private properties which can be deserialized into:
public class EntityHeader
{
int Id { get; set; }
int Checksum { get; set; }
}
public class Entity
{
private EntityHeader m_Header = new EntityHeader();
public EntityHeader Header { get { return m_Header; } }
[JsonProperty]
private int Id { set { m_Header.Id = value; } }
[JsonProperty]
private int Checksum { set { m_Header.Checksum = value; } }
public string Name { get; set; }
public bool Hair { get; set; }
}
Thus, all the properties in the JSON can be read straight into the Entity object, but consumers of Entity objects have access to a "nicely encapsulated" EntityHeader property.
I haven't tested this, and it may even be kludgey, but it would technically work for me (OP). I am still interested in other answers!
Base on your example you could either; use the adapter pattern:
public class EntityJson
{
int Id { get; set; }
int Checksum { get; set; }
public string Name { get; set; }
public bool Hair { get; set; }
}
// quick/poor example
public class EntityAdapter : IEntity
{
public EntityAdapter(EntityJson model)
{
Header = new Header(); // and populate this objects fields
Name = model.Name; // populate other properties
}
public EntityHeader Header { get; set; }
public string Name { get; set; }
public bool Hair { get; set; }
}
Or abuse the fact that json.net ignores properties not available:
var entity = JsonConvert.Deserialze<Entity>();
var header = JsonConvert.Deserialize<EntityHeader>();
entity.Header = header;
I'm going to go ahead and post this answer which is a little bit too long for a comment, so please take this more as an extended comment than an actual attempt to answer your specific question. And of course, you know your requirements best so this is just my considered opinion :)
With that in mind, my advice is:
Don't do this.
I would instead create a simple DTO class that has a 1-1 relationship to the JSON being received; and I'd put all my validation attributes on the properties of that class.
Once I had deserialised the JSON into this simple DTO, I would then use a mapping layer of some kind (roll your own or use Automapper, etc) to map this DTO into a more meaningful structure such as your Entity class.
My reasoning behind this is because unless your Entity class is itself only a simple DTO (in which case it should be as simple as possible and ideally not be a composite) you are mixing OOP and concerns with data mapping concerns; whilst this in and of itself is not such a bad thing, it only serves to increase the complexity of your code.
Consider for example if your incoming JSON ends up with 30 or 40 properties, and you manage to figure out a way (maybe adapting some of the nice techniques from the other answers) to map it to the Entity class. But what about when something goes wrong - it's going to be much easier to reason about, and therefore debug, a process which you have much more control over; it's also going to be much easier to make special adaptations for odd edge cases where the serialiser behaviour just can't help you out
Granted it's a bit of work to write and maintain these DTOs but not that much - Webtools already does this for you
Reference: At the boundaries, Applications are not Object-Oriented
I am trying to serialize an instance of a class that inherits from DynamicObject. I've had no trouble getting the dynamic properties to serialize (not demonstrated here for brevity), but "normal" properties don't seem to make the trip. I experience the same problem regardless of serialization class: it's the same for JavaScriptSerializer, JsonConvert, and XmlSerializer.
public class MyDynamicClass : DynamicObject
{
public string MyNormalProperty { get; set; }
}
...
MyDynamicClass instance = new MyDynamicClass()
{
MyNormalProperty = "Hello, world!"
};
string json = JsonConvert.SerializeObject(instance);
// the resulting string is "{}", but I expected to see MyNormalProperty in there
Shouldn't MyNormalProperty show up in the serialized string? Is there a trick, or have I misunderstood something fundamental about inheriting from DynamicObject?
You can use the DataContract/DataMember attributes from System.Runtime.Serialization
[DataContract]
public class MyDynamicClass : DynamicObject
{
[DataMember]
public string MyNormalProperty { get; set; }
}
This way the serialisation will work no matter what serialiser you use...
Just use JsonProperty attribute
public class MyDynamicClass : DynamicObject
{
[JsonProperty("MyNormalProperty")]
public string MyNormalProperty { get; set; }
}
Output: {"MyNormalProperty":"Hello, world!"}
Let's assume I have got a class like:
public class SomeObject
{
public Guid InternalId { get; set; }
public string Address { get; set; }
}
I store instances of this object into the ASP.NET profile. It get's XML serialized and everything is fine. Now I want to reduce the size of the profile, and I want to replace the long propertynames by something shorter:
public class SomeObject
{
[XmlElement("id")]
public Guid InternalId { get; set; }
[XmlElement("ad")]
public string Address { get; set; }
}
New objects get serialized just fine, and short, and everything. However: the XmlSerializer cannot deserialize the old XML files. Is there any hook I can apply to change a classes signature, but still be able to deserialize old instances.
I have the eventhandler XmlSerializer_UnknownElement, and then I can set the value of the target property myself, however I only have the value of the element as a string, so I should parse it by myself which is quite error-prone.
Two answers, one I know will work, the other I'm not sure.
1) Implement the IXmlSerializable interface in your class. Its very easy to do, and gives you complete control over how the class is serialized and deserialized.
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
2) Not sure if this will work, but try adding another XmlElementAttribute tag to your class properties. It compiles, but I'm not sure if it'll work.
public class SomeObject
{
[XmlElement("InternalId")]
[XmlElement("id")]
public Guid InternalId { get; set; }
[XmlElement("Address")]
[XmlElement("ad")]
public string Address { get; set; }
}