protobuf-net: properties versus fields - c#

In our project, we have a data transfer object (DTO) class which is decorated with a [ProtoContract] attribute, and all of its members are public properties decorated with [ProtoMember] attributes - except that one of the members is a public field (by accident). Now we want to change the one public field into a property. Can this have an impact about the implicit protobuf contract? (We want to avoid breaking changes, and I suppose that this change is non-breaking, but I want to be sure.)

Yes, that's absolutely fine; protobuf-net won't care, and the serialized payload will remain identical.

Related

C# - Does it make sense to have an empty interface with a class level attribute to specify common behavior?

I have several classes that serve as data transfer objects (in C#). These classes are all serialized using JSON.Net to be sent to an API. Unfortunately, the property names specified in the API don't have standardized naming conventions. Some properties use camel casing, some use snake casing, some all lowercase, and so on. So, I need to account for this when serializing the DTOs to JSON. Also, when properties are null, I want them to be excluded from the serialized JSON.
So, here was my solution. I created an empty interface called ISerializableDto and added class level attributes specifying that properties should be excluded when null and the default property naming strategy is snake casing.
[JsonObject(
NamingStrategyType = typeof(Newtonsoft.Json.Serialization.SnakeCaseNamingStrategy),
ItemNullValueHandling = NullValueHandling.Ignore)]
public interface ISerializableDto
{
}
All of my DTO classes inherit from this interface. When the naming convention for a property in one of the DTO classes is not snake cased, I just specify the property name explicitly through a property level attribute.
public class ExampleDto : ISerializableDto
{
public string SomeRandomPropertyName { get; set; } // This will serialize to "some_random_property_name"
[JsonProperty(PropertyName = "someRandomCamelCasedPropertyName")]
public string SomeRandomCamelCasedPropertyName { get; set; } // This will serialize to "someRandomCamelCasedPropertyName"
}
This all works fine. I can do a simple JsonConvert.SerializeObject(myDtoObject) and it behaves exactly as I intended. The property names are snake cased unless otherwise specified and null properties are excluded. But, I'm not confident this is the best way to go about doing this.
Does it make sense to have an empty interface with a class level attribute to specify common behavior?
I could remove the interface entirely and put the class level attributes on each DTO class. But, someone might miss it if they need to add a new DTO class later on. Or, I could even specify these behaviors in the JsonConvert.SerializeObject call. But my worry there is that some of the naming behavior is specified in the DTO class, and some is specified externally.
Is there some better way of doing this?
I would probably do this by creating an attribute [SerializableDto] that derives from JsonProperty and contains the settings that you want. Since all the rest of your specifiers (like for the property names) are done with attributes it seems more consistent. If you put it in an interface you create a more complex situation where some of the specification is done by implementing an interface while other related specification is done using attributes.
Have not checked whether or not JsonProperty is sealed. If it is then your situation is trickier. You might still be able to do it though using an attribute that dynamically attaches the Json attribute using TypeDescriptor.AddAttributes.

Reacting on serialize and deserialize of an instance

I have a class which i am serializing. I annotated it with [Serializable] and i am using binary serializer. Everything works fine.
But later i introduced new properties, which cannot be serialized (lets say they contain a lot of mess about GUI which does not need to be rembered). I can compute these properties based on other properties of class.
I need to do it two times, when I serialize - clean mess and enter stabile state ready for serialization. And deserialization - again compute all needed properties.
I need to react on 'events' instance is being serialized/deserialized.
However I can't find these events because I am not implementing the interface ISerializable or abstract class Aserializable but only class atribute [Serializable].
I do not know when class is being serialized because it is not the concern of this class; it is serialized as a field of another class.
Is there a way I can react on those events?
You can use OnDeserializedAttribute and its related attributes (OnSerializing, OnSerialized, OnDeserializing) to create special methods that are called during the serialization/deserialization process.
Build Custome Serialization by Implementing ISerializable. Use OnSerializingAttribute, to manipulate object before serilazation and OnDeserializingAttribute, to manipulate before deserialization.
Have you considered per chance the [XmlIgnoreAttribute] attribute? It will prevent a property to be serialized. No need to tamper withe the serialization workflow.
My bad, didn't realize you wanted to reload some property on deserialization. So why not serialize these? In an optional subObject, or whatever?

Auto implemented properties and serialization

I'm going through a lot of code and marking classes which I now want to persist with the Serialization attribute. I haven't written the binary serialization/deserization engine as yet so guess I will answer my own question once that's complete! - but thought I'd try get an earlier response here if that's OK. I've come across some code which contains a property such as:
public string Id
{
get;
set;
}
Does the "Id" get serialized? I understand that underneath the compiler auto creates a class member, but does this get serialized correctly (since all the data members of the class instance are written to storage)? It feels like it won't since you can't place the Serialized/NonSerialized attribute on properties.
Thanks in advance.
You can use the [field:NonSerialized] attribute to mark the backing field of events as being non-serializable, however it seems this is not possible with auto-properties. With auto-properties the backing fields will be serialized and the only way to prevent that behaviour is to transform them into regular properties and annotate the explicit backing fields with [NonSerialized] as normal.
As #John has pointed out in his comments, the BinaryFormatter (System.Runtime.Serialization.Formatters.Binary) will serialize your auto-generated backing field. You can use custom serialization by implementing the ISerializable interface and then decide for your class which values are serialized or not.

Serialize/deserialize objects - order of fields matters?

Is it possible that DataContractSerializer wrongly deserializes an object if the fields are not in the "correct" (whatever that means) order?
The classes that I try to serialize/deserialize do not have order-attributes placed on fields/properties. Yet one of my fields always gets deserialized as null even though it has a non-null value (it actually contains a list of strings).
When I moved two XML elements in serialized file around to match the order in another XML example (for which deserialization worked without problems) everything started to work.
This makes no sense to me but maybe someone knows better. ;)
To be eligible for correct serialization / serialization by the DataContractSerializer, all of the following must be true.
The class that must be serialized must have SerializableAttribute or DataContractAttribute set;
The properties and fields of the class that must be serialized require the DataMemberAttribute set;
The datatype of the serializable property or field must be serializable (i.e., have a public ctor and inherit ISerializable);
The class that must be serialized must implement IExtensibleDataObject;
Note: serializable fields can be either public or private.
Members must be in alphabetical order or you should use the Order-property of the DataMemberAttribute.
So, the order of the declaration does matter. If members are not in alphabetical order, they are skipped. Look up this answer at StackOverflow for an example, perhaps it applies to your case.

