Redis入门 - C#|.NET Core封装Nuget包
经过前面章节的学习,可以说大家已经算Redis开发入门了。已经可以去到项目上磨砺了。
但是今天我还想和大家分享一章:封装自己的Redis C#库,然后打包成Nuget包。

首先要说明的是:不是要自己开发一个Redis客户端库,而是基于上篇文章中介绍的6大库,做一个简单封装,真的很简单的那种,就是包个壳子。
再来说说为什么要做这个事情。
01、原因
1.可测试
我希望代码是以服务的方式注入到程序中,而不是静态方法的方式去调用。使用依赖注入来提供服务使得程序可测试性增强,如果做单元测试,依赖注入的服务很容易通过mock来测试,而静态方法往往很难被模拟,测试起来很不灵活;
2.解耦
对于一个系统来说会使用到各种技术来达到某种能力,实现一个功能可能会有很多种方法,我们在意的是实现这个功能,而不是你用了什么方法。回到主题,我们需要的是使用Redis来实现业务功能,而具体用那个客户端库并不重要。
再举个例子比如今天我们选择了ServiceStack.Redis库接过遇到问题我们解决不了怎么办?难道业务不做了?不可能吧!而恰巧这个时候CSRedisCore库可以解决,你会怎么选?
这时候可能会想换的成本有多大?两种库方法名不统一,功能也不一样,如果系统中到处散落Redis方法调用,这可怎么换啊。
试想如果我们封装了一层,提供了一组接口,打包成Nuget包,这个时候大家用的就是这个Nuget包,而我们只需要把Nuget包里用ServiceStack.Redis实现的方法换成用CSRedisCore实现一下,大家直接更新一下Nuget包,可能一行代码都不用改就完成了替换。
因为我们依赖的是我们自己封装的接口,而不是具体Redis客户端库,因此可以解耦轻松替换。

3.扩展
Redis的原生功能可以理解为基础功能,表明Redis有这种能力。但是我们怎么使用,怎么更好的发挥它的价值,这就是我们自己能力的体现了。
大家相过想过没有,为什么有的库商业化做的特别好,特别简单容易上手。商业化好说明提供的服务好,也就是说明它能帮你做很多事情,它在原生功能上加了很多自己的创作。
项目做多了,我们自己也会遇到一些相似的功能,如果这个时候我们想把这些相似功能封装一下,要放哪里呢?怎么给别人用?如果我们遇到一个功能现有库都没有相应能力,需要我们基于原生自己开发实现又应该在哪做呢?
这些功能积累的多了总要有个地方放吧,而这时如果我们自己封装了一层,放哪的问题是不是一下子就解决了,说不定做着做着就成了一个产品了呢。
不知道到这里,大家有没有感觉思路一下子被打开了。可能我们没写几行代码,但是这个格局一下子就打开了,而这几行代码也可能产生意想不到的收获,可能是无限可能,也可能就是你实现自己Redis客户端库的开端。

