Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StackExchange.Redis casting RedisValue to byte[] via "as byte[]" returns null

I'm trying to create a Redis provider for Strathweb.CacheOutput.WebApi2, but trying to convert from a byte[] -> RedisValue -> byte[] is returning null.

I can manually set the object type as byte[] instead of var / RedisValue and it will correctly return the value as a byte[], but after it has been set as a RedisValue its failing to convert it to a byte[].

His Interface has the Get always return an object so I can't force the type or use a separate call without having to modify the interface.

If I try to do an result as byte[] I get Cannot convert type 'StackExchange.Redis.RedisValue' to 'byte[]' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion

If I try to do a (byte[])result I get Cannot cast 'result' (which has an actual type of 'StackExchange.Redis.RedisValue') to 'byte[]'

Is there something I'm missing or am I going to have to hack it in somehow by checking what type of data its looking for based on the key?

Here is the interface:

namespace WebApi.OutputCache.Core.Cache
{
    public interface IApiOutputCache
    {
        void RemoveStartsWith(string key);
        T Get<T>(string key) where T : class;
        object Get(string key);
        void Remove(string key);
        bool Contains(string key);
        void Add(string key, object o, DateTimeOffset expiration, string dependsOnKey = null);
        IEnumerable<string> AllKeys { get; }
    }
}

And here is how its called:

        var val = _webApiCache.Get(cachekey) as byte[];
        if (val == null) return;

Edit: Adding examples of the API I implemented using both ServiceStack.Redis v3 (working atm as it just uses object and StackExchange.Redis which is not working)

https://github.com/mackayj/WebApi.OutputCache.Redis.ServiceStack

https://github.com/mackayj/WebApi.OutputCache.Redis.StackExchange

like image 884
John Avatar asked Oct 03 '14 17:10

John


2 Answers

The following code using StackExchange.Redis can set/get value of generic type and convert RedisValue to byte[] in process, it should work fine for any serializable type.

    public static void SetItem<T>(string key, T value)
    {

        IDatabase redDb = GetDB();
        redDb.StringSet(key, ToByteArray<T>(value));
    }

    public static T GetItem<T>(string key)
    {
        IDatabase redDb = GetDB();
        RedisValue redisResult = redDb.StringGet(key);
        T objResult = FromByteArray<T>(redisResult);
        return objResult;
    }

   public static byte[] ToByteArray<T>(T obj)
   {
        if (obj == null)
            return null;
        BinaryFormatter bf = new BinaryFormatter();
        using (MemoryStream ms = new MemoryStream())
        {
            bf.Serialize(ms, obj);
            return ms.ToArray();
        }
    }

    public static T FromByteArray<T>(byte[] data)
    {
        if (data == null)
            return default(T);
        BinaryFormatter bf = new BinaryFormatter();
        using (MemoryStream ms = new MemoryStream(data))
        {
            object obj = bf.Deserialize(ms);
            return (T)obj;
        }
    }
like image 145
Basyonic Avatar answered Sep 21 '22 05:09

Basyonic


That's an interesting problem. There are a few ways I can think of approaching it:

  • cast it to a byte[] before storing it
  • cheat with dynamic
  • wrap it in some other identifiable wrapper prior to storing it

Essentially, custom conversion operators don't work when unboxing, unless you use dynamic

I could also perhaps implement IConvertible or some other well-known interface.

like image 43
Marc Gravell Avatar answered Sep 18 '22 05:09

Marc Gravell