反射实现Model修改前后的内容对比 【API调用】腾讯云短信 Windows操作系统下Redis服务安装图文详解 Redis入门学习
反射实现Model修改前后的内容对比
在开发过程中,我们会遇到这样一个问题,编辑了一个对象之后,我们想要把这个对象修改了哪些内容保存下来,以便将来查看和追责。
首先我们要创建一个User类
1 public class User
2 {
3 private string name;
4 public string Name
5 {
6 get { return name; }
7 set { name = value; }
8 }
9 private string age;
10 public string Age
11 {
12 get { return age; }
13 set { age = value; }
14 }
15 private string sex;
16 public string Sex
17 {
18 get { return sex; }
19 set { sex = value; }
20 }
21 }
然后在Main函数中声明并初始化一个User对象
1 User userA = new User()
2 {
3 Name = "李四",
4 Age = "25",
5 Sex = "男",
6 };
因为要对比对象编辑前后的内容,所以需要备份一下这个UserA,我们来个深拷贝
1 User userB = DeepCopyByXml<User>(userA);
1 /// <summary>
2 /// 深拷贝
3 /// </summary>
4 /// <typeparam name="T"></typeparam>
5 /// <param name="obj"></param>
6 /// <returns></returns>
7 public static T DeepCopyByXml<T>(T obj) where T : class
8 {
9 object retval;
10 using (MemoryStream ms = new MemoryStream())
11 {
12 XmlSerializer xml = new XmlSerializer(typeof(T));
13 xml.Serialize(ms, obj);
14 ms.Seek(0, SeekOrigin.Begin);
15 retval = xml.Deserialize(ms);
16 ms.Close();
17 }
18 return (T)retval;
19 }
接下来的工作是修改UserA的属性,然后和UserB对比,利用反射来实现该功能
/// <summary>
/// Model对比
/// </summary>
/// <typeparam Name="T"></typeparam>
/// <param Name="oldModel"></param>
/// <param Name="newModel"></param>
private static void CompareModel<T>(T oldModel, T newModel) where T : class
{
string changeStr = string.Empty;
PropertyInfo[] properties = oldModel.GetType().GetProperties();
Console.WriteLine("--------用户信息修改汇总--------");
foreach (System.Reflection.PropertyInfo item in properties)
{string name = item.Name;
object oldValue = item.GetValue(oldModel);
object newValue = item.GetValue(newModel);
if (!oldValue.Equals(newValue))
{
Console.WriteLine(name + " :由[" + oldValue + "] 改为 [" + newValue + "]");
}
}
}

从运行结果来看我们已经获取到了修改的内容,美中不足的是“Name”和“Age”,如何以中文显示属性名,接下来将利用C#的特性来实现
新建一个自定义的特性类TableAttribute
/*
参数 validon 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。
参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。
参数 inherited(可选的)为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。
*/
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Field |
AttributeTargets.Property,
AllowMultiple = false,
Inherited = false)]
public class TableAttribute : System.Attribute
{
private string fieldName;
private string tableName;
/// <summary>
/// 表名
/// </summary>
public string TableName
{
get { return tableName; }
set { tableName = value; }
}
/// <summary>
/// 字段名
/// </summary>
public string FieldName
{
get { return fieldName; }
set { fieldName = value; }
}
}
接着修改User类,加上自定义的特性TableAttribute
/// <summary>
/// 用户信息实体类
/// </summary>
[TableAttribute(TableName = "用户信息")]
public class User
{
private string name;
[TableAttribute(FieldName = "姓名")]
public string Name
{
get { return name; }
set { name = value; }
}
private string age;
[TableAttribute(FieldName = "年龄")]
public string Age
{
get { return age; }
set { age = value; }
}
private string sex;
[TableAttribute(FieldName = "性别")]
public string Sex
{
get { return sex; }
set { sex = value; }
}
}
最后修改一下CompareModel这个方法
1 /// <summary>
2 /// Model对比
3 /// </summary>
4 /// <typeparam Name="T"></typeparam>
5 /// <param Name="oldModel"></param>
6 /// <param Name="newModel"></param>
7 private static void CompareModel<T>(T oldModel, T newModel) where T : class
8 {
9 string changeStr = string.Empty;
10 PropertyInfo[] properties = oldModel.GetType().GetProperties();
11 Console.WriteLine("--------用户信息修改汇总--------");
12 foreach (System.Reflection.PropertyInfo item in properties)
13 {
14 TableAttribute tableAttribute = item.GetCustomAttribute<TableAttribute>();
15 string name = item.Name;
16 if (tableAttribute != null)
17 name = tableAttribute.FieldName;
18 object oldValue = item.GetValue(oldModel);
19 object newValue = item.GetValue(newModel);
20 if (!oldValue.Equals(newValue))
21 {
22 Console.WriteLine(name + " :由[" + oldValue + "] 改为 [" + newValue + "]");
23 }
24 }
25 }
我们看一下运行结果

完整demo下载:https://files.cnblogs.com/files/LikeHeart/ExampleReflection.zip
(完)
【API调用】腾讯云短信
在之前介绍的火车票查询工具中,利用邮件和短信将查询结果推送给用户。免费短信的条数只有5条,用完之后只能单独使用邮件提醒。
最近发现腾讯云的福利,简单的介绍一下用法。

腾讯云-》产品-》通信服务-》短信-》开通服务-》添加应用-》创建签名和模板-》等待审核通过-》按照Demo测试


在整个流程中,最耗时的就是创建签名和模板,对个人来说只能选择app、公众号或小程序的方式进行申请,多亏之前折腾过一点小程序,从而闯关成功。
接下来查看官方Demo https://github.com/qcloudsms/qcloudsms/tree/master/demo/csharp
整理后的测试Demo
调用代码:
1 using QcloudSms;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7
8 namespace ConsoleTest
9 {
10 class SmsSDKDemo
11 {
12 /// <summary>
13 /// appId
14 /// </summary>
15 private static int appId = 140xxxxx;
16 /// <summary>
17 /// appKey
18 /// </summary>
19 private static string appKey = "xxxxxxxxxxxxxxx";
20 /// <summary>
21 /// 接收手机号
22 /// </summary>
23 private static string phoneNumber = "xxxxxxxx";
24 /// <summary>
25 /// 短信模板ID
26 /// </summary>
27 private static int tmplateId = xxxxxxx;
28
29 static void Main(string[] args)
30 {
31 try
32 {
33 SmsSingleSenderResult singleResult;
34 SmsSingleSender singleSender = new SmsSingleSender(appId, appKey);
35
36 singleResult = singleSender.Send(SmsType.普通短信, phoneNumber, "");
37 Console.WriteLine(singleResult);
38
39 List<string> templParams = new List<string>();
40 templParams.Add("G2619");
41 templParams.Add("二等座:23 无座:128");
42 singleResult = singleSender.SendWithParam(phoneNumber, tmplateId, templParams);
43 Console.WriteLine(singleResult);
44 }
45 catch (Exception e)
46 {
47 Console.WriteLine(e);
48 }
49 Console.Read();
50 }
51 }
52 }
1 namespace QcloudSms
2 {
3 #region 短信类型枚举
4 /// <summary>
5 /// 短信类型枚举
6 /// </summary>
7 public enum SmsType
8 {
9 普通短信 = 0,
10 营销短信 = 1
11 }
12 #endregion
13
14 #region 单发
15 /// <summary>
16 /// 单发
17 /// </summary>
18 class SmsSingleSender
19 {
20 #region 变量
21 /// <summary>
22 /// appId
23 /// </summary>
24 private int appId;
25 /// <summary>
26 /// appkey
27 /// </summary>
28 private string appkey;
29 /// <summary>
30 /// url
31 /// </summary>
32 private string url = "https://yun.tim.qq.com/v5/tlssmssvr/sendsms";
33 /// <summary>
34 /// util
35 /// </summary>
36 private SmsSenderUtil util = new SmsSenderUtil();
37 #endregion
38
39 #region 构造
40 /// <summary>
41 /// 构造函数
42 /// </summary>
43 /// <param name="sdkappid"></param>
44 /// <param name="appkey"></param>
45 public SmsSingleSender(int sdkappid, string appkey)
46 {
47 this.appId = sdkappid;
48 this.appkey = appkey;
49 }
50 #endregion
51
52 #region 普通单发短信接口
53 /// <summary>
54 /// 普通单发短信接口,明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名
55 /// </summary>
56 /// <param name="type">短信类型,0 为普通短信,1 营销短信</param>
57 /// <param name="phoneNumber">不带国家码的手机号</param>
58 /// <param name="msg">信息内容,必须与申请的模板格式一致,否则将返回错误</param>
59 /// <param name="extend">短信码号扩展号,格式为纯数字串,其他格式无效。默认没有开通</param>
60 /// <param name="ext">服务端原样返回的参数,可填空</param>
61 /// <returns>SmsSingleSenderResult</returns>
62 public SmsSingleSenderResult Send(SmsType type, string phoneNumber, string msg, string extend = "", string ext = "")
63 {
64 long random = util.GetRandom();
65 long curTime = util.GetCurTime();
66
67 // 按照协议组织 post 请求包体
68 JObject tel = new JObject();
69 tel.Add("nationcode", SmsSenderUtil.nationCode);
70 tel.Add("mobile", phoneNumber);
71 JObject data = new JObject();
72 data.Add("tel", tel);
73 data.Add("msg", msg);
74 data.Add("type", (int)type);
75 data.Add("sig", util.StrToHash(string.Format("appkey={0}&random={1}&time={2}&mobile={3}", appkey, random, curTime, phoneNumber)));
76 data.Add("time", curTime);
77 data.Add("extend", extend);
78 data.Add("ext", ext);
79
80 string wholeUrl = url + "?sdkappid=" + appId + "&random=" + random;
81 HttpWebRequest request = util.GetPostHttpConn(wholeUrl);
82 byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
83 request.ContentLength = requestData.Length;
84 Stream requestStream = request.GetRequestStream();
85 requestStream.Write(requestData, 0, requestData.Length);
86 requestStream.Close();
87
88 // 接收返回包
89 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
90 Stream responseStream = response.GetResponseStream();
91 StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
92 string responseStr = streamReader.ReadToEnd();
93 streamReader.Close();
94 responseStream.Close();
95 SmsSingleSenderResult result;
96 if (HttpStatusCode.OK == response.StatusCode)
97 {
98 result = util.ResponseStrToSingleSenderResult(responseStr);
99 }
100 else
101 {
102 result = new SmsSingleSenderResult();
103 result.result = -1;
104 result.errmsg = "http error " + response.StatusCode + " " + responseStr;
105 }
106 return result;
107 }
108 #endregion
109
110 #region 指定模板单发
111 /// <summary>
112 /// 指定模板单发
113 /// </summary>
114 /// <param name="phoneNumber">不带国家码的手机号</param>
115 /// <param name="templId">模板 id</param>
116 /// <param name="templParams">模板参数列表,如模板 {1}...{2}...{3},那么需要带三个参数</param>
117 /// <param name="sign">短信签名,如果使用默认签名,该字段可缺省</param>
118 /// <param name="extend">扩展码,可填空</param>
119 /// <param name="ext">服务端原样返回的参数,可填空</param>
120 /// <returns>SmsSingleSenderResult</returns>
121 public SmsSingleSenderResult SendWithParam(string phoneNumber, int templId, List<string> templParams, string sign = "", string extend = "", string ext = "")
122 {
123 long random = util.GetRandom();
124 long curTime = util.GetCurTime();
125
126 // 按照协议组织 post 请求包体
127 JObject tel = new JObject();
128 tel.Add("nationcode", SmsSenderUtil.nationCode);
129 tel.Add("mobile", phoneNumber);
130 JObject data = new JObject();
131 data.Add("tel", tel);
132 data.Add("sig", util.CalculateSigForTempl(appkey, random, curTime, phoneNumber));
133 data.Add("tpl_id", templId);
134 data.Add("params", util.SmsParamsToJSONArray(templParams));
135 data.Add("sign", sign);
136 data.Add("time", curTime);
137 data.Add("extend", extend);
138 data.Add("ext", ext);
139
140 string wholeUrl = url + "?sdkappid=" + appId + "&random=" + random;
141 HttpWebRequest request = util.GetPostHttpConn(wholeUrl);
142 byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
143 request.ContentLength = requestData.Length;
144 Stream requestStream = request.GetRequestStream();
145 requestStream.Write(requestData, 0, requestData.Length);
146 requestStream.Close();
147
148 // 接收返回包
149 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
150 Stream responseStream = response.GetResponseStream();
151 StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
152 string responseStr = streamReader.ReadToEnd();
153 streamReader.Close();
154 responseStream.Close();
155 SmsSingleSenderResult result;
156 if (HttpStatusCode.OK == response.StatusCode)
157 {
158 result = util.ResponseStrToSingleSenderResult(responseStr);
159 }
160 else
161 {
162 result = new SmsSingleSenderResult();
163 result.result = -1;
164 result.errmsg = "http error " + response.StatusCode + " " + responseStr;
165 }
166 return result;
167 }
168 #endregion
169 }
170 #endregion
171
172 #region 单发结果
173 /// <summary>
174 /// 单发结果
175 /// </summary>
176 class SmsSingleSenderResult
177 {
178 /// <summary>
179 /// 错误码,0 表示成功(计费依据),非 0 表示失败
180 /// </summary>
181 public int result { set; get; }
182 /// <summary>
183 /// 错误消息,result 非 0 时的具体错误信息
184 /// </summary>
185 public string errmsg { set; get; }
186 /// <summary>
187 /// 用户的 session 内容,腾讯 server 回包中会原样返回
188 /// </summary>
189 public string ext { set; get; }
190 /// <summary>
191 /// 本次发送标识 id,标识一次短信下发记录
192 /// </summary>
193 public string sid { set; get; }
194 /// <summary>
195 /// 短信计费的条数
196 /// </summary>
197 public int fee { set; get; }
198 /// <summary>
199 /// ToString()
200 /// </summary>
201 /// <returns></returns>
202 public override string ToString()
203 {
204 return string.Format("SmsSingleSenderResult\nresult {0}\nerrMsg {1}\next {2}\nsid {3}\nfee {4}", result, errmsg, ext, sid, fee);
205 }
206 }
207 #endregion
208
209 #region 群发
210 /// <summary>
211 /// 群发
212 /// </summary>
213 class SmsMultiSender
214 {
215 #region 变量
216 /// <summary>
217 /// appId
218 /// </summary>
219 private int appId;
220 /// <summary>
221 /// appkey
222 /// </summary>
223 private string appkey;
224 /// <summary>
225 /// url
226 /// </summary>
227 private string url = "https://yun.tim.qq.com/v5/tlssmssvr/sendmultisms2";
228 /// <summary>
229 /// util
230 /// </summary>
231 private SmsSenderUtil util = new SmsSenderUtil();
232 #endregion
233
234 #region 构造
235 /// <summary>
236 /// 构造
237 /// </summary>
238 /// <param name="sdkappid"></param>
239 /// <param name="appkey"></param>
240 public SmsMultiSender(int sdkappid, string appkey)
241 {
242 this.appId = sdkappid;
243 this.appkey = appkey;
244 }
245 #endregion
246
247 #region 普通群发短信接口
248 /// <summary>
249 /// 普通群发短信接口,明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名
250 ///【注意】 海外短信无群发功能
251 /// </summary>
252 /// <param name="type">短信类型,0 为普通短信,1 营销短信</param>
253 /// <param name="nationCode"></param>
254 /// <param name="phoneNumbers">不带国家码的手机号列表</param>
255 /// <param name="msg">信息内容,必须与申请的模板格式一致,否则将返回错误</param>
256 /// <param name="extend">扩展码,可填空</param>
257 /// <param name="ext">服务端原样返回的参数,可填空</param>
258 /// <returns>SmsMultiSenderResult</returns>
259 public SmsMultiSenderResult Send(SmsType type, List<string> phoneNumbers, string msg, string extend = "", string ext = "")
260 {
261 long random = util.GetRandom();
262 long curTime = util.GetCurTime();
263
264 // 按照协议组织 post 请求包体
265 JObject data = new JObject();
266 data.Add("tel", util.PhoneNumbersToJSONArray(SmsSenderUtil.nationCode, phoneNumbers));
267 data.Add("type", (int)type);
268 data.Add("msg", msg);
269 data.Add("sig", util.CalculateSig(appkey, random, curTime, phoneNumbers));
270 data.Add("time", curTime);
271 data.Add("extend", extend);
272 data.Add("ext", ext);
273
274 string wholeUrl = url + "?sdkappid=" + appId + "&random=" + random;
275 HttpWebRequest request = util.GetPostHttpConn(wholeUrl);
276 byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
277 request.ContentLength = requestData.Length;
278 Stream requestStream = request.GetRequestStream();
279 requestStream.Write(requestData, 0, requestData.Length);
280 requestStream.Close();
281
282 // 接收返回包
283 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
284 Stream responseStream = response.GetResponseStream();
285 StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
286 string responseStr = streamReader.ReadToEnd();
287 streamReader.Close();
288 responseStream.Close();
289 SmsMultiSenderResult result;
290 if (HttpStatusCode.OK == response.StatusCode)
291 {
292 result = util.ResponseStrToMultiSenderResult(responseStr);
293 }
294 else
295 {
296 result = new SmsMultiSenderResult();
297 result.result = -1;
298 result.errmsg = "http error " + response.StatusCode + " " + responseStr;
299 }
300 return result;
301 }
302 #endregion
303
304 #region 指定模板群发
305 /// <summary>
306 /// 指定模板群发
307 /// 【注意】海外短信无群发功能
308 /// </summary>
309 /// <param name="phoneNumbers">不带国家码的手机号列表</param>
310 /// <param name="templId"> 模板 id</param>
311 /// <param name="templParams">模板参数列表</param>
312 /// <param name="sign"> 签名,如果填空,系统会使用默认签名</param>
313 /// <param name="extend">扩展码,可以填空</param>
314 /// <param name="ext">服务端原样返回的参数,可以填空</param>
315 /// <returns> SmsMultiSenderResult</returns>
316 public SmsMultiSenderResult SendWithParam(List<string> phoneNumbers, int templId, List<string> templParams, string sign = "", string extend = "", string ext = "")
317 {
318 long random = util.GetRandom();
319 long curTime = util.GetCurTime();
320
321 // 按照协议组织 post 请求包体
322 JObject data = new JObject();
323 data.Add("tel", util.PhoneNumbersToJSONArray(SmsSenderUtil.nationCode, phoneNumbers));
324 data.Add("sig", util.CalculateSigForTempl(appkey, random, curTime, phoneNumbers));
325 data.Add("tpl_id", templId);
326 data.Add("params", util.SmsParamsToJSONArray(templParams));
327 data.Add("sign", sign);
328 data.Add("time", curTime);
329 data.Add("extend", extend);
330 data.Add("ext", ext);
331
332 string wholeUrl = url + "?sdkappid=" + appId + "&random=" + random;
333 HttpWebRequest request = util.GetPostHttpConn(wholeUrl);
334 byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
335 request.ContentLength = requestData.Length;
336 Stream requestStream = request.GetRequestStream();
337 requestStream.Write(requestData, 0, requestData.Length);
338 requestStream.Close();
339
340 // 接收返回包
341 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
342 Stream responseStream = response.GetResponseStream();
343 StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
344 string responseStr = streamReader.ReadToEnd();
345 streamReader.Close();
346 responseStream.Close();
347 SmsMultiSenderResult result;
348 if (HttpStatusCode.OK == response.StatusCode)
349 {
350 result = util.ResponseStrToMultiSenderResult(responseStr);
351 }
352 else
353 {
354 result = new SmsMultiSenderResult();
355 result.result = -1;
356 result.errmsg = "http error " + response.StatusCode + " " + responseStr;
357 }
358 return result;
359 }
360 #endregion
361 }
362 #endregion
363
364 #region 群发结果
365 /// <summary>
366 /// 群发结果
367 /// </summary>
368 class SmsMultiSenderResult
369 {
370 public class Detail
371 {
372 /// <summary>
373 /// 错误码,0 表示成功(计费依据),非 0 表示失败
374 /// </summary>
375 public int result { get; set; }
376 /// <summary>
377 /// 错误消息,result 非 0 时的具体错误信息
378 /// </summary>
379 public string errmsg { get; set; }
380 /// <summary>
381 /// 手机号码
382 /// </summary>
383 public string mobile { get; set; }
384 /// <summary>
385 /// 国家码
386 /// </summary>
387 public string nationcode { get; set; }
388 /// <summary>
389 /// 本次发送标识 id,标识一次短信下发记录
390 /// </summary>
391 public string sid { get; set; }
392 /// <summary>
393 /// 短信计费的条数
394 /// </summary>
395 public int fee { get; set; }
396 /// <summary>
397 /// ToString()
398 /// </summary>
399 /// <returns></returns>
400 public override string ToString()
401 {
402 return string.Format(
403 "\tDetail result {0} errmsg {1} mobile {2} nationcode {3} sid {4} fee {5}",
404 result, errmsg, mobile, nationcode, sid, fee);
405 }
406 }
407
408 public int result;
409 public string errmsg = "";
410 public string ext = "";
411 public IList<Detail> detail;
412
413 public override string ToString()
414 {
415 if (null != detail)
416 {
417 return String.Format(
418 "SmsMultiSenderResult\nresult {0}\nerrmsg {1}\next {2}\ndetail:\n{3}",
419 result, errmsg, ext, String.Join("\n", detail));
420 }
421 else
422 {
423 return String.Format(
424 "SmsMultiSenderResult\nresult {0}\nerrmsg {1}\next {2}\n",
425 result, errmsg, ext);
426 }
427 }
428 }
429 #endregion
430
431 #region 公共类
432 /// <summary>
433 /// 公共类
434 /// </summary>
435 class SmsSenderUtil
436 {
437 /// <summary>
438 /// 国家码
439 /// </summary>
440 public static string nationCode = "86";
441 /// <summary>
442 /// 随机数生成器
443 /// </summary>
444 private Random random = new Random();
445
446 #region GetPostHttpConn
447 /// <summary>
448 /// GetPostHttpConn
449 /// </summary>
450 /// <param name="url"></param>
451 /// <returns></returns>
452 public HttpWebRequest GetPostHttpConn(string url)
453 {
454 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
455 request.Method = "POST";
456 request.ContentType = "application/x-www-form-urlencoded";
457 return request;
458 }
459 #endregion
460
461 #region 生成随机数
462 /// <summary>
463 /// 生成随机数
464 /// </summary>
465 /// <returns></returns>
466 public long GetRandom()
467 {
468 return random.Next(999999) % 900000 + 100000;
469 }
470 #endregion
471
472 #region 获取请求发起时间
473 /// <summary>
474 /// 获取请求发起时间,
475 /// unix 时间戳(单位:秒),如果和系统时间相差超过 10 分钟则会返回失败
476 /// </summary>
477 /// <returns></returns>
478 public long GetCurTime()
479 {
480 Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
481 return unixTimestamp;
482 }
483 #endregion
484
485 #region 字符串转SHA256
486 /// <summary>
487 /// 字符串转SHA256
488 /// </summary>
489 /// <param name="str"></param>
490 /// <returns></returns>
491 public string StrToHash(string str)
492 {
493 SHA256 sha256 = SHA256Managed.Create();
494 byte[] resultByteArray = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(str));
495 return ByteArrayToHex(resultByteArray);
496 }
497
498 /// <summary>
499 /// 将二进制的数值转换为 16 进制字符串,如 "abc" => "616263"
500 /// </summary>
501 /// <param name="byteArray"></param>
502 /// <returns></returns>
503 private static string ByteArrayToHex(byte[] byteArray)
504 {
505 string returnStr = "";
506 if (byteArray != null)
507 {
508 for (int i = 0; i < byteArray.Length; i++)
509 {
510 returnStr += byteArray[i].ToString("x2");
511 }
512 }
513 return returnStr;
514 }
515 #endregion
516
517 #region 将单发回包解析成结果对象
518 /// <summary>
519 /// 将单发回包解析成结果对象
520 /// </summary>
521 /// <param name="str"></param>
522 /// <returns></returns>
523 public SmsSingleSenderResult ResponseStrToSingleSenderResult(string str)
524 {
525 SmsSingleSenderResult result = JsonConvert.DeserializeObject<SmsSingleSenderResult>(str);
526 return result;
527 }
528 #endregion
529
530 #region 将群发回包解析成结果对象
531 /// <summary>
532 /// 将群发回包解析成结果对象
533 /// </summary>
534 /// <param name="str"></param>
535 /// <returns></returns>
536 public SmsMultiSenderResult ResponseStrToMultiSenderResult(string str)
537 {
538 SmsMultiSenderResult result = JsonConvert.DeserializeObject<SmsMultiSenderResult>(str);
539 return result;
540 }
541 #endregion
542
543 #region List<string>转JArray
544 /// <summary>
545 /// List<string>转JArray
546 /// </summary>
547 /// <param name="templParams"></param>
548 /// <returns></returns>
549 public JArray SmsParamsToJSONArray(List<string> templParams)
550 {
551 JArray smsParams = new JArray();
552 foreach (string templParamsElement in templParams)
553 {
554 smsParams.Add(templParamsElement);
555 }
556 return smsParams;
557 }
558 #endregion
559
560 #region PhoneNumbersToJSONArray
561 /// <summary>
562 /// PhoneNumbersToJSONArray
563 /// </summary>
564 /// <param name="nationCode"></param>
565 /// <param name="phoneNumbers"></param>
566 /// <returns></returns>
567 public JArray PhoneNumbersToJSONArray(string nationCode, List<string> phoneNumbers)
568 {
569 JArray tel = new JArray();
570 int i = 0;
571 do
572 {
573 JObject telElement = new JObject();
574 telElement.Add("nationcode", nationCode);
575 telElement.Add("mobile", phoneNumbers.ElementAt(i));
576 tel.Add(telElement);
577 } while (++i < phoneNumbers.Count);
578 return tel;
579 }
580 #endregion
581
582 #region 计算App凭证
583 /*
584 "sig" 字段根据公式 sha256(appkey=$appkey&random=$random&time=$time&mobile=$mobile)生成
585 */
586 public string CalculateSigForTempl(string appkey, long random, long curTime, List<string> phoneNumbers)
587 {
588 string phoneNumbersString = phoneNumbers.ElementAt(0);
589 for (int i = 1; i < phoneNumbers.Count; i++)
590 {
591 phoneNumbersString += "," + phoneNumbers.ElementAt(i);
592 }
593 return StrToHash(String.Format(
594 "appkey={0}&random={1}&time={2}&mobile={3}",
595 appkey, random, curTime, phoneNumbersString));
596 }
597
598 public string CalculateSigForTempl(string appkey, long random, long curTime, string phoneNumber)
599 {
600 List<string> phoneNumbers = new List<string>();
601 phoneNumbers.Add(phoneNumber);
602 return CalculateSigForTempl(appkey, random, curTime, phoneNumbers);
603 }
604
605 public string CalculateSig(string appkey, long random, long curTime, List<string> phoneNumbers)
606 {
607 string phoneNumbersString = phoneNumbers.ElementAt(0);
608 for (int i = 1; i < phoneNumbers.Count; i++)
609 {
610 phoneNumbersString += "," + phoneNumbers.ElementAt(i);
611 }
612 return StrToHash(String.Format(
613 "appkey={0}&random={1}&time={2}&mobile={3}",
614 appkey, random, curTime, phoneNumbersString));
615 }
616 #endregion
617 }
618 #endregion
619 }
demo下载路径为:https://files.cnblogs.com/files/LikeHeart/ConsoleTest.zip
Windows操作系统下Redis服务安装图文详解
Redis下载地址:https://github.com/MSOpenTech/redis/releases
下载msi格式的安装文件。
1.运行安装程序,单击next按钮。

2.勾选接受许可协议中的条款,单击next按钮。

3.选择安装目录,勾选添加到环境变量,单击next按钮。

4.端口号以及防火墙添加例外,单击next按钮。

5.是否设置最大内存限制,默认不勾选,单击next按钮。

6.开始安装,单击Insatll按钮。

7.等待安装,耗时不超过一分钟。

8.安装完成,单击Finsh按钮。

9.安装目录文件如下所示。

10.可以从服务中查看到redis服务已经正常运行。

Redis入门学习
一、软件安装
Redis下载地址:https://github.com/MSOpenTech/redis/releases
因为官方并不支持windows系统,需要从微软的GitHub上下载。
解压缩后文件夹内容如图所示(版本3.2.100):

最开始会用到的文件有redis-server.exe、redis-cli.exe以及一个配置文件redis.windows.conf。
1)启动redis服务,运行cmd.exe
进入到redis文件夹
cd desttop/redis
启动redis-server.exe 并使用配置文件,出现如下图所示就是启动成功了。
redis-server.exe redis.windows.conf

2)启动客户端,再打开一个cmd.exe
进入到文件夹后启动redis-cli.exe
redis-cli.exe
国际惯例,ping helloworld ,解锁熟练掌握redis的成就。

3)为什么默认使用6379端口
Redis作者antirez同学在twitter上说将在下一篇博文(http://oldblog.antirez.com/post/redis-as-LRU-cache.html)中向大家解释为什么他选择6379作为默认端口号。而现在这篇博文出炉,在解释了Redis的LRU机制之后,如期向大家解释了采用6379作为默认端口的原因。6379在是手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字。
二、基本用法
redis是以kev-value形式进行数据存储的,value有字符串、哈希表、列表、集合、有序集合等。
一些命令的使用,可以参考http://doc.redisfans.com/学习。
配置文件的使用,redis.windows-service.conf(以windows服务运行时修改),
1.密码修改
# requirepass foobared //去掉注释#,将foobared替换为你自己的密码
2.文件命名修改
dbfilename dump.rdb // xxxx.rdb
三、C#使用Redis
1)使用到的第三方dll:
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" /> <package id="StackExchange.Redis" version="1.2.6" targetFramework="net45" />
2)搜集到的RedisHelper方法,增加了批量操作
1 /// <summary>
2 /// Redis操作
3 /// </summary>
4 public class RedisHelper
5 {
6 /// <summary>
7 /// 连接redis库的Number
8 /// </summary>
9 private int DbNum { set; get; }
10 private readonly ConnectionMultiplexer _conn;
11 /// <summary>
12 /// 自定义键前缀
13 /// </summary>
14 public string CustomKey;
15
16 #region 构造函数
17
18 public RedisHelper(int dbNum = 0)
19 : this(dbNum, null)
20 {
21 }
22
23 public RedisHelper(int dbNum, string readWriteHosts)
24 {
25 DbNum = dbNum;
26 _conn =
27 string.IsNullOrWhiteSpace(readWriteHosts) ?
28 RedisConnectionHelp.Instance :
29 RedisConnectionHelp.GetConnectionMultiplexer(readWriteHosts);
30 }
31
32 #endregion 构造函数
33
34 #region String
35
36 #region 同步方法
37
38 /// <summary>
39 /// 保存单个key value
40 /// </summary>
41 /// <param name="key">Redis Key</param>
42 /// <param name="value">保存的值</param>
43 /// <param name="expiry">过期时间</param>
44 /// <returns></returns>
45 public bool StringSet(string key, string value, TimeSpan? expiry = default(TimeSpan?))
46 {
47 key = AddSysCustomKey(key);
48 return Do(db => db.StringSet(key, value, expiry));
49 }
50
51 /// <summary>
52 /// 保存多个key value
53 /// </summary>
54 /// <param name="keyValues">键值对</param>
55 /// <returns></returns>
56 public bool StringSet(List<KeyValuePair<RedisKey, RedisValue>> keyValues)
57 {
58 List<KeyValuePair<RedisKey, RedisValue>> newkeyValues =
59 keyValues.Select(p => new KeyValuePair<RedisKey, RedisValue>(AddSysCustomKey(p.Key), p.Value)).ToList();
60 return Do(db => db.StringSet(newkeyValues.ToArray()));
61 }
62
63 /// <summary>
64 /// 保存一个对象
65 /// </summary>
66 /// <typeparam name="T"></typeparam>
67 /// <param name="key"></param>
68 /// <param name="obj"></param>
69 /// <param name="expiry"></param>
70 /// <returns></returns>
71 public bool StringSet<T>(string key, T obj, TimeSpan? expiry = default(TimeSpan?))
72 {
73 key = AddSysCustomKey(key);
74 string json = ConvertJson(obj);
75 return Do(db => db.StringSet(key, json, expiry));
76 }
77
78 /// <summary>
79 /// 获取单个key的值
80 /// </summary>
81 /// <param name="key">Redis Key</param>
82 /// <returns></returns>
83 public byte[] StringGet(string key)
84 {
85 key = AddSysCustomKey(key);
86 return Do(db => db.StringGet(key));
87 }
88
89 /// <summary>
90 /// 获取多个Key
91 /// </summary>
92 /// <param name="listKey">Redis Key集合</param>
93 /// <returns></returns>
94 public RedisValue[] StringGet(List<string> listKey)
95 {
96 List<string> newKeys = listKey.Select(AddSysCustomKey).ToList();
97 return Do(db => db.StringGet(ConvertRedisKeys(newKeys)));
98 }
99
100 /// <summary>
101 /// 获取一个key的对象
102 /// </summary>
103 /// <typeparam name="T"></typeparam>
104 /// <param name="key"></param>
105 /// <returns></returns>
106 public T StringGet<T>(string key)
107 {
108 key = AddSysCustomKey(key);
109 return Do(db => ConvertObj<T>(db.StringGet(key)));
110 }
111
112 public object StringGetObj(string key)
113 {
114 key = AddSysCustomKey(key);
115 var database = _conn.GetDatabase(DbNum);
116 return database.StringGet(key);
117 }
118
119 public static object GetObjFromBytes(byte[] buffer)
120 {
121 using (System.IO.MemoryStream stream = new System.IO.MemoryStream(buffer))
122 {
123 stream.Position = 0;
124 System.Runtime.Serialization.IFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
125 Object reobj = bf.Deserialize(stream);
126 return reobj;
127 }
128 }
129
130 /// <summary>
131 /// 为数字增长val
132 /// </summary>
133 /// <param name="key"></param>
134 /// <param name="val">可以为负</param>
135 /// <returns>增长后的值</returns>
136 public double StringIncrement(string key, double val = 1)
137 {
138 key = AddSysCustomKey(key);
139 return Do(db => db.StringIncrement(key, val));
140 }
141
142 /// <summary>
143 /// 为数字减少val
144 /// </summary>
145 /// <param name="key"></param>
146 /// <param name="val">可以为负</param>
147 /// <returns>减少后的值</returns>
148 public double StringDecrement(string key, double val = 1)
149 {
150 key = AddSysCustomKey(key);
151 return Do(db => db.StringDecrement(key, val));
152 }
153
154 #endregion 同步方法
155
156 #region 异步方法
157
158 /// <summary>
159 /// 保存单个key value
160 /// </summary>
161 /// <param name="key">Redis Key</param>
162 /// <param name="value">保存的值</param>
163 /// <param name="expiry">过期时间</param>
164 /// <returns></returns>
165 public async Task<bool> StringSetAsync(string key, string value, TimeSpan? expiry = default(TimeSpan?))
166 {
167 key = AddSysCustomKey(key);
168 return await Do(db => db.StringSetAsync(key, value, expiry));
169 }
170
171 /// <summary>
172 /// 保存多个key value
173 /// </summary>
174 /// <param name="keyValues">键值对</param>
175 /// <returns></returns>
176 public async Task<bool> StringSetAsync(List<KeyValuePair<RedisKey, RedisValue>> keyValues)
177 {
178 List<KeyValuePair<RedisKey, RedisValue>> newkeyValues =
179 keyValues.Select(p => new KeyValuePair<RedisKey, RedisValue>(AddSysCustomKey(p.Key), p.Value)).ToList();
180 return await Do(db => db.StringSetAsync(newkeyValues.ToArray()));
181 }
182
183 /// <summary>
184 /// 保存一个对象
185 /// </summary>
186 /// <typeparam name="T"></typeparam>
187 /// <param name="key"></param>
188 /// <param name="obj"></param>
189 /// <param name="expiry"></param>
190 /// <returns></returns>
191 public async Task<bool> StringSetAsync<T>(string key, T obj, TimeSpan? expiry = default(TimeSpan?))
192 {
193 key = AddSysCustomKey(key);
194 string json = ConvertJson(obj);
195 return await Do(db => db.StringSetAsync(key, json, expiry));
196 }
197
198 /// <summary>
199 /// 获取单个key的值
200 /// </summary>
201 /// <param name="key">Redis Key</param>
202 /// <returns></returns>
203 public async Task<string> StringGetAsync(string key)
204 {
205 key = AddSysCustomKey(key);
206 return await Do(db => db.StringGetAsync(key));
207 }
208
209 /// <summary>
210 /// 获取多个Key
211 /// </summary>
212 /// <param name="listKey">Redis Key集合</param>
213 /// <returns></returns>
214 public async Task<RedisValue[]> StringGetAsync(List<string> listKey)
215 {
216 List<string> newKeys = listKey.Select(AddSysCustomKey).ToList();
217 return await Do(db => db.StringGetAsync(ConvertRedisKeys(newKeys)));
218 }
219
220 /// <summary>
221 /// 获取一个key的对象
222 /// </summary>
223 /// <typeparam name="T"></typeparam>
224 /// <param name="key"></param>
225 /// <returns></returns>
226 public async Task<T> StringGetAsync<T>(string key)
227 {
228 key = AddSysCustomKey(key);
229 string result = await Do(db => db.StringGetAsync(key));
230 return ConvertObj<T>(result);
231 }
232
233 /// <summary>
234 /// 为数字增长val
235 /// </summary>
236 /// <param name="key"></param>
237 /// <param name="val">可以为负</param>
238 /// <returns>增长后的值</returns>
239 public async Task<double> StringIncrementAsync(string key, double val = 1)
240 {
241 key = AddSysCustomKey(key);
242 return await Do(db => db.StringIncrementAsync(key, val));
243 }
244
245 /// <summary>
246 /// 为数字减少val
247 /// </summary>
248 /// <param name="key"></param>
249 /// <param name="val">可以为负</param>
250 /// <returns>减少后的值</returns>
251 public async Task<double> StringDecrementAsync(string key, double val = 1)
252 {
253 key = AddSysCustomKey(key);
254 return await Do(db => db.StringDecrementAsync(key, val));
255 }
256
257 #endregion 异步方法
258
259 #endregion String
260
261 #region Hash
262
263 #region 同步方法
264
265 /// <summary>
266 /// 判断某个数据是否已经被缓存
267 /// </summary>
268 /// <param name="key"></param>
269 /// <param name="dataKey"></param>
270 /// <returns></returns>
271 public bool HashExists(string key, string dataKey)
272 {
273 key = AddSysCustomKey(key);
274 return Do(db => db.HashExists(key, dataKey));
275 }
276
277 /// <summary>
278 /// 存储数据到hash表
279 /// </summary>
280 /// <typeparam name="T"></typeparam>
281 /// <param name="key"></param>
282 /// <param name="dataKey"></param>
283 /// <param name="t"></param>
284 /// <returns></returns>
285 public bool HashSet<T>(string key, string dataKey, T t)
286 {
287 key = AddSysCustomKey(key);
288 return Do(db =>
289 {
290 string json = ConvertJson(t);
291 return db.HashSet(key, dataKey, json);
292 });
293 }
294
295 /// <summary>
296 /// 移除hash中的某值
297 /// </summary>
298 /// <param name="key"></param>
299 /// <param name="dataKey"></param>
300 /// <returns></returns>
301 public bool HashDelete(string key, string dataKey)
302 {
303 key = AddSysCustomKey(key);
304 return Do(db => db.HashDelete(key, dataKey));
305 }
306
307 /// <summary>
308 /// 移除hash中的多个值
309 /// </summary>
310 /// <param name="key"></param>
311 /// <param name="dataKeys"></param>
312 /// <returns></returns>
313 public long HashDelete(string key, List<RedisValue> dataKeys)
314 {
315 key = AddSysCustomKey(key);
316 //List<RedisValue> dataKeys1 = new List<RedisValue>() {"1","2"};
317 return Do(db => db.HashDelete(key, dataKeys.ToArray()));
318 }
319
320 /// <summary>
321 /// 从hash表获取数据
322 /// </summary>
323 /// <typeparam name="T"></typeparam>
324 /// <param name="key"></param>
325 /// <param name="dataKey"></param>
326 /// <returns></returns>
327 public T HashGet<T>(string key, string dataKey)
328 {
329 key = AddSysCustomKey(key);
330 return Do(db =>
331 {
332 string value = db.HashGet(key, dataKey);
333 return ConvertObj<T>(value);
334 });
335 }
336
337 /// <summary>
338 /// 为数字增长val
339 /// </summary>
340 /// <param name="key"></param>
341 /// <param name="dataKey"></param>
342 /// <param name="val">可以为负</param>
343 /// <returns>增长后的值</returns>
344 public double HashIncrement(string key, string dataKey, double val = 1)
345 {
346 key = AddSysCustomKey(key);
347 return Do(db => db.HashIncrement(key, dataKey, val));
348 }
349
350 /// <summary>
351 /// 为数字减少val
352 /// </summary>
353 /// <param name="key"></param>
354 /// <param name="dataKey"></param>
355 /// <param name="val">可以为负</param>
356 /// <returns>减少后的值</returns>
357 public double HashDecrement(string key, string dataKey, double val = 1)
358 {
359 key = AddSysCustomKey(key);
360 return Do(db => db.HashDecrement(key, dataKey, val));
361 }
362
363 /// <summary>
364 /// 获取hashkey所有Redis key
365 /// </summary>
366 /// <typeparam name="T"></typeparam>
367 /// <param name="key"></param>
368 /// <returns></returns>
369 public List<T> HashKeys<T>(string key)
370 {
371 key = AddSysCustomKey(key);
372 return Do(db =>
373 {
374 RedisValue[] values = db.HashKeys(key);
375 return ConvetList<T>(values);
376 });
377 }
378
379 #endregion 同步方法
380
381 #region 异步方法
382
383 /// <summary>
384 /// 判断某个数据是否已经被缓存
385 /// </summary>
386 /// <param name="key"></param>
387 /// <param name="dataKey"></param>
388 /// <returns></returns>
389 public async Task<bool> HashExistsAsync(string key, string dataKey)
390 {
391 key = AddSysCustomKey(key);
392 return await Do(db => db.HashExistsAsync(key, dataKey));
393 }
394
395 /// <summary>
396 /// 存储数据到hash表
397 /// </summary>
398 /// <typeparam name="T"></typeparam>
399 /// <param name="key"></param>
400 /// <param name="dataKey"></param>
401 /// <param name="t"></param>
402 /// <returns></returns>
403 public async Task<bool> HashSetAsync<T>(string key, string dataKey, T t)
404 {
405 key = AddSysCustomKey(key);
406 return await Do(db =>
407 {
408 string json = ConvertJson(t);
409 return db.HashSetAsync(key, dataKey, json);
410 });
411 }
412
413 /// <summary>
414 /// 移除hash中的某值
415 /// </summary>
416 /// <param name="key"></param>
417 /// <param name="dataKey"></param>
418 /// <returns></returns>
419 public async Task<bool> HashDeleteAsync(string key, string dataKey)
420 {
421 key = AddSysCustomKey(key);
422 return await Do(db => db.HashDeleteAsync(key, dataKey));
423 }
424
425 /// <summary>
426 /// 移除hash中的多个值
427 /// </summary>
428 /// <param name="key"></param>
429 /// <param name="dataKeys"></param>
430 /// <returns></returns>
431 public async Task<long> HashDeleteAsync(string key, List<RedisValue> dataKeys)
432 {
433 key = AddSysCustomKey(key);
434 //List<RedisValue> dataKeys1 = new List<RedisValue>() {"1","2"};
435 return await Do(db => db.HashDeleteAsync(key, dataKeys.ToArray()));
436 }
437
438 /// <summary>
439 /// 从hash表获取数据
440 /// </summary>
441 /// <typeparam name="T"></typeparam>
442 /// <param name="key"></param>
443 /// <param name="dataKey"></param>
444 /// <returns></returns>
445 public async Task<T> HashGeAsync<T>(string key, string dataKey)
446 {
447 key = AddSysCustomKey(key);
448 string value = await Do(db => db.HashGetAsync(key, dataKey));
449 return ConvertObj<T>(value);
450 }
451
452 /// <summary>
453 /// 为数字增长val
454 /// </summary>
455 /// <param name="key"></param>
456 /// <param name="dataKey"></param>
457 /// <param name="val">可以为负</param>
458 /// <returns>增长后的值</returns>
459 public async Task<double> HashIncrementAsync(string key, string dataKey, double val = 1)
460 {
461 key = AddSysCustomKey(key);
462 return await Do(db => db.HashIncrementAsync(key, dataKey, val));
463 }
464
465 /// <summary>
466 /// 为数字减少val
467 /// </summary>
468 /// <param name="key"></param>
469 /// <param name="dataKey"></param>
470 /// <param name="val">可以为负</param>
471 /// <returns>减少后的值</returns>
472 public async Task<double> HashDecrementAsync(string key, string dataKey, double val = 1)
473 {
474 key = AddSysCustomKey(key);
475 return await Do(db => db.HashDecrementAsync(key, dataKey, val));
476 }
477
478 /// <summary>
479 /// 获取hashkey所有Redis key
480 /// </summary>
481 /// <typeparam name="T"></typeparam>
482 /// <param name="key"></param>
483 /// <returns></returns>
484 public async Task<List<T>> HashKeysAsync<T>(string key)
485 {
486 key = AddSysCustomKey(key);
487 RedisValue[] values = await Do(db => db.HashKeysAsync(key));
488 return ConvetList<T>(values);
489 }
490
491 #endregion 异步方法
492
493 #endregion Hash
494
495 #region List
496
497 #region 同步方法
498
499 /// <summary>
500 /// 移除指定ListId的内部List的值
501 /// </summary>
502 /// <param name="key"></param>
503 /// <param name="value"></param>
504 public void ListRemove<T>(string key, T value)
505 {
506 key = AddSysCustomKey(key);
507 Do(db => db.ListRemove(key, ConvertJson(value)));
508 }
509
510 /// <summary>
511 /// 获取指定key的List
512 /// </summary>
513 /// <param name="key"></param>
514 /// <returns></returns>
515 public List<T> ListRange<T>(string key)
516 {
517 key = AddSysCustomKey(key);
518 return Do(redis =>
519 {
520 var values = redis.ListRange(key);
521 return ConvetList<T>(values);
522 });
523 }
524
525 /// <summary>
526 /// 入队
527 /// </summary>
528 /// <param name="key"></param>
529 /// <param name="value"></param>
530 public void ListRightPush<T>(string key, T value)
531 {
532 key = AddSysCustomKey(key);
533 Do(db => db.ListRightPush(key, ConvertJson(value)));
534 }
535
536 /// <summary>
537 /// 出队
538 /// </summary>
539 /// <typeparam name="T"></typeparam>
540 /// <param name="key"></param>
541 /// <returns></returns>
542 public T ListRightPop<T>(string key)
543 {
544 key = AddSysCustomKey(key);
545 return Do(db =>
546 {
547 var value = db.ListRightPop(key);
548 return ConvertObj<T>(value);
549 });
550 }
551
552 /// <summary>
553 /// 入栈
554 /// </summary>
555 /// <typeparam name="T"></typeparam>
556 /// <param name="key"></param>
557 /// <param name="value"></param>
558 public void ListLeftPush<T>(string key, T value)
559 {
560 key = AddSysCustomKey(key);
561 Do(db => db.ListLeftPush(key, ConvertJson(value)));
562 }
563
564 /// <summary>
565 /// 出栈
566 /// </summary>
567 /// <typeparam name="T"></typeparam>
568 /// <param name="key"></param>
569 /// <returns></returns>
570 public T ListLeftPop<T>(string key)
571 {
572 key = AddSysCustomKey(key);
573 return Do(db =>
574 {
575 var value = db.ListLeftPop(key);
576 return ConvertObj<T>(value);
577 });
578 }
579
580 /// <summary>
581 /// 获取集合中的数量
582 /// </summary>
583 /// <param name="key"></param>
584 /// <returns></returns>
585 public long ListLength(string key)
586 {
587 key = AddSysCustomKey(key);
588 return Do(redis => redis.ListLength(key));
589 }
590
591 #endregion 同步方法
592
593 #region 异步方法
594
595 /// <summary>
596 /// 移除指定ListId的内部List的值
597 /// </summary>
598 /// <param name="key"></param>
599 /// <param name="value"></param>
600 public async Task<long> ListRemoveAsync<T>(string key, T value)
601 {
602 key = AddSysCustomKey(key);
603 return await Do(db => db.ListRemoveAsync(key, ConvertJson(value)));
604 }
605
606 /// <summary>
607 /// 获取指定key的List
608 /// </summary>
609 /// <param name="key"></param>
610 /// <returns></returns>
611 public async Task<List<T>> ListRangeAsync<T>(string key)
612 {
613 key = AddSysCustomKey(key);
614 var values = await Do(redis => redis.ListRangeAsync(key));
615 return ConvetList<T>(values);
616 }
617
618 /// <summary>
619 /// 入队
620 /// </summary>
621 /// <param name="key"></param>
622 /// <param name="value"></param>
623 public async Task<long> ListRightPushAsync<T>(string key, T value)
624 {
625 key = AddSysCustomKey(key);
626 return await Do(db => db.ListRightPushAsync(key, ConvertJson(value)));
627 }
628
629 /// <summary>
630 /// 出队
631 /// </summary>
632 /// <typeparam name="T"></typeparam>
633 /// <param name="key"></param>
634 /// <returns></returns>
635 public async Task<T> ListRightPopAsync<T>(string key)
636 {
637 key = AddSysCustomKey(key);
638 var value = await Do(db => db.ListRightPopAsync(key));
639 return ConvertObj<T>(value);
640 }
641
642 /// <summary>
643 /// 入栈
644 /// </summary>
645 /// <typeparam name="T"></typeparam>
646 /// <param name="key"></param>
647 /// <param name="value"></param>
648 public async Task<long> ListLeftPushAsync<T>(string key, T value)
649 {
650 key = AddSysCustomKey(key);
651 return await Do(db => db.ListLeftPushAsync(key, ConvertJson(value)));
652 }
653
654 /// <summary>
655 /// 出栈
656 /// </summary>
657 /// <typeparam name="T"></typeparam>
658 /// <param name="key"></param>
659 /// <returns></returns>
660 public async Task<T> ListLeftPopAsync<T>(string key)
661 {
662 key = AddSysCustomKey(key);
663 var value = await Do(db => db.ListLeftPopAsync(key));
664 return ConvertObj<T>(value);
665 }
666
667 /// <summary>
668 /// 获取集合中的数量
669 /// </summary>
670 /// <param name="key"></param>
671 /// <returns></returns>
672 public async Task<long> ListLengthAsync(string key)
673 {
674 key = AddSysCustomKey(key);
675 return await Do(redis => redis.ListLengthAsync(key));
676 }
677
678 #endregion 异步方法
679
680 #endregion List
681
682 #region SortedSet 有序集合
683
684 #region 同步方法
685
686 /// <summary>
687 /// 添加
688 /// </summary>
689 /// <param name="key"></param>
690 /// <param name="value"></param>
691 /// <param name="score"></param>
692 public bool SortedSetAdd<T>(string key, T value, double score)
693 {
694 key = AddSysCustomKey(key);
695 return Do(redis => redis.SortedSetAdd(key, ConvertJson<T>(value), score));
696 }
697
698 /// <summary>
699 /// 删除
700 /// </summary>
701 /// <param name="key"></param>
702 /// <param name="value"></param>
703 public bool SortedSetRemove<T>(string key, T value)
704 {
705 key = AddSysCustomKey(key);
706 return Do(redis => redis.SortedSetRemove(key, ConvertJson(value)));
707 }
708
709 /// <summary>
710 /// 获取全部
711 /// </summary>
712 /// <param name="key"></param>
713 /// <returns></returns>
714 public List<T> SortedSetRangeByRank<T>(string key)
715 {
716 key = AddSysCustomKey(key);
717 return Do(redis =>
718 {
719 var values = redis.SortedSetRangeByRank(key);
720 return ConvetList<T>(values);
721 });
722 }
723
724 /// <summary>
725 /// 获取集合中的数量
726 /// </summary>
727 /// <param name="key"></param>
728 /// <returns></returns>
729 public long SortedSetLength(string key)
730 {
731 key = AddSysCustomKey(key);
732 return Do(redis => redis.SortedSetLength(key));
733 }
734
735 #endregion 同步方法
736
737 #region 异步方法
738
739 /// <summary>
740 /// 添加
741 /// </summary>
742 /// <param name="key"></param>
743 /// <param name="value"></param>
744 /// <param name="score"></param>
745 public async Task<bool> SortedSetAddAsync<T>(string key, T value, double score)
746 {
747 key = AddSysCustomKey(key);
748 return await Do(redis => redis.SortedSetAddAsync(key, ConvertJson<T>(value), score));
749 }
750
751 /// <summary>
752 /// 删除
753 /// </summary>
754 /// <param name="key"></param>
755 /// <param name="value"></param>
756 public async Task<bool> SortedSetRemoveAsync<T>(string key, T value)
757 {
758 key = AddSysCustomKey(key);
759 return await Do(redis => redis.SortedSetRemoveAsync(key, ConvertJson(value)));
760 }
761
762 /// <summary>
763 /// 获取全部
764 /// </summary>
765 /// <param name="key"></param>
766 /// <returns></returns>
767 public async Task<List<T>> SortedSetRangeByRankAsync<T>(string key)
768 {
769 key = AddSysCustomKey(key);
770 var values = await Do(redis => redis.SortedSetRangeByRankAsync(key));
771 return ConvetList<T>(values);
772 }
773
774 /// <summary>
775 /// 获取集合中的数量
776 /// </summary>
777 /// <param name="key"></param>
778 /// <returns></returns>
779 public async Task<long> SortedSetLengthAsync(string key)
780 {
781 key = AddSysCustomKey(key);
782 return await Do(redis => redis.SortedSetLengthAsync(key));
783 }
784
785 #endregion 异步方法
786
787 #endregion SortedSet 有序集合
788
789 #region key
790
791 /// <summary>
792 /// 删除单个key
793 /// </summary>
794 /// <param name="key">redis key</param>
795 /// <returns>是否删除成功</returns>
796 public bool KeyDelete(string key)
797 {
798 key = AddSysCustomKey(key);
799 return Do(db => db.KeyDelete(key));
800 }
801
802 /// <summary>
803 /// 删除多个key
804 /// </summary>
805 /// <param name="keys">rediskey</param>
806 /// <returns>成功删除的个数</returns>
807 public long KeyDelete(List<string> keys)
808 {
809 List<string> newKeys = keys.Select(AddSysCustomKey).ToList();
810 return Do(db => db.KeyDelete(ConvertRedisKeys(newKeys)));
811 }
812
813 /// <summary>
814 /// 判断key是否存储
815 /// </summary>
816 /// <param name="key">redis key</param>
817 /// <returns></returns>
818 public bool KeyExists(string key)
819 {
820 key = AddSysCustomKey(key);
821 return Do(db => db.KeyExists(key));
822 }
823
824 /// <summary>
825 /// 重新命名key
826 /// </summary>
827 /// <param name="key">就的redis key</param>
828 /// <param name="newKey">新的redis key</param>
829 /// <returns></returns>
830 public bool KeyRename(string key, string newKey)
831 {
832 key = AddSysCustomKey(key);
833 return Do(db => db.KeyRename(key, newKey));
834 }
835
836 /// <summary>
837 /// 设置Key的时间
838 /// </summary>
839 /// <param name="key">redis key</param>
840 /// <param name="expiry"></param>
841 /// <returns></returns>
842 public bool KeyExpire(string key, TimeSpan? expiry = default(TimeSpan?))
843 {
844 key = AddSysCustomKey(key);
845 return Do(db => db.KeyExpire(key, expiry));
846 }
847
848 #endregion key
849
850 #region 发布订阅
851
852 /// <summary>
853 /// Redis发布订阅 订阅
854 /// </summary>
855 /// <param name="subChannel"></param>
856 /// <param name="handler"></param>
857 public void Subscribe(string subChannel, Action<RedisChannel, RedisValue> handler = null)
858 {
859 ISubscriber sub = _conn.GetSubscriber();
860 sub.Subscribe(subChannel, (channel, message) =>
861 {
862 if (handler == null)
863 {
864 Console.WriteLine(subChannel + " 订阅收到消息:" + message);
865 }
866 else
867 {
868 handler(channel, message);
869 }
870 });
871 }
872
873 /// <summary>
874 /// Redis发布订阅 发布
875 /// </summary>
876 /// <typeparam name="T"></typeparam>
877 /// <param name="channel"></param>
878 /// <param name="msg"></param>
879 /// <returns></returns>
880 public long Publish<T>(string channel, T msg)
881 {
882 ISubscriber sub = _conn.GetSubscriber();
883 return sub.Publish(channel, ConvertJson(msg));
884 }
885
886 /// <summary>
887 /// Redis发布订阅 取消订阅
888 /// </summary>
889 /// <param name="channel"></param>
890 public void Unsubscribe(string channel)
891 {
892 ISubscriber sub = _conn.GetSubscriber();
893 sub.Unsubscribe(channel);
894 }
895
896 /// <summary>
897 /// Redis发布订阅 取消全部订阅
898 /// </summary>
899 public void UnsubscribeAll()
900 {
901 ISubscriber sub = _conn.GetSubscriber();
902 sub.UnsubscribeAll();
903 }
904
905 #endregion 发布订阅
906
907 #region 其他
908
909 public ITransaction CreateTransaction()
910 {
911 return GetDatabase().CreateTransaction();
912 }
913
914 public IDatabase GetDatabase()
915 {
916 return _conn.GetDatabase(DbNum);
917 }
918
919 public IServer GetServer(string hostAndPort)
920 {
921 return _conn.GetServer(hostAndPort);
922 }
923
924 /// <summary>
925 /// 设置前缀
926 /// </summary>
927 /// <param name="customKey"></param>
928 public void SetSysCustomKey(string customKey)
929 {
930 CustomKey = customKey;
931 }
932
933 #endregion 其他
934
935 #region 辅助方法
936
937 private string AddSysCustomKey(string oldKey)
938 {
939 var prefixKey = CustomKey ?? RedisConnectionHelp.SysCustomKey;
940 return prefixKey + oldKey;
941 }
942
943 private T Do<T>(Func<IDatabase, T> func)
944 {
945 var database = _conn.GetDatabase(DbNum);
946 return func(database);
947 }
948
949 public string ConvertJson<T>(T value)
950 {
951 string result = value is string ? value.ToString() : JsonConvert.SerializeObject(value);
952 return result;
953 }
954
955 public T ConvertObj<T>(RedisValue value)
956 {
957 return JsonConvert.DeserializeObject<T>(value);
958 }
959
960 private List<T> ConvetList<T>(RedisValue[] values)
961 {
962 List<T> result = new List<T>();
963 foreach (var item in values)
964 {
965 var model = ConvertObj<T>(item);
966 result.Add(model);
967 }
968 return result;
969 }
970
971 private RedisKey[] ConvertRedisKeys(List<string> redisKeys)
972 {
973 return redisKeys.Select(redisKey => (RedisKey)redisKey).ToArray();
974 }
975
976 #endregion 辅助方法
977
978 #region 批量操作
979
980 #region 批量写Key-Value
981 /// <summary>
982 /// 批量写Key-Value
983 /// </summary>
984 /// <param name="keyValues"></param>
985 /// <returns></returns>
986 public bool StringWriteBatch(List<KeyValuePair<RedisKey, RedisValue>> keyValues)
987 {
988 bool result = false;
989 try
990 {
991 var db = _conn.GetDatabase();
992 var batch = db.CreateBatch();
993 foreach (var item in keyValues)
994 {
995 batch.StringSetAsync(item.Key, item.Value);
996 }
997 batch.Execute();
998 result = true;
999 }
1000 catch
1001 {
1002 }
1003 return result;
1004 }
1005 #endregion
1006
1007 #region 批量读Key-Value
1008 /// <summary>
1009 /// 批量读Key-Value
1010 /// </summary>
1011 /// <typeparam name="T"></typeparam>
1012 /// <param name="lstKey"></param>
1013 /// <returns></returns>
1014 public List<T> StringReadBatch<T>(List<RedisKey> lstKey)
1015 {
1016 List<Task<RedisValue>> valueList = new List<Task<RedisValue>>();
1017 List<T> lstResult = new List<T>();
1018 try
1019 {
1020 var db = _conn.GetDatabase();
1021 var batch = db.CreateBatch();
1022 foreach (var item in lstKey)
1023 {
1024 Task<RedisValue> value = batch.StringGetAsync(item);
1025 valueList.Add(value);
1026 }
1027 batch.Execute();
1028
1029 foreach (var item in valueList)
1030 {
1031 T t = ConvertObj<T>(item.Result);
1032 lstResult.Add(t);
1033 }
1034 }
1035 catch
1036 {
1037 }
1038 return lstResult;
1039 }
1040
1041 /// <summary>
1042 /// 批量读操作,返回DataSe集合
1043 /// </summary>
1044 /// <param name="lstKey"></param>
1045 /// <returns></returns>
1046 public DataSet StringReadBatch(List<RedisKey> lstKey)
1047 {
1048 if (lstKey == null || lstKey.Count < 1) return null;
1049 List<Task<RedisValue>> valueList = new List<Task<RedisValue>>();
1050 DataSet ds = new DataSet();
1051 try
1052 {
1053 var db = _conn.GetDatabase();
1054 var batch = db.CreateBatch();
1055 foreach (var item in lstKey)
1056 {
1057 Task<RedisValue> value = batch.StringGetAsync(item);
1058 valueList.Add(value);
1059 }
1060 batch.Execute();
1061
1062 foreach (var item in valueList)
1063 {
1064 DataTable t = ConvertObj<DataTable>(item.Result);
1065 ds.Tables.Add(t);
1066 }
1067 }
1068 catch
1069 {
1070 }
1071 return ds;
1072 }
1073 #endregion
1074
1075 #region 批量写Hash
1076 /// <summary>
1077 /// 批量写Hash
1078 /// </summary>
1079 /// <param name="keyValues"></param>
1080 /// <returns></returns>
1081 public bool HashWriteBatch(List<KeyValuePair<RedisKey, HashEntry[]>> keyValues)
1082 {
1083 bool result = false;
1084 try
1085 {
1086 var db = _conn.GetDatabase();
1087 var batch = db.CreateBatch();
1088 foreach (var item in keyValues)
1089 {
1090 batch.HashSetAsync(item.Key, item.Value);
1091 }
1092 batch.Execute();
1093 result = true;
1094 }
1095 catch
1096 {
1097 }
1098 return result;
1099 }
1100 #endregion
1101
1102 #region 批量读Hash
1103 /// <summary>
1104 /// 批量读Hash
1105 /// </summary>
1106 ///<param name="keyFields">hash键和field</param>
1107 /// <returns></returns>
1108 public List<T> HashReadBatch<T>(List<KeyValuePair<RedisKey, RedisValue[]>> keyFields)
1109 {
1110 List<Task<RedisValue[]>> valueList = new List<Task<RedisValue[]>>();
1111 List<T> lstResult = new List<T>();
1112 try
1113 {
1114 var db = _conn.GetDatabase();
1115 var batch = db.CreateBatch();
1116 foreach (var item in keyFields)
1117 {
1118 Task<RedisValue[]> value = batch.HashGetAsync(item.Key, item.Value);
1119 valueList.Add(value);
1120 }
1121 batch.Execute();
1122
1123 foreach (var item in valueList)
1124 {
1125 if (item.Result == null) continue;
1126 foreach (var redisValue in item.Result)
1127 {
1128 T t = ConvertObj<T>(redisValue);
1129 lstResult.Add(t);
1130 }
1131 }
1132 }
1133 catch
1134 {
1135 }
1136 return lstResult;
1137 }
1138 #endregion
1139
1140 #endregion
3)单例模式
1 /// <summary>
2 /// ConnectionMultiplexer对象管理帮助类
3 /// </summary>
4 public static class RedisConnectionHelp
5 {
6 //系统自定义Key前缀
7 public static readonly string SysCustomKey = ConfigurationManager.AppSettings["redisKey"] ?? "";
8
9 //"127.0.0.1:6379,allowadmin=true
10 private static readonly string RedisConnectionString = ConfigurationManager.ConnectionStrings["RedisExchangeHosts"].ConnectionString;
11
12 private static readonly object Locker = new object();
13 private static ConnectionMultiplexer _instance;
14 private static readonly ConcurrentDictionary<string, ConnectionMultiplexer> ConnectionCache = new ConcurrentDictionary<string, ConnectionMultiplexer>();
15
16 /// <summary>
17 /// 单例获取
18 /// </summary>
19 public static ConnectionMultiplexer Instance
20 {
21 get
22 {
23 if (_instance == null)
24 {
25 lock (Locker)
26 {
27 if (_instance == null || !_instance.IsConnected)
28 {
29 _instance = GetManager();
30 }
31 }
32 }
33 return _instance;
34 }
35 }
36
37 /// <summary>
38 /// 缓存获取
39 /// </summary>
40 /// <param name="connectionString"></param>
41 /// <returns></returns>
42 public static ConnectionMultiplexer GetConnectionMultiplexer(string connectionString)
43 {
44 if (!ConnectionCache.ContainsKey(connectionString))
45 {
46 ConnectionCache[connectionString] = GetManager(connectionString);
47 }
48 return ConnectionCache[connectionString];
49 }
50
51 private static ConnectionMultiplexer GetManager(string connectionString = null)
52 {
53 connectionString = connectionString ?? RedisConnectionString;
54 var connect = ConnectionMultiplexer.Connect(connectionString);
55
56 //注册如下事件
57 connect.ConnectionFailed += MuxerConnectionFailed;
58 connect.ConnectionRestored += MuxerConnectionRestored;
59 connect.ErrorMessage += MuxerErrorMessage;
60 connect.ConfigurationChanged += MuxerConfigurationChanged;
61 connect.HashSlotMoved += MuxerHashSlotMoved;
62 connect.InternalError += MuxerInternalError;
63
64 return connect;
65 }
66
67 #region 事件
68
69 /// <summary>
70 /// 配置更改时
71 /// </summary>
72 /// <param name="sender"></param>
73 /// <param name="e"></param>
74 private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e)
75 {
76 Console.WriteLine("Configuration changed: " + e.EndPoint);
77 }
78
79 /// <summary>
80 /// 发生错误时
81 /// </summary>
82 /// <param name="sender"></param>
83 /// <param name="e"></param>
84 private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e)
85 {
86 Console.WriteLine("ErrorMessage: " + e.Message);
87 }
88
89 /// <summary>
90 /// 重新建立连接之前的错误
91 /// </summary>
92 /// <param name="sender"></param>
93 /// <param name="e"></param>
94 private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e)
95 {
96 Console.WriteLine("ConnectionRestored: " + e.EndPoint);
97 }
98
99 /// <summary>
100 /// 连接失败 , 如果重新连接成功你将不会收到这个通知
101 /// </summary>
102 /// <param name="sender"></param>
103 /// <param name="e"></param>
104 private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e)
105 {
106 Console.WriteLine("重新连接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType + (e.Exception == null ? "" : (", " + e.Exception.Message)));
107 }
108
109 /// <summary>
110 /// 更改集群
111 /// </summary>
112 /// <param name="sender"></param>
113 /// <param name="e"></param>
114 private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)
115 {
116 Console.WriteLine("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint);
117 }
118
119 /// <summary>
120 /// redis类库错误
121 /// </summary>
122 /// <param name="sender"></param>
123 /// <param name="e"></param>
124 private static void MuxerInternalError(object sender, InternalErrorEventArgs e)
125 {
126 Console.WriteLine("InternalError:Message" + e.Exception.Message);
127 }
128
129 #endregion 事件
130 }
4)app.config中增加redis连接字符串
<connectionStrings>
<add name="RedisExchangeHosts" connectionString="127.0.0.1:6379,password=xxxxxx"/>
</connectionStrings>



浙公网安备 33010602011771号