我创建了以下单例类来处理Redis连接,并公开BookSleeve功能:
public class RedisConnection
{
private static RedisConnection _instance = null;
private BookSleeve.RedisSubscriberConnection _channel;
private readonly int _db;
private readonly string[] _keys; // represent channel name
public BookSleeve.RedisConnection _connection;
/// <summary>
/// Initialize all class parameters
/// </summary>
private RedisConnection(string serverList, int db, IEnumerable<string> keys)
{
_connection = ConnectionUtils.Connect(serverList);
_db = db;
_keys = keys.ToArray();
_connection.Closed += OnConnectionClosed;
_connection.Error += OnConnectionError;
// Create a subscription channel in redis
_channel = _connection.GetOpenSubscriberChannel();
// Subscribe to the registered connections
_channel.Subscribe(_keys, OnMessage);
// Dirty hack but it seems like subscribe returns before the actual
// subscription is properly setup in some cases
while (_channel.SubscriptionCount == 0)
{
Thread.Sleep(500);
}
}
/// <summary>
/// Do something when a message is received
/// </summary>
/// <param name="key"></param>
/// <param name="data"></param>
private void OnMessage(string key, byte[] data)
{
// since we are just interested in pub/sub, no data persistence is active
// however, if the persistence flag is enabled, here is where we can save the data
// The key is the stream id (channel)
//var message = RedisMessage.Deserialize(data);
var message = Helpers.BytesToString(data);
if (true) ;
//_publishQueue.Enqueue(() => OnReceived(key, (ulong)message.Id, message.Messages));
}
public static RedisConnection GetInstance(string serverList, int db, IEnumerable<string> keys)
{
if (_instance == null)
{
// could include some sort of lock for thread safety
_instance = new RedisConnection(serverList, db, keys);
}
return _instance;
}
private static void OnConnectionClosed(object sender, EventArgs e)
{
// Should we auto reconnect?
if (true)
{
;
}
}
private static void OnConnectionError(object sender, BookSleeve.ErrorEventArgs e)
{
// How do we bubble errors?
if (true)
{
;
}
}
}
在OnMessage()
中,var message = RedisMessage.Deserialize(data);
由于以下错误而被注释掉:
由于其保护级别,RedisMessage无法访问。
RedisMessage是BookSleeve中的一个抽象类,我有点不知道为什么我不能使用它。
我遇到了这个问题,因为当我向通道(pub / sub)发送消息时,我可能想在OnMessage()中对它们做一些事情 - 例如,如果设置了持久性标志,我可能会选择开始录制数据。问题是此时数据已序列化,我希望将其反序列化(字符串)并将其保留在Redis中。
这是我的测试方法:
[TestMethod]
public void TestRedisConnection()
{
// setup parameters
string serverList = "dbcache1.local:6379";
int db = 0;
List<string> eventKeys = new List<string>();
eventKeys.Add("Testing.FaucetChannel");
BookSleeve.RedisConnection redisConnection = Faucet.Services.RedisConnection.GetInstance(serverList, db, eventKeys)._connection;
// broadcast to a channel
redisConnection.Publish("Testing.FaucetChannel", "a published value!!!");
}
由于我无法使用Deserialize()
方法,因此我创建了一个静态助手类:
public static class Helpers
{
/// <summary>
/// Serializes a string to bytes
/// </summary>
/// <param name="val"></param>
/// <returns></returns>
public static byte[] StringToBytes(string str)
{
try
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
catch (Exception ex)
{
/* handle exception omitted */
return null;
}
}
/// <summary>
/// Deserializes bytes to string
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static string BytesToString(byte[] bytes)
{
string set;
try
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
catch (Exception ex)
{
// removed error handling logic!
return null;
}
}
}
不幸的是,这不能正确地将字符串反序列化为其原始形式,而我得到的是这样的:异汢獩敨庆ㄠㄠ,而不是实际的原始文本。
建议?
答案 0 :(得分:0)
显然这是一个编码类型的问题,同时,稍微看一下this link,我只是添加了UTF8的编码类型,输出看起来很好:
#region EncodingType enum
/// <summary>
/// Encoding Types.
/// </summary>
public enum EncodingType
{
ASCII,
Unicode,
UTF7,
UTF8
}
#endregion
#region ByteArrayToString
/// <summary>
/// Converts a byte array to a string using Unicode encoding.
/// </summary>
/// <param name="bytes">Array of bytes to be converted.</param>
/// <returns>string</returns>
public static string ByteArrayToString(byte[] bytes)
{
return ByteArrayToString(bytes, EncodingType.Unicode);
}
/// <summary>
/// Converts a byte array to a string using specified encoding.
/// </summary>
/// <param name="bytes">Array of bytes to be converted.</param>
/// <param name="encodingType">EncodingType enum.</param>
/// <returns>string</returns>
public static string ByteArrayToString(byte[] bytes, EncodingType encodingType)
{
System.Text.Encoding encoding=null;
switch (encodingType)
{
case EncodingType.ASCII:
encoding=new System.Text.ASCIIEncoding();
break;
case EncodingType.Unicode:
encoding=new System.Text.UnicodeEncoding();
break;
case EncodingType.UTF7:
encoding=new System.Text.UTF7Encoding();
break;
case EncodingType.UTF8:
encoding=new System.Text.UTF8Encoding();
break;
}
return encoding.GetString(bytes);
}
#endregion
<强> - UPDATE - 强>
更简单:var message = Encoding.UTF8.GetString(data);
答案 1 :(得分:0)
RedisMessage
表示即将发送到服务器的待处理请求;这有一些具体的实现,通常与要发送的参数的性质和数量有关。它使毫无意义来“反序列化”(甚至“序列化”)RedisMessage
- 这不是他们的目的。 明智唯一要做的就是Write(...)
他们到Stream
。
如果你想要关于RedisMessage
的信息,那么.ToString()
有一个概述,但这不是圆形的,并且坦率地用于调试。
RedisMessage
是internal
类;一个实现细节。除非您正在处理对核心代码的拉取请求,否则您永远不需要与RedisMessage
进行交互。
在类似的级别,有RedisResult
表示从服务器返回的响应。如果你想快速获取数据,那么幸运的是更简单:
object val = result.Parse(true);
(true
表示“推测性地测试数据是否看起来像string
”。但同样,这是一个internal
实现细节,您不应该使用它。