Aoite 是一个适于任何 .Net Framework 4.0+ 项目的快速开发整体解决方案。Aoite.Data 适用于市面上大多数的数据库提供程序,通过统一封装,可以在日常开发中简单便捷的操作数据库。

赶紧加入 Aoite GitHub 的大家庭吧!!

插几句话:开源对我来讲,是一种分享。没有人可以从中获取金钱上的利益。每一套框架都有不足和亮点所在。Aoite 目的是让园友多一种可尝试的选择。对我来说的根本目的在于让 Aoite 真正的成为一个快速开发整体解决方案

1. 快速入门

Redis 在 .NET 上有非常多成熟的框架。Aoite.Redis 仅仅目前只是实现其中的一员。实现 Aoite.Redis 的根本目的是为了迎合 Aoite.CommandModel 模块,并且减少对外部框架的依赖。

using(var client = new RedisClient(6379, null /* password*/))
{
client.FlushAll();
client.Set("Int32Value", 1);
client.Set("StringValue", "a");
client.Set("DoubleValue", 1.0);
client.Set("DecimalValue", 1.0m);
client.Set("AnonymousValue", new BinaryValue(new { A = "a" })); Console.WriteLine((Int32)client.Get("Int32Value"));
Console.WriteLine((String)client.Get("StringValue"));
Console.WriteLine((Double)client.Get("DoubleValue"));
Console.WriteLine((Decimal)client.Get("DecimalValue"));
Console.WriteLine(client.Get("AnonymousValue").ToModel());
}

1.1 二进制值 BinaryValue

System.BinaryValue 是一个非常有趣的类。它提供了从 decimal、Guid、string、DateTime、DateTimeOffset、TimeSpan、bool、ulong、char、uint、double、ushort、short、float、int 和 long 与 byte[] 之间的隐式转换。

比如你可以这么写:

BinaryValue value1 = 5;
BinaryValue value2 = "abc"; int x = value1;
string y = value2;

当然了,对于复杂的类型,就必须通过构造函数来创建。

 BinaryValue value = new BinaryValue(new { Username = "username", Passowrd = "passowrd" });
Console.WriteLine(value.ToModel());

ToModel 还提供了一个泛型,可以执行返回值的数据类型。

不过,当遇见一个你无法预期判断出具体类型时,你可以这么做:

static void Print<T>(T obj)
{
BinaryValue value = BinaryValue.Create(obj);
Console.WriteLine(value.Parse(typeof(T)));
}

然后你就可以像这样调用:

Print("a");
Print(1);
Print(new { Username = "username", Passowrd = "passowrd" });

相信看到这里的你,应该就明白 System.BinaryValue 在 Redis 中可发挥的重大作用了。

1.2 事务

Redis 的事务不同于关系型数据库的事务。在事务范围内的任何命令,都只会返回一个内容“QUENED”,表示此命令已成功加入命令列表(但不代表执行一定会成功)。所以在 Redis 上的事务,我们要一种稍微奇怪的方式进行。

你看见的代码,可能是这样的:

using(var client = new RedisClient(6379, null /* password*/))
{
using(var tran = client.BeginTransaction())
{
tran.On(tran.Set("key1", "value1"), r =>
{
Console.WriteLine("设置 Key1 为 value1 的结果是 {0}", r);
});
tran.On(tran.IncrBy("key2"), r =>
{
Console.WriteLine(r);
});
tran.Commit();
}
Console.WriteLine((string)client.Get("key1"));
Console.WriteLine((string)client.Get("key2"));//- 根据 Redis 的协议,返回应该是 String 类型,而不是 Int64
}

1.3 Hash 的改进

如果有一个对象,你想存储在 Redis 中时,是以字段进行存储的,那就需要用到 Redis 的 HASH。

class MyModel
{
public string Username { get; set; }
public string Password { get; set; }
}

以下代码将 MyModel 存储到 Hash 中、从 Hash 获取所有域和获取部分域:

using(var client = new RedisClient(6379, null /* password*/))
{
client.FlushAll();
string key = "model001";
client.HMSet(key, new MyModel() { Username = "admin", Password = "123456" });
var model = client.HGetAll<MyModel>(key);
Console.WriteLine("Model -> {0}\t{1}", model.Username, model.Password); Console.WriteLine("Username : {0}", client.HGet(key, "Username"));
Console.WriteLine("Password : {0}", client.HGet(key, "Password"));
}

上面的代码输出:

Model -> admin  123456
Username : admin
Password : 123456

1.4 Scan Redis 的扫描

Redis 中有 SCAN、HSCAN、SSCAN 和 ZSCAN 四个扫描的命令。Aoite.Redis 针对扫描的命令进行封装,返回一个 IEnumerable<T> 类型。扫描的过程并不是一次性全部加载。而是充分利用 yield 进行懒加载,第一次扫描至多返回 10 条数据(可以干涉需要返回的数量),再填充到 Queue 先进先出的队列中。等到队列中没有数据时,再重新扫描至多 10 条数据。直至扫描的队列为空并且下一批扫描的数据,整个扫描结束。

