Most flexible serialization of objects to be saved to a database - c#

Give an object similar to:
public class MyObject : IInterfaceA
{
public IEnumerable<IInterfaceB> MyList{get; set}
public MyComplexObjectX{get; set;}
public MyComplexObjectY{get; set;}
}
which may have a fairly complex graph.
Does anybody know the best means of serializing this whereby namespace changes would not be an issue on deserialization? Would Json be the way to go perhaps?
Secondly there is also a good bit of use of lists of interfaces, generics etc. Im happy to use known types with DataContractSerializer but I think I will have the issue with namespace changes then.
Performance, size of serialized object etc are not an issue for me right now.
Thanks.

Related

How to deserialize JSON to immutable object in ASP.net

So I've been trying to convert JSON to an immutable object for an API, and I've just hit wall after wall with it. The System.Text.Json.Serialization.JsonConstructor attribute doesn't seem to work at all. Here's an example of the record.
using System.Text.Json.Serialization;
namespace App.Foobar{
public record Foo
{
[JsonConstructor]
public Foo(decimal bar){
Bar = bar;
}
[JsonIgnore]
public decimal Bar {get;}
}
}
And the JSON I'm passing in;
{
foo: {
bar: 12
}
}
So how would I deserialize JSON into this class? Is there something I'm doing wrong with the JSON I'm passing in, or is it a problem in the class?
I need to preserve the JsonIgnore attribute, as well.
Your problem is that the JsonIgnoreAttribute applies to both serialization and deserialization, and this is something you cannot change.
So in short, if you have [JsonIgnore], you won't be able to get its value from deserializing JSON data, no matter what.
As a workaround, you cuold play with read-only properties, or null-valued properties or even default-valued properties since you can set serialization options for these. See this article for more information.
In general, you can read about immutable types as Microsoft has envisioned them to make sure you don't try to do weird stuff.
AutoMapper Workaround
You can also work around this using AutoMapper. You can have a private record class that does not ignore the bar property and then map it to a public record class that does ignore said property.
And actually, I don't know if AutoMapper works with record. Test it out. If not, do the mapping yourself.

C# Serialization - Could not find the assembly

