Chris
Chris

Reputation: 2481

Redis states that classes marked DataContract are not serializable?

I have the following code:

[DataContract(Namespace = "removed")]
public class FootballPlayer
{
    /// <summary>
    /// Id of the player.
    /// </summary>
    [DataMember]
    public int Id { get; set; }

/// <summary>
/// Name of the player.
/// </summary>
[DataMember]
public string Name { get; set; }

And when I try to populate my redis cache, I get the following error:

Additional information: Type  'FootballApp.PlayerBase.Contract.FootballPlayer' in Assembly 'FootballApp.PlayerBase.Contract, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.

Is there anything I should do to tell Redis to accept the DataContractSerializer as an 'accepted' serializer(?) for want of a better term?

I don't want to have to go back through all my classes and mark as [Serialiazble] - I expect (As it was fine for AppFabric) that [DataContract] and [DataMember] to do that for me...

Upvotes: 1

Views: 1070

Answers (1)

Christian.K
Christian.K

Reputation: 49260

Redis itself surely doesn't know about the DataContractAttribute, or even .NET as such.

StackExchange.Redis, AFAIK, doesn't know about it either, that is it has no built-in support for it - at least a search in the GitHub repository doesn't yield a single hit.

Here is what I have done to store "DataContract objects" in Redis using StackExchange.Redis - serialize/deserialize them manually:

 private static byte[] GetBuffer<T>(T obj) {
     using (var m = new MemoryStream()) {
         var ser = new DataContractSerializer(obj.GetType());
         ser.WriteObject(m, obj);
         return m.ToArray();
     }   
 }

From that byte-Array you can then construct a RedisValue instance, which is the "primitive" used by StackExchange.Redis to handle values being stored/retrieved from Redis.

Speaking of retrieval, you'll need the reverse function to deserialize a byte-Array back to an object instance:

 private static T GetObject<T>(byte[] buffer) {
     using (var m = new MemoryStream(buffer)) {
        var ser = new DataContractSerializer(typeof(T));
        return (T)ser.ReadObject(m);
     }
 }

You may want to hide this stuff behind some abstraction or extension methods, of course.

Finally, you might want to reconsider your design as such, however. Depending on your application it might be valuable to not store complete object (graphs) as blobs in redis, but rather individual attributes as single keys (and associated values). Thus, you will not have the cost of serializing/transfering/deserializing a whole chunk of bytes around if you just need a single (or a couple of) attribute(s) - of course you might have more network roundtrips. As I said, it depends on your application.

Additionally, you can use Redis' API (or even LUA scripts) to effeciently manipulate and work with your data without even transfering it in the first place. You could use Redis' data types or a naming scheme (e.g. users.<name>.age) to achieve such.

Upvotes: 4

Related Questions