Scan:返回类型 IEnumerable<string>,以下代码输出内容: 11(1,10,11,12...18,19)。

static void Code7()
{
using(var client = new RedisClient(6379, null /* password*/))
{
client.FlushAll();
for(int i = 0; i < 20; i++)
{
client.Set("key" + i, "Value" + i);
}
Console.WriteLine(client.Scan(pattern: "key1*").Count());
}
}

HScan:返回类型 IEnumerable<RedisFieldItem>

using(var client = new RedisClient(6379, null /* password*/))
{
client.FlushAll();
for(int i = 0; i < 20; i++)
{
client.HSet("Key", "Field" + i, "Value" + i);
}
Console.WriteLine("[Field]\t|\t[Value]");
foreach(var item in client.HScan("Key", pattern: "Field1*"))
{
Console.WriteLine("{0}\t|\t{1}",item.Field, item.Value);
}
}

以上代码输出:

[Field] |       [Value]
Field1 | Value1
Field10 | Value10
Field...| Value...
Field18 | Value18
Field19 | Value19

SScan:返回类型 IEnumerable<BinaryValue>,以下代码输出内容 5

using(var client = new RedisClient(6379, null /* password*/))
{
client.FlushAll();
for(int i = 0; i < 20; i++)
{
client.SAdd("Key", "Member" + i % 5);
}
Console.WriteLine(client.SScan("Key").Count());
}

ZAdd:返回类型 IEnumerable<RedisScoreItem>,代码可以参考 HScan

1.5 哪些命令还没有被实现?

String 未实现命令

Key 未实现命令

Pub/Sub 未实现命令

  • 所有命令等找到合适的方式再去实现。

Connection

Server

隐式实现的命令

  • Transaction,事务性命令通过 IRedisClient.BeginTransaction 来隐士完成。

  • Connection
    • AUTH:初始化 RedisClient 就应该提供 Redis 的密码,来简化整体的流程。

3. 序列化

