I've done a lot of serialization development lately, mostly for sending objects over sockets, but I've run into an interesting question: Is it possible to send just a few of the properties from an object through a serializer?
My envisioned scenario is this: You have some sort of "state" object for each client, consisting of many properties (strings, ints, bools, etc). When your client first connects, the entire state object is serialized via an Xml or Binary serializer, and sent over the socket, to be recreated on the other side. Now both client and server have identical state objects. Your server then needs to change the state, and does so by simply setting one of the state object's property. The socket (either hooked to the state's events, or part of the state object itself) could synchronize the two states by reserializing the entire object, but it seems like a single "property change" object would do.
Obviously, this could be implemented manually. But it seems like a serializer should be able to serialize just a single property, and apply it like a patch on the other side. Does anyone know if this is possible, or would I have to write the entire thing from scratch?
With XmlSerializer (and protobuf-net, for a binary equivalent, since protobuf-net adopts most of XmlSerializer's patterns) you could do this by having a method:
public bool SouldSerializeFoo() {
return fooIsDirty;
}
public string Foo {get;set;}
for each property Foo - but you'd need to maintain the "what is dirty" manually in your own code (perhaps in the set). Lots of work; I've done a diffing serializer in the past - it was a real PITA, to be honest. I should also note that the [XmlIgnore] public bool FooSpecified {get{...} set{...}} pattern does the same thing, but for what you want, ShouldSerialize* is more appropriate.
As an addition to Marc's answer, here's the MSDN docs on the ShouldSerialize* methods
Related
I asking this mostly to see if there is something that ressembles what I am trying to achive.
My ultimate goal is to serialize an object graph, keeping references, but making all the properties accessible via a Path of sorts.
My first thoughts were something like dictionary and recursively loop through all the objects properties/fields, and if the value is different than the Default one, try and serialize if its a primitive, otherwise keep going till the type can be serialized.
I need to support Types not marked as [Serializable], and to be able to add custom serialization, similiar to how surrugates work in the BinaryFormatter.
Is there a serializer that works remotely like I said?
Or what other caveats can you think of, by this aproach?
Note: The serialization Size is not a big issue nor is the speed that it serializes/deserializes, at least for now.
An example of what I want to to is something like this :
SerializationContext.GetValue["root/Prop/X"] returns me the X value.
This needs to work with .Net 3.5, and it should serialize based on field/property name.
I have an C# object that hold a big list (10-100MB) and some other properties. I want to serialize the object, but I don't want to serialize the list. is there any easy way to do that?
Thanks!
Since it is tagged xml, this could be as simple as adding [XmlIgnore] to the appropriate property:
[XmlIgnore]
public List<Foo> Items {get;set;}
Then just use XmlSerializer as normal.
If it needs to be controllable (sometimes yes, sometimes no) then an alternative is to add:
public bool ShouldSerializeItems() {
// your logic here
}
This pattern is recognised by many serializers, XmlSerializer included.
If you mean by serialization loading the object from database, then I can recommend NHibernate, you simply mark, you want to enable lazy-loading on the List and your object will return, with Items set to null (and if you are still in transaction, Items will load, after and only after attempting to access it; if you are out of transaction already, you will get a nullPointer exception I think)... but basically, Lazy-loading in any its kind is certainly a principle, you should keep an eye on.
EDIT: missed the tags, shame on me
I'm attempting to write a generic serializer using protobuf.net v2. However I'm running into some issues which make me wonder if perhaps what I'm doing is impossible. The objects to be serialized are of an indeterminate type to which I don't have access so I'm attempting to walk the object and add its properties to the type model.
var model = TypeModel.Create();
List<string> propertiesToSerialize = new List<string>();
foreach (var property in typeToSerialize.GetProperties())
{
propertiesToSerialize.Add(property.Name);
}
model.AutoAddMissingTypes = true;
model.Add(typeToSerialize, true).Add(propertiesToSerialize.ToArray());
For simple objects which contain only primitives this seems to work just fine. However when working with an object which contains, say, a Dictionary<string,object> I encounter an error telling me that no serializer is registered for Object.
I did look at serializing a Dictionary<string,object> in ProtoBuf-net fails but it seems the suggested solution requires some knowledge and access to the object being serialized.
Any suggestions on how I might proceed?
protobuf-net does not set out to be able to serialize every scenario (especially those dominated by object), in exactly the same way that XmlSerializer and DataContractSerializer have scenarios which they can't model. In particular, the total lack of metadata in the protobuf format (part of why it is very efficient) means that it is only intended to be consumed by code that knows the structure of the data in advance - which is not possible if too much is object.
That said, there is some support via DynamicType=true, but that would not currently be enabled for the dictionary scenario you mention.
In most cases, though, it isn't really the case that the data can be anything; more typically there are a finite number of expected data types. When that is the case, the object problem can be addressed in a cleaner way using a slightly different model (specifically, a non-generic base-type, a generic sub-type, and a few "include" options). As with most serialization, there are scenarios were it may be desirable to have a separate "DTO" model, that looks closer to the serialization output than to your domain model.
A final note: the GetProperties()/Add() approach is not robust, as GetProperties() does not guarantee any particular order to the members; with protobuf-net in the way you show, order is important, as this helps determine the keys to use. Even if the order was fixed (sorting alphabetically, for example), note that adding a member could be a breaking change.
Let's say we have a business object, let's call it a Foo, which contains an ordered list of Bars. We pass this Foo around as XML.
We have a class which deserializes a Foo XML node (FooXMLDeserializer) which itself uses a class which deserializes the child Bar XML nodes (BarXMLDeserializer).
Now, I'm adding some functionality to the BarXMLDeserializer that maintains some state such that if FooXMLDeserializer is called on two separate Foo nodes without reseting the BarXMLDeserializer's state, the results may be invalid. BarXMLDeserializer does not know when it has processed the final Bar in a Foo.
Is there some way that I can design the BarXMLDeserializer class to communicate to developers working on consuming classes that it has state and must be reset for each Foo?
Further info:
My change solves a minor enough problem in our code that I won't be able to convince my manager to let me spend X days redesigning the whole system to nicely handle this case.
If it matters, BarXMLDeserializer keeps is state in a BarStateTracker class which is internal to it.
Programming in C#, but looking for a more general solution.
Thanks.
Expose your serializer only as a static method:
// no public constructor, etc
var deserializer = BarXMLDeserializer.CreateNew();
Then, when you have finished deserializing data, mark a field in your object. If the field is set, throw an exception if the same instance is used to deserialize more data when the deserialize method is called.
if(IsInstanceExhausted)
throw new InvalidOperationException("You must use a fresh instance.");
They'll figure it out after their first exception. In addition, mark your class as IDisposable so that code naturally uses using statements:
using(var deserializer = BarXMLDeserializer.CreateNew())
{
}
The list goes on of additional ways. ALTERNATIVELY, you could simply design your Deserializer to clear it's state or reset after a deserialization attempt, or to clear the state at the beginning of a deserialization attempt.
Right now, I'm currently serializing a class like this:
class Session
{
String setting1;
String setting2;
...etc... (other member variables)
List<SessionAction> actionsPerformed;
}
Where SessionAction is an interface that just has one method. All implementations of the SessionAction interface have various properties describing what that specific SessionAction does.
Currently, I serialize this to a file which can be loaded again using the default .Net binary serializer. Now, I want to serialize this to a template. This template will just be the List of SessionActions serialized to a file, but upon loading it back into memory at another time, I want some properties of these SessionActions to require input from the user (which I plan to dynamically generate GUI controls on the fly depending on the property type). Right now, I'm stuck on determining the best way to do this.
Is there some way I could flag some properties so that upon using reflection, I could determine which properties need input from user? Or what are my other options? Feel free to leave comments if anything isn't clear.
For info, I don't recommend using BinaryFormatter for anything that you are storing long-term; it is very brittle between versions. It is fine for short-lived messages where you know the same version will be used for serialization and deserialization.
I would recommend any of: XmlSerializer, DataContractSerializer (3.0), or for fast binary, protobuf-net; all of these are contract-based, so much more version tolerant.
Re the question; you could use things like Nullable<T> for value-types, and null for strings etc - and ask for input for those that are null? There are other routes involving things like the ShouldSerialize* pattern, but this might upset the serialization APIs.
If you know from start what properties will have that SessionAction, you must implement IDeserializationCallback and put to those props the attribute [NonSerialized]. When you implement the OnDeserialization method you get the new values from the user.