当然这也是我自己对编码,对封装的个人拙见。说这么多也是希望可以给大家一些帮助。
02、实现
下面闲话少说进入正题,如果来封装呢?
我们先梳理一下大致思路:
1.我们需要一个接口,里面包含:原库原生能力Client、其他我们自定义功能。
2.一个入口,别人要用,总要有个入口吧。
其实要求就这么简单。
下面我们就以封装CSRedisClient为例,首先定义IRedisService接口,里面包含Client字段以及两个演示的自定义方法
using CSRedis;
namespace Redis.RedisExtension
{
public interface IRedisService
{
/// <summary>
/// RedisClient
/// </summary>
/// <returns></returns>
CSRedisClient Client { get; }
#region 自定义方法
/// <summary>
/// 获取指定 key 的值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
T Get<T>(string key);
/// <summary>
/// 获取指定 key 的值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
Task<T> GetAsync<T>(string key);
#endregion
}
}
然后需要实现IRedisService,同时以CSRedisClient为构造函数入参,具体代码如下:
using CSRedis;
namespace Redis.RedisExtension
{
public class RedisService : IRedisService
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="redisClient"></param>
public RedisService(CSRedisClient redisClient)
{
Client = redisClient;
}
/// <summary>
/// CSRedis
/// </summary>
/// <returns></returns>
public CSRedisClient Client { get; }
#region 自定义方法
/// <summary>
/// 获取指定 key 的值
/// </summary>
/// <returns></returns>
public T Get<T>(string key)
{
return Client.Get<T>(key);
}
/// <summary>
/// 获取指定 key 的值
/// </summary>
/// <returns></returns>
public Task<T> GetAsync<T>(string key)
{
return Client.GetAsync<T>(key);
}
#endregion
}
}
到这里第一个问题就解决了,对于第二个问题我们,我们可以对IServiceCollection进行扩展添加启动扩展方法AddRedisClientSetup,具体代码如下:
using CSRedis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Redis.RedisExtension
{
public static class RedisSetupExtensions
{
/// <summary>
/// Redis客户端启动项
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddRedisClientSetup(this IServiceCollection services)
{
services.AddSingleton<CSRedisClient>(serviceProvider =>
{
var configuration = serviceProvider.GetRequiredService<IConfiguration>();
var setting = configuration["RedisConnectionString"];
return new CSRedisClient(setting);
});
services.AddSingleton<IRedisService, RedisService>();
return services;
}
/// <summary>
/// Redis客户端启动项
/// </summary>
/// <param name="services"></param>
/// <param name="connectionString"></param>
/// <returns></returns>
public static IServiceCollection AddRedisClientSetup(this IServiceCollection services, string connectionString)
{
services.AddSingleton<CSRedisClient>(serviceProvider =>
{
return new CSRedisClient(connectionString);
});
services.AddSingleton<IRedisService, RedisService>();
return services;
}
}
}
为什么要提供两个重载方法,因为如果用户基于我们的约定,在配置文件中以"RedisConnectionString"命名Redis连接字符串,用户直接调用AddRedisClientSetup()方法即可完成Redis启动,但是可能因为各种原因用户没法遵守约定,因此我们也要提供一个用户可以指定Redis连接字符串方法的入口。
下面我们就用基于约定的方式,在配置文件中加入以下配置:
{
"RedisConnectionString": "127.0.0.1:6379"
}
然后使用Client.Set方法设置key1,再用自定义方法Get方法读取,代码如下:
public static void Run()
{
var configuration = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();
var services = new ServiceCollection();
services.AddSingleton<IConfiguration>(configuration);
services.AddRedisClientSetup();
var redisService = services.BuildServiceProvider().GetService<IRedisService>();
var setResult = redisService.Client.Set("key1", "value1");
Console.WriteLine($"redisService.Client.Set(\"key1\",\"value1\")执行结果:{setResult}");
var value = redisService.Get<string>("key1");
Console.WriteLine($"redisService.Get<string>(\"key1\")执行结果:{value}");
redisService.Client.Del("key1");
}
执行结果如下:

