I have an issue where an property needs to be serialized and deserialized using to different keys.
In the serializer, the property addresses the key trade:
'tradeId': { key: 'trade' },
This works when addressing the deserialization endpoint.
However, for serialization, the endpoint property is called trade-identifier, requiring the serializer reference to be changed to the following:
'tradeId': { key: 'tradeIdentifier' },
Is there any way to define seperate keys for serialization and deserialization in an Ember serializer?
Thanks to #handlebears for pointing me in the right direction here.
Simply adding a serialize method to the governing serializer file allowed me to reassign the data to the appropriate JSON property:
serialize(snapshot, options){
let json = this._super(...arguments);
json.tradeIdentifier = json.trade;
delete json.trade;
return json;
}
});
Related
I am working on Akka.net persistence and using MongoDb as the persistent store. One of the properties on the events that we persist is of custom struct type "Rational". We have configured a custom serializer for this Rational type that serializes rational type value into a decimal value. However, we don't see that custom serializer getting invoked at all. The MongoDb shows newly inserted document with rational value of type object instead of decimal.
Below is akka.hocon configuration;
akka {
actor {
serializers {
my-rational = "RationalTypePersistence.RationalSerializer, RationalTypePersistence"
}
serialization-bindings {
"RationalTypePersistence.Rational, RationalTypePersistence" = "my-rational"
}
}
}
In debugging session also, the breakpoints set in the custom serializer's "ToBinary" and "fromBinary" methods don't get hit. The breakpoint in the constructor get hits multiple times though.
The custom serializer is extending Akka.Serialization.Serializer, and has overriden Identifier, FromBinary, ToBinary properties/methods.
Are we missing any configuration ?
I have downloaded a sample code from github and run AtLeastOnceDelivery.sln
Every new run it is sending messages with it. And if I change the message namespace it shows an error started with
Error loading snapshot [SnapshotMetadata<pid: delivery, seqNr: 0, timestamp: 2018/09/24>], remaining attempts: [0]
If I could clear the persistence hopefully it will accept then changed namespace and restart messaging id.
By default, all snapshots are stored as files directly in ./snapshots directory of the application, while events are stored in the memory. Because of that you should consider using a one of the akka.persistence plugins for the production purposes.
Your problem happens because you're using akka.net default serializers (dedicated for networking) which are not very version tolerant - so changing any fields, their types, class names or namespaces makes previous version of the class non-deserializable - and in future will be subject to change. This is also why it's strongly discouraged to use default serializers for persistence.
How to make a custom Akka.NET Serializer
While there are plans to improve serializers API, at the current moment (Akka.NET v1.3.9), to make your own serializer you need to simply inherit from Akka.Serialization.Serializer class:
public sealed class MySerializer : Serializer
{
public MySerializer(ExtendedActorSystem system) : base(system) { }
public override int Identifier => /* globaly unique serializer id */;
public override bool IncludeManifest => true;
public override byte[] ToBinary(object obj)
{
// serialize object
}
public override object FromBinary(byte[] bytes, Type type)
{
// deserialize object
}
}
Keep in mind that Identifier property must be unique in cluster scope - usually values below 100 are used by akka.net internal serializers, therefore it's better to use higher values.
How to bind serializer to be used for a given type
By convention Akka.NET uses empty interfaces to mark message types that are supposed to be serialized. Then you can setup your HOCON configuration to use a specific serializer for a given interface:
akka.actor {
serializers {
my-serializer = ""MyNamespace.MySerializer, MyAssembly""
}
serialization-bindings {
""MyNamespace.MyInterface, MyAssembly"" = my-serializer
}
}
Where MyInterface is interface assigned to a message type you want to serialize/deserialize with MySerializer.
I have a problem with mirage.
I am defining a serializer extending ActiveModelSerializer with serializeIds: 'always', in this case the model is serialized with the relations models ids.
But when i want include some model in the serialized content i use include: ['someModel'], in that case the someModel is included succesfully, but the ids of the rest of relationships are ignored.
How can i include the ids too?
Hm, I believe this is the default behavior. To override this you could call super on the Serializer's serialize method and ensure the ids are added to the payload:
serialize(post, request) {
let json = Serializer.prototype.serialize.apply(this, arguments);
json.post.commentIds = post.commentIds;
return json;
}
When I set Json.NET to serialize with TypeNameHandling set to TypeNameHandling.Auto, it correctly sets $type for child properties of an object but does not do so for the root object being serialized. Why?
Please consider the following repro:
public class Animal
{
public Animal[] Offspring { get; set; }
}
public class Dog : Animal {}
Animal fido = new Dog
{
Offspring = new Animal[] { new Dog() }
};
var json = JsonConvert.SerializeObject(fido,
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
The Json emitted into the json variable is:
{
"Offspring": [{
"$type": "MyApp.Dog, MyApp",
"Offspring": null
}]
}
The Json.NET Documentation says that for TypeNameHandling.Auto the behavior is:
Include the .NET type name when the type of the object being serialized is not the same as its declared type.
My question is - Why does fido not have
"$type": "MyApp.Dog, MyApp", like its puppy? :)
UPDATE: I've found out from the accepted answer to this question that I can force $type to be added by doing this:
var json = JsonConvert.SerializeObject(fido,
typeof(Animal),
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
Formatting = Formatting.Indented
});
But my question still holds - Why does Json.NET not do this by itself as per the documentation?
Short answer: it doesn't because it can't.
As you stated in your question, setting TypeNameHandling to Auto directs Json.Net to include the .NET type name when the actual (run-time) type of the object being serialized is not the same as its declared (compile-time) type. In order to do that, Json.Net needs to know both types for every object.
For everything inside the root object, this is straightforward: just get the runtime type of the root object via GetType(), then use reflection to get all of its declared properties and their types, and for each one compare the declared type to the actual type to see if they differ. If they do, output the type name.
But for the root object itself, Json.Net doesn't have access to both types. All the information it has is the object referenced by fido, whose runtime type is Dog. There's no way for Json.Net to discover that the fido variable was declared as Animal, unless you provide that context somehow. And that is exactly why Json.Net provides overloads of SerializeObject which allow you to specify the compile-time type of the object being serialized. You must use one of these overloads if you want the TypeNameHandling.Auto setting to work for the root object.
Brian is absolutely correct, Json.NET has no way of knowing the compile-time declared type of the object it's being passed as the value parameter is declared as an object. The easy fix for this was if Json.NET added generic serialize methods so that the compile-time declared type would automatically flow over to Json.NET but the library's author has decided against my proposal for this here.
As an alternative, I've wrapped all my json (de)serialization needs in a JsonHelper class with generic serialize methods which use the typeof expression to automatically pass the compile-time declared type of the value to be serialized.
Newer versions of Json.Net allow you to pass the expected type to the serialize method
ser.Serialize(stream, rootObject, typeof(BaseClass));
You can pass the base class to the serialize method and TypeNameHandling.Auto will write the $type if the object and expected type do not match.
Is there any switch that instructs svcutil to generate DataContract properties with their names as defined in code? For example when I create a proxy which uses the following DataContract:
[DataContract(Namespace = "http://schemas.mynamespace.com/2012/08")]
public class MyDataContract
{
[DataMember(IsRequired = true, Order = 0)]
private int _id;
public int Id
{
get { return _id; }
set { _id = value; }
}
}
I get this DataContract on the proxy generated class:
public partial class MyDataContract : object
{
private int _idField;
[System.Runtime.Serialization.DataMemberAttribute(IsRequired=true)]
public int _id
{
get
{
return this._idField;
}
set
{
this._idField = value;
}
}
}
The order property of the DataMemberAttribute is always ommited as well for the first 3 properties and a MessageContract ommits an IDisposable implementation.
Well, I cannot comment on the omitted order, but I may be able to help on the rest:
One usually specifies the DataMember attribute on the property, not on the field. The data-contract itself does not distinguish between a property and a field, but it knows the name, type, if it is mandatory, etc. etc.
Added: What Chris said: With [DataMember(Name="whateveryouwant")] you'll be able to set a name different from the field/property name. I do not like such usage, though, but it is helpful when refactoring code, but still keeping the API compatible.
Only other DataContract (and some intrinsically supported) types are serialized to/from messages. IDisposable seems not to be one.
Serializing the inherited IDisposable of a MessageContract would not make any sense. A message-contract is the .NET representation of a SOAP message. It literally has nothing else to do but to provide a 1:1 mapping between what is in the SOAP message XML, and the accessible .NET types.
A message is part of a ServiceContract, in that it specifies which kind of message must be sent to a certain operation to be a valid invocation, and another (response-)message contract specifies how the data, that the operation returns, will be structured. Nothing else; it is a data-aggregate.
If you want to capture the result of a service-operation on the client, and for convenience automatically send a message back upon going out of scope (or for instance unregistering from a service), you will have to implement this on the client-side. Be aware, however, that the service must not require this to happen (due to lost connections, crashes, etc.).
Use the name property on DataMember attribute
Such as:
[DataMember(Name="myname")]