2014-10-03 14 views
5

Sto provando a creare un provider Redis per Strathweb.CacheOutput.WebApi2, ma provo a convertire da un byte [] -> RedisValue - > byte [] restituisce null.StackExchange.Redis trasmette RedisValue al byte [] via "come byte []" restituisce null

Posso impostare manualmente il tipo di oggetto come byte [] invece di var/RedisValue e restituirà correttamente il valore come byte [], ma dopo che è stato impostato come RedisValue non riesce a convertirlo in un byte [].

La sua interfaccia ha l'oggetto Restituisci sempre un oggetto quindi non posso forzare il tipo o utilizzare una chiamata separata senza dover modificare l'interfaccia.

Se provo a fare un result as byte[] ottengo Cannot convert type 'StackExchange.Redis.RedisValue' to 'byte[]' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion

Se provo a fare un (byte[])result ottengo Cannot cast 'result' (which has an actual type of 'StackExchange.Redis.RedisValue') to 'byte[]'

C'è qualcosa che mi manca o sto andando a incidere in in qualche modo controllando che tipo di dati sta cercando in base alla chiave?

Qui è l'interfaccia:

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; } 
    } 
} 

Ed ecco come la sua chiamata:

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

Modifica: Aggiunta di esempi di API I implementate utilizzando entrambe le ServiceStack.Redis v3 (lavora come atm appena usa object e StackExchange.Redis che non funziona)

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

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

risposta

3

La conversione tra byte[] e RedisValue utilizza un conversion operator. Il valore è noto al compilatore solo come object, quindi non sa che è necessario chiamare l'operatore di conversione. Cioè se si scrive il codice seguente:

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

Il compilatore scrive qualcosa di simile a quanto segue per l'ultima riga, che non riesce:

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

È possibile risolvere questo problema lasciando che il compilatore conosce il vero tipo dell'oggetto prima di provare a convertirlo.

byte[] bytes = (RedisValue)result; 

Questo fa sì che il compilatore di scrivere codice come questo:

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

Il problema è che l'interfaccia restituisce un oggetto e il codice chiamante sta eseguendo un 'come byte []'. Sto provando a non modificare né l'interfaccia né il codice principale, ma penso che sto solo aggiungendo un nuovo metodo che restituisce il byte [] per ora. Ho modificato il mio post per mostrare il codice di chiamata corretto con 'come byte []' – John

2

Questo è un problema interessante.Ci sono alcuni modi che posso pensare che si avvicina:

  • getto ad un byte[] prima di riporlo
  • barare con dynamic
  • avvolgerla in qualche altro involucro identificabile prima di conservarla
In sostanza, gli operatori di conversione personalizzati non funzionano quando si disattiva un box, a meno che non si usi dynamic

Potrei anche forse implemente ment IConvertible o qualche altra interfaccia ben nota.

+0

Più ci penso, più sono sicuro che 'RedisValue' dovrebbe': IConvertible'. Questo sarà probabilmente nella prossima goccia. –

+0

Grazie per la rapida risposta Marc! Ho sostituito quel codice con una chiamata diretta che restituisce il byte [] al posto dell'oggetto e si accorge che sta fallendo in molti altri posti (chiamate 'come stringa' e' come MediaTypeHeaderValue'). Ho provato a impostarlo come un 'dynamic result = _database.GetString (key)' ma questo ha dato lo stesso risultato, cosa intendevi per barare con dynamic? C'è un modo per farlo restituire un oggetto invece di convertirlo in RedisValue? – John

+0

Alla fine ho semplicemente disattivato 'StackExchange.Redis' per' ServiceStack.Redis' e sono riuscito a farlo senza problemi. Mi piace molto di più la tua versione in quanto è molto più piccola. Se c'è un modo per usare semplicemente 'object' not' RedisValue' come tipo di ritorno per favore fammelo sapere così posso scambiarlo di nuovo :) – John

1

Il seguente codice che utilizza StackExchange.Redis può impostare/ottenere il valore di tipo generico e convertire RedisValue in byte [] in elaborazione, dovrebbe funzionare correttamente per qualsiasi tipo serializzabile.

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; 
     } 
    } 
Problemi correlati