是不是很简单,然后我们只需要把上面三个文件IRedisService、RedisService、RedisSetupExtensions放到单独的类库中,然后打包发布成Nuget包,就可以给大家一起用啦,今天我这边就不发布Nuget包了,后面会有相关的计划,到时候再细聊。
注:测试方法代码以及示例源码都已经上传至代码库,有兴趣的可以看看。https://gitee.com/hugogoos/Planner
Redis入门 - C#|.NET Core封装Nuget包的更多相关文章
- asp.net core 三 Nuget包管理
参考连接:http://www.cnblogs.com/netcore2/p/7412891.html 这里的说明,基本就是学习了别人的文章,自己做了个备份 asp.net c ...
- 解决 .net core 中 nuget 包版本冲突问题
今天在一个 asp.net core 项目中遇到了 nuget 包版本冲突的问题,错误信息如下: Version conflict detected for Microsoft.AspNet.WebA ...
- .Net core 还原Nuget包失败的解决方法
今天是2018最后一天了,真是神奇的一年啊,写个博客压压惊,来年继续加油吧..... 正文: 当我们打开.net core 项目时候,发现输出提示nuget包还原失败,这个时候首先要考虑.Net Co ...
- 解决 .net core 中 nuget 包版本冲突问题[转载]
今天在一个 asp.net core 项目中遇到了 nuget 包版本冲突的问题,错误信息如下: Version conflict detected for Microsoft.AspNet.WebA ...
- 【NET Core】Nuget包发布流程
1.新建一个.NET Core类库 2.新增一个方法,并编译项目 3.下载Nuget.exe,与刚才新建的类库放在同一目录下 下载地址:https://www.nuget.org/downloads ...
- NetCore入门篇:(三)Net Core项目Nuget及Bower包管理
一.创建项目 1.如何创建项目,参照上一篇文章 二.程序包介绍 1.Net Core的程序包分前后端两种,后端用nuget,前端用bower. 2.与Net 不同,Net Core引用nuget包时, ...
- .NET Core 学习笔记2——管理nuget包
.NET Core 基于Nuget包.它是一个.nupkg后缀的zip文件. 工具 dotnet 工具 vs2017 的程序包管理控台 这两个工具都可以用命令行来下载安装,更新,上传包(上传要先在网站 ...
- .NET Core 环境下使用命令行移除某个 nuget 包的具体方法
.NET Core 使用Nuget包一般是先写入csproj文件,然后下载保存在\bin\Debug\netcoreapp2.0\publish\下,所以可以采用如下方案进行删除操作(其中netcor ...
- 001从零开始入门Entity Framework Core——基础知识
Entity Framework (EF) Core 是轻量化.可扩展.开源和跨平台版的常用 Entity Framework 数据访问技术. 一.什么是 Entity Framework Core ...
- 基于 Vue.js 之 iView UI 框架非工程化实践记要 使用 Newtonsoft.Json 操作 JSON 字符串 基于.net core实现项目自动编译、并生成nuget包 webpack + vue 在dev和production模式下的小小区别 这样入门asp.net core 之 静态文件 这样入门asp.net core,如何
基于 Vue.js 之 iView UI 框架非工程化实践记要 像我们平日里做惯了 Java 或者 .NET 这种后端程序员,对于前端的认识还常常停留在 jQuery 时代,包括其插件在需要时就引 ...
随机推荐
- PHP+Redis 实例【一】点赞 + 热度
前言 点赞其实是一个很有意思的功能.基本的设计思路有大致两种, 一种自然是用mysql(写了几百行的代码都还没写完,有毒)啦 数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或m ...
- [oeasy]python0033_任务管理_jobs_切换任务_进程树结构_fg
查看进程 回忆上次内容 上次先进程查询 ps -elf 查看所有进程信息 ps -lf 查看本终端相关进程信息 杀死进程 kill -9 PID 给进程发送死亡信号 运行多个 python3 sh ...
- oeasy教您玩转vim - 23 - 配置文件
配置文件 回忆上节课内容 我们上次找到配置文件的位置 ~/.vimrc 了解各种配置开关 修改配置文件并应用 这次想了解和配色方案相关的内容 colorscheme vi ~/.vimrc.old 中 ...
- DuiLib的编译
Duilib编译需要注意两点: 加入预处理器:WIN32;_DEBUG;_WINDOWS;UILIB_STATIC; 到这一步还是报错,报错的是DuiString += 这一行报错,还有Util这 ...
- vue codemirror sql编辑器功能 可自定义提醒(关键字,库名,表名),高亮,主题
工作中再一次需要开发sql编辑器,优化上篇文章内容 https://www.cnblogs.com/Lu-Lu/p/14388888.html 本次功能是tab页打开多个sql编辑器,效果图: 安装: ...
- python获取引用对象的个数
python获取引用对象的个数 使用sys.getrefcount()来获取当前对象被引用了多少次,返回的结果比实际大1 import sys class A: pass a = A() #创建实例对 ...
- 使用 useSeoMeta 进行 SEO 配置
title: 使用 useSeoMeta 进行 SEO 配置 date: 2024/7/30 updated: 2024/7/30 author: cmdragon excerpt: 摘要:本文介绍了 ...
- 【SpringMVC】 Controller接收深度复杂对象封装不到的问题
首先来看数据结构的定义: 一个Form对象,然后里面有一个排版日期对象的List集合 排班集合的每个元素中又有一个String集合 在前端的Post请求中可以看到这个String集合是传递了的 但是D ...
- 【MybatisPlus】 Field '主键' doesn't have a default value
使用MybatisPlus的 PoMapper执行Insert插入方法报错: 复原场景: 1.PO对象存在主键值(双主键) 2.表中数据为空 3.首次插入 这张表使用的是双主键,发现原因是因为PO设置 ...
- 【转载】 NCCL(Nvidia Collective multi-GPU Communication Library) Nvidia英伟达的Multi-GPU多卡通信框架NCCL 学习;PCIe 速率调研
原文地址: https://www.cnblogs.com/xuyaowen/p/nccl-learning.html ---------------------------------------- ...