Aoite.Serialization 里有包含两个部分内容。

  • 继承 System.Serializer 的序列化器。比如已实现好的:System.Serializer.BinarySystem.Serializer.JsonSystem.Serializer.Xml,当然还有本节的主角 `System.Serializer.Quickly'。
  • 一套二进制的序列化组件 Aoite.Serialization.ObjectWriterObjectReader。这是一套针对字段级别的序列化,支持的类型非常多,Aoite.Tests 里有一个非常复杂的测试对象,想要了解它支持的类型,可以通过那个单元测试进行了解。

3.1 快速入门

我们定义一个稍微有一丝丝复杂的对象:

class Dict2 : Dictionary<string, object>
{
public string MyProperty { get; set; }
}

然后我们可以这么序列化和反序列化:

Dict2 dict = new Dict2() { MyProperty = "Hello" };
dict.Add("1", new { A = "a" });
dict.Add("2", "haha");
dict.Add("3", 3);
dict.Add("4", new[] { 1, 2, 3, 4 });
var bytes = Serializer.Quickly.FastWriteBytes(dict);
Console.WriteLine("bytes length {0}", bytes.Length); var dict2 = Serializer.Quickly.FastReadBytes(bytes) as Dict2; foreach(var item in dict2)
{
Console.WriteLine("{0}\t\t{1}", item.Key, item.Value);
if(item.Value is Array)
{
foreach(var value in item.Value as Array)
{
Console.Write(value);
Console.Write(",");
}
}
}

3.2 序列化特殊对象

Aoite.Redis.RedisSessionState 这个特殊类,有一个数据类型为 SessionStateItemCollection 的特殊属性,这个通过 Quickly 的序列化是没有问题的,但是在使用时,便会抛出内存错误,具体什么原因我是没有深入研究。所以,针对无法序列化的对象,特性 SerializableUsage 便排上用场。

class RedisSessionState
{
//...
[SerializableUsage(typeof(Serializable))]
public SessionStateItemCollection Items { get; set; }
//... class Serializable : Aoite.Serialization.ICustomSerializable
{
public object Deserialize(ObjectReader reader)
{
SessionStateItemCollection items = new SessionStateItemCollection();
var count = reader.ReadInt32();
for(int i = 0; i < count; i++)
{
var name = (string)reader.Deserialize();
var value = reader.Deserialize();
items[name] = value;
}
return items;
} public void Serialize(ObjectWriter writer, object value)
{
var items = value as SessionStateItemCollection;
writer.InnerWrite(items.Count);
foreach(string name in items.Keys)
{
writer.Serialize(name);
writer.Serialize(items[name]);
}
}
} }

SerializableUsage 特性指定一个类型,这样序列化器在处理过程中,将会初始化这个类型的实例,并调用 SerializeDeserialize 方法。

这样,理论上任何对象都可以序列化为文本。当然了,如果你想序列化 System.Windows.Forms.Form(这个还是有办法的) 或者 System.Web.Page 这就比较难了……

4. 结束

关于 Aoite.Ioc 和 Aoite.Serialization 的简单介绍,就到此结束了,如果你喜欢这个框架,不妨点个推荐吧!如果你非常喜欢这个框架,那请顺便到Aoite GitHub Star 一下 :)

Aoite 系列(03) - 一起来 Redis 吧!的更多相关文章

  1. Aoite 系列 目录

    介绍 本项目从2009年孵化(V->Sofire->Aoite),至今已度过5个年头.一直在优化,一直在重构,一直在商用.有十分完整的单元测试用例.可以放心使用. Aoite on 博客园 ...

  2. Aoite 系列(04) - 强劲的 CommandModel 开发模式(上篇)

    Aoite 是一个适于任何 .Net Framework 4.0+ 项目的快速开发整体解决方案.Aoite.CommandModel 是一种开发模式,我把它成为"命令模型",这是一 ...

  3. Aoite 系列(02) - 超动感的 Ioc 容器

    Aoite 系列(02) - 超动感的 Ioc 容器 Aoite 是一个适于任何 .Net Framework 4.0+ 项目的快速开发整体解决方案.Aoite.Ioc 是一套解决依赖的最佳实践. 说 ...

  4. Aoite 系列(01) - 比 Dapper 更好用的 ORM

    Aoite 是一个适于任何 .Net Framework 4.0+ 项目的快速开发整体解决方案.Aoite.Data 适用于市面上大多数的数据库提供程序,通过统一封装,可以在日常开发中简单便捷的操作数 ...

  5. Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  6. java io系列03之 ByteArrayOutputStream的简介,源码分析和示例(包括OutputStream)

    前面学习ByteArrayInputStream,了解了“输入流”.接下来,我们学习与ByteArrayInputStream相对应的输出流,即ByteArrayOutputStream.本章,我们会 ...

  7. JavaScript进阶系列03,通过硬编码、工厂模式、构造函数创建JavaScript对象

    本篇体验通过硬编码.工厂模式.构造函数来创建JavaScript对象. □ 通过硬编码创建JavaScript对象 当需要创建一个JavaScript对象时,我们可能这样写: var person = ...

  8. 委托、Lambda表达式、事件系列03,从委托到Lamda表达式

    在"委托.Lambda表达式.事件系列02,什么时候该用委托"一文中,使用委托让代码简洁了不少. namespace ConsoleApplication2 { internal ...

  9. php从入门到放弃系列-03.php函数和面向对象

    php从入门到放弃系列-03.php函数和面向对象 一.函数 php真正的威力源自它的函数,内置了1000个函数,可以参考PHP 参考手册. 自定义函数: function functionName( ...

随机推荐

  1. hibernate存储过程 3

              hibernate存储过程 User.hbm.xml文件的内容如下: <?xml version="1.0"?> <!DOCTYPE hibe ...

  2. Trie 最长前缀匹配串的实现

    http://blog.csdn.net/hguisu/article/details/8131559

  3. webService 跨域请求webconfig配置

    在webService文件夹下单独添加一个web.config <?xml version="1.0" encoding="UTF-8"?>< ...

  4. JavaBean知识

    四.JavaBean的概念1.JavaBean一般具有的特点:a.字段都是私有的. private String name;b.提供公共的getter或setter方法(属性).getter或sett ...

  5. G.Interference Signal---河南省第八届程序设计大赛(dp)

    G.Interference Signal 时间限制: 2 Sec  内存限制: 128 MB提交: 47  解决: 18[提交][状态] 题目描述 Dr.Kong’s laboratory moni ...

  6. UIAlertController、UIAlertAction 警告框

      NS_CLASS_AVAILABLE_IOS(8_0) @interface UIAlertAction : NSObject <NSCopying> //创建操作 + (instan ...

  7. H5中的拖拽事件

    最近浏览了张鑫旭大神的基于HTML5 drag/drop模块拖动插入排序删除完整实例,感觉受益匪浅.于是将最做的demo记录下来. 首先浏览一下事件,这些事件比较好记,只要记住用在谁的身上就好了,无非 ...

  8. .net sharepoint文档库操作

      /// <summary> /// 检查文档库 /// </summary> /// <param name="siteUrl"></ ...

  9. 机器学习利器——Scikit-learn的安装

    由于笔者最近在进行毕业论文的准备,且毕业论文中需要用到Python版本的机器学习库——scikit-learn.所以最近三天一直在Windows上部署这个框架,终于部署成功了... 首先打开加州大学底 ...

  10. 使用KeepAlived搭建MySQL高可用环境

    使用KeepAlived搭建MySQL的高可用环境.首先搭建MySQL的主从复制在Master开启binlog,创建复制帐号,然后在Slave输入命令   2016年7月25日   配置安装技巧:   ...