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

I am trying to create a Redis provider for Strathweb.CacheOutput.WebApi2, but trying to convert from byte [] → RedisValue → byte [] returns null.

I can manually set the object type as byte [] instead of var / RedisValue, and it will correctly return the value as byte [], but after it was set as RedisValue, it could not convert it to byte [].

In its interface, Get always returns an object, so I cannot force this type or use a separate call without having to change the interface.

If I try to do the 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 (byte[])result , I get Cannot cast 'result' (which has an actual type of 'StackExchange.Redis.RedisValue') to 'byte[]'

Is there something that I am missing, or will I have to hack something by checking which data types it searches 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 this is how it is called:

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

Edit: adding examples of API I implemented using both ServiceStack.Redis v3 (working atm as it just uses object and StackExchange.Redis, which doesn't work)

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

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

+5
source share
3 answers

The conversion between byte[] and RedisValue uses the conversion operator. The value is known only to the compiler as object , however, therefore, it does not know that it needs to call the conversion operator. That is, if you write the following code:

 object result = someRedisValue; byte[] bytes = (byte[])result; 

On the last line, the compiler writes something like the following:

 cast result to byte[] // runtime error: it not a byte[]! store that in 'bytes' 

You can solve this problem by letting the compiler know the actual type of the object before trying to convert it.

 byte[] bytes = (RedisValue)result; 

This forces the compiler to write code like this:

 cast result to RedisValue call RedisValue implicit RedisValue to byte[] conversion on that store that in 'bytes' 
+4
source

This is an interesting problem. There are several ways I can think of approaching it:

  • open it before saving it
  • cheat with dynamic
  • wrap it in some other identifiable wrapper before saving it.

Essentially, custom conversion operators do not work when unpacking unless you use dynamic

Perhaps I could implement IConvertible or some other known interface.

+3
source

The following code using StackExchange.Redis can set / get the value of the generic type and convert RedisValue to byte [] in the 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; } } 
+1
source

Source: https://habr.com/ru/post/1203956/


All Articles