Interface "not marked with serializable attribute" exception

I have a very odd exception in my C# app: when trying to deserialize a class containing a generic List<IListMember> (where list entries are specified by an interface), an exception is thrown reporting that "the type ...IListMember is not marked with the serializable attribute" (phrasing may be slightly different, my VisualStudio is not in English).
Now, interfaces cannot be Serializable; the class actually contained in the list, implementing IListMember, is [Serializable]; and yes, I have checked that IListMember is in fact defined as an interface and not accidentally as a class!
I have tried reproducing the exception in a separate test project only containing the class containing the List and the members, but there it serializes and deserializes happily :/
Does anyone have any good ideas about what it could be?
Edit:
We are using a BinarySerializer; and I repeat, when extracted to a test project the class serializes happily. So I do not need a workaround to serialize a class containing a List<IThing>, as in general this works fine (as long as the actual classes implementing IThing are serializable); what I am looking for is reasons why it might not work this particular time...
I have now put in a workaround (serializing each list member individually, together with the number of entries, and recreating the List by hand), but would really like to find out what it could be for future reference.
It doesn't matter that the class backing the interface is serializable. Interfaces cannot be serialized, period.
In order to deserialize, the serializer needs to be able to instantiate a concrete type, and it determines this type by reflecting on the fields/properties of the class-to-be-deserialized.
If the type of one of those properties is an interface, then it will never be able to construct a concrete type to assign to that member. All it sees is the interface, it has no idea which class originally implemented it when the data was serialized.
If you want the class to be serializable, then every class in the object graph must be a concrete type. No interfaces allowed.
(Postscript: Actually, I sort of lied, the BinaryFormatter can serialize/deserialize directly to/from interface types, but I strongly suspect that's not what's being used here.)
The Easy Way (Although ugly) Wrap your list:
public ListMemberCollection : List<IListMember>, ISerializable
{
// Implement ISerializable Here
}
The Alternative Way (Although better) AbstractBaseClass:
[Serializable]
public ListMemberBase : IListMember
{
// Implement abstract versions of everything
}
A possibility?: (On your other class)
class TheClassYoureSerializing
{
[Serializable]
public List<IListMember> list { get; set; }
}

Categories