I am working on C# TCP Server-Client programming. My problem is simple but somehow i couldnt figure it out.
I have an object i would like to seriliaze this object send over socket and deserialize client side. But problem is with deserializing. I serialize object with binaryformatter. Actually i am getting the actual byte array i should. But somehow while deserializing i am getting
System.Runtime.Serialization.SerializationException: 'Multi Server,
Version=1.0.0.0, Culture=neutural, PublicTokenKey=Null' assembly could
not found.
When i try to deserialize on the server side after serializing it has no problem.
I tried to customize binder which didnt work also. I really appriciate if somebody could help me.
If I'm guessing correct, you have 2 projects - "Multi Client" and "Multi Server".
You serialize object defined in "Multi Server" and then you have a copy of that class in "Multi Client".
So you serialize an object "MultiServer.SomeClass" and then you want to make it a "MultiClient.SomeClass". This ain't gonna work.
You need to create a common dll project (let's name it "MultiCommon", where you will put your class, and reference it by both "MultiServer" and "MultiClient". In this way, you will serialize and deserialize not "MultiServer.SomeClass" but "MultiCommon.SomeClass".
It sounds like you're using BinaryFormatter, in which case frankly I think the most valuable advice would be: don't do that. The data format of BinaryFormatter is fundamentally tied to your exact implementation details, making it very hard to a: have different code at different ends (meaning: deployment is very hard and brittle - everywhere needs to change at the same time), or b: revise the implementation over time.
Frankly, I would strongly advise looking at alternative serialization tools. I'm hugely biased, but protobuf-net works very well for this type of scenario; it is still "binary" (meaning: not text), but it isn't tied to the internal implementation details. It is fast (usually much faster than BinaryFormatter), efficient (usually much less bandwidth required than BinaryFormatter), free, and is usually very easy to apply to an existing object model; it usually means going from this:
[Serializable]
public class Custom {
public int Id {get;set;}
public string Name {get;set;}
// ...etc
}
to this:
[ProtoContract] // you can keep the [Serializable] for compat if you want
public class Custom {
[ProtoMember(1)]
public int Id {get;set;}
[ProtoMember(2)]
public string Name {get;set;}
// ...etc
}

WCF Contracts without the annotations [duplicate]

This question already has answers here:
Is DataContract attributes required for WCF
(4 answers)
Closed 9 years ago.
I was wondering if there is any way to define a WCF Contract class without using the [DataContract] and [DataMember] annotation. The reason is that domain model we currently have is fairly clean so we would like to keep it this way. Whats the best practice here? Create a Transfer object and copy the domain model object into a transfer object (that has the required annotations and is the Contract transfered between Client and Server)? Or somehow not annotate the object model and specify the contract in a different way.
If you do not add any serialization attributes to your class, and use it as part of a WCF service contract method, WCF will use the default serialization rules to produce a data contract anyway. This means that the class will implicitly become a [DataContract] every public property that has both a get and set accessor will implicitly become a [DataMember].
The only time you need to apply the attributes is if you want to override the default behavior, e.g. hiding some attributes, applying namespaces, etc. It's generally considered good practice to do so anyway, because relying on the default behavior might get you in trouble later. (It also makes it explicit that your class is meant for use by WCF). But it's not strictly required, as long as the default behavior meets your needs.
In response to your follow-up:
As far as I know there's no completely external way to change the serialization behavior of the DataContractSerializer for a given class; every option requires at least some level of attribution on the class being serialized. As #Yair Nevet describes below, my preferred method for turning existing domain objects into data contracts is the MetadataType attribute.
Alternatively, you can bypass the whole issue by doing what you suggested in your question: don't serialize your domain objects, but create custom DTO objects and serialize them. I tend to do this whenever I'm using the Entity Framework, for example, because serializing those can be tricky. This is also a good approach to take if your domain objects have lots of behaviors built into them -- you get a clear separation of "data being passed around" vs. "objects participating in my business logic."
You often end up with lots of redundant code, but it does achieve your goal of zero changes to your existing objects.
You can use the MetadataType attribute and a metadata model class in order to separate the annotations from your model.
For example:
[MetadataType(typeof(MyModelMetadata))]
public class MyModel : MyModelBase {
... /* the current model code */
}
[DataContract]
public class MyModelMetadata {
[DataMember]
public string Name { get; set; }
}
WCF is capable of serializing your objects without the attributes. The attributes are there to allow for customization. For example, the two classes will serialize identically by the DataContractSerializer:
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
[DataContract]
public class Customer
{
[DataMember] public string FirstName { get; set; }
[DataMember] public string LastName { get; set; }
}
It is worth mentioning that you really should mark your class with the attributes. They aren't as "messy" as you think. It will actually save you from headache in the future. For example:
[DataContract(Name = "Customer")]
public class Customer
{
[DataMember(Name = "FirstName")]
public string FirstName { get; set; }
[DataMember(Name = "LastName")]
public string LastName { get; set; }
}
In the previous code sample, I explicitly set the names of the class and members. This will allow me to refactor the names without breaking consumers code. So, if someone decides that my class should be named CustomerDetail instead of Customer, I can still leave the name as Customer so that consumers of my service continue to work.
You could always use DTOs. Make a separate class that has everything that is needed to serialize your objects. Then project your domain model on to the DTO. You could use something like AutoMapper to make this process a little easier.
Regarding Performance
Unless you have hundreds, probably thousands, or objects or a very large number of properties per class, the act of converting to and from DTOs probably isn't that much performance overhead.
If you are using something like EF, and you are not serializing every property, you might even be able to reduce some overhead by projecting your EF query directly on to your DTOs.
This is kind of a dramatic case, but I had (poorly designed) database models with 50+ properties per type. By changing to DTOs that only have the 10-15 properties I cared about, I was able to almost double the performance of a WCF service.

Serializing extra elements into a IDictionary instance with MongoDb's C# driver

I have recently tried to play around with MongoDb's serialization. Basically, I am trying to use the driver's serializer to store my models while at the same time attempting to avoid any dependencies between my well-known model classes and 10gen's MongoDb C# driver (v1.2, if it matters).
This, by itself, is no issue. What is problematic however is that there can be (dynamic) information stored for some of the objects side by side to well-known elements. I could do this by using the [BsonExtraElements] attribute, but as I said above, I am trying to avoid coupling my models to MongoDb. Model classes that can have this behaviour, implement a certain interface:
public interface IHaveMoreInformation
{
IDictionary<string, object> Extra { get; set; }
}
For this, I have tried to write a custom convention that gets registered in the convention profile at application startup:
public sealed class ExtraElementsConvention : IExtraElementsMemberConvention
{
#region Implementation of IExtraElementsMemberConvention
public string FindExtraElementsMember(Type type)
{
return typeof(IHaveMoreInformation).IsAssignableFrom(type) ? "Extra" : null;
}
#endregion
}
This is where the problem starts. The driver expects a BsonDocument property (again, I don't want to couple). I was hoping there is a way to work around this and serialize this additional information into an IDictionary<string,object> instance.
I am helpful for any ideas to achieve this.
Thanks in advance,
Manny
After looking into the driver's inner workings, I've decided to take the matter to mongoDB's issue tracking system. Until now (1.3.1), the driver seems very keen on only accepting a BsonDocument property for extra elements; this would effectively couple models to types declared by the driver, which is a bit of a pain when you decide to switch technologies.
The issue is currently being tracked here:
https://jira.mongodb.org/browse/CSHARP-395
Hopefully this improvement will find its way into 1.4 and help people looking to achieve something similar in the future.

C# How do you solve a circular object reference

I've run into what i belive could be a major issue for my code design and i was hoping someone here could explain to me how i would work around the issue.
I have 2 classes which each have a property of the other class creating a circular reference. I plan on serializing these classes and using XSLT to format the output but i'm assuming this will fail due to the circular reference.
Example
public class Book
{
public BookShop TheShop = new BookShop();
}
public class BookShop
{
list<Book> Books = new list<Book>();
}
So from this example each book will be in a bookShop and each bookshop will have many books. If i serialize the bookshop it will then serialize each book which then serialize a bookshop and so on round and round. How should i handle this?
Tag TheShop with an attribute to prevent its serialization.
[XmlIgnore] with the default serializer.
http://www.codeproject.com/KB/XML/GameCatalog.aspx
Probably just a problem with your example, not your real code: Don't use public fields but properties. I think XmlSerializer doesn't even serialize public fields.
Add [XmlIgnore] to the TheShop property to prevent it from being serialized.
You can then set it manually when deserializing.
Best practice would be to have the BookShop class implement an interface (IBookShop) and then have the Book class store the interface not the concrete class. You should also make BookShop into a property in the Book class:
public class Book
{
public Book(IBookShop bookShop)
{
TheStop = bookShop;
}
[XmlIgnore]
public IBookShop TheShop { get; set; }
}
public interface IBookShop
{
void SomeMethod();
}
public class BookShop : IBookShop
{
list<Book> Books = new list<Book>();
public void SomeMethod()
{
}
}
If you're going to use System.Xml.Serialization.XmlSerializer, you should decorate TheShop with System.Xml.Serialization.XmlIgnoreAttribute:
public class Book
{
[System.Xml.Serialization.XmlIgnore]
public BookShop TheShop;
}
That is, assuming the BookShop is the root object you wish to serialize. MSDN
First you need to check whether this is really a problem. If you always care about a bookshop when you have a book, and you always care about all the books a bookshop has, then it's perfectly sensible to have the whole graph serialised. This doesn't result in an infinite loop, because the serialisation uses an identifier to indicate a reference to an object already serialised (there is a bug if you do an XML serialisation of a graph with a circular reference in its types, but that's a bug rather than inherent to the problem of serialising XML, as the fact that it can be resolved proves, see Why do I get a "System.StackOverflowException was unhandled " exception when serializing? on that).
So, maybe you don't want to do anything here at all, and you're fine as you are.
Otherwise, the question is - just what do you want to serialise? Most suggestions so far have been to not serialise the TheShop property. This could be fine, or it may be useless if you will need to later access that shop.
If you have some sort of identifier (id number, uri) for each shop, then you could perhaps memoise - access to TheShop looks first at whether a private _theShop is null, and if it is, loads the relevant object into _theShop based on that identifier. Then you just need to serialise the identifier, not the full object.
Finally, if you are using XSLT to format the output to some other specification (whether XHTML for display, or something else) you may find it simpler just to roll your own XML serialisation. While this is a more complicated task in many ways, the fact that the XML produced by serialisation isn't particularly convenient for reformatting for display may mean that overall it's simpler this way. Indeed, if this is your only reason for serialising (you will never deserialise from the XML produced) then it may be much easier, as you need only consider what the XML for display needs, and not worry about anything else. Hence serialising may not be the best approach at all, but simply a ToXml() method, or a WriteBookToXml() method in another class.

Categories