在开发过程中,我们会遇到这样一个问题,编辑了一个对象之后,我们想要把这个对象修改了哪些内容保存下来,以便将来查看和追责。
首先我们要创建一个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 Age11 {12 get { return age; }13 set { age = value; }14 }15 private string sex;16 public string Sex17 {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(userA);
1 ///2 /// 深拷贝 3 /// 4 ///5 /// 6 /// 7 public static T DeepCopyByXml (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对比,利用反射来实现该功能
////// Model对比 /// ////// /// private static void CompareModel (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; ////// 表名 /// public string TableName { get { return tableName; } set { tableName = value; } } ////// 字段名 /// public string FieldName { get { return fieldName; } set { fieldName = value; } } }
接着修改User类,加上自定义的特性TableAttribute
////// 用户信息实体类 /// [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 ///2 /// Model对比 3 /// 4 ///5 /// 6 /// 7 private static void CompareModel (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 ();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下载:
(完)
在之前介绍的火车票查询工具中,利用邮件和短信将查询结果推送给用户。免费短信的条数只有5条,用完之后只能单独使用邮件提醒。
最近发现腾讯云的福利,简单的介绍一下用法。
腾讯云-》产品-》通信服务-》短信-》开通服务-》添加应用-》创建签名和模板-》等待审核通过-》按照Demo测试
在整个流程中,最耗时的就是创建签名和模板,对个人来说只能选择app、公众号或小程序的方式进行申请,多亏之前折腾过一点小程序,从而闯关成功。
接下来查看官方Demo
整理后的测试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 SmsSDKDemo11 {12 ///13 /// appId14 /// 15 private static int appId = 140xxxxx;16 ///17 /// appKey18 /// 19 private static string appKey = "xxxxxxxxxxxxxxx";20 ///21 /// 接收手机号22 /// 23 private static string phoneNumber = "xxxxxxxx";24 ///25 /// 短信模板ID26 /// 27 private static int tmplateId = xxxxxxx;28 29 static void Main(string[] args)30 {31 try32 {33 SmsSingleSenderResult singleResult;34 SmsSingleSender singleSender = new SmsSingleSender(appId, appKey);35 36 singleResult = singleSender.Send(SmsType.普通短信, phoneNumber, "");37 Console.WriteLine(singleResult);38 39 ListtemplParams = new List ();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 ///5 /// 短信类型枚举 6 /// 7 public enum SmsType 8 { 9 普通短信 = 0, 10 营销短信 = 1 11 } 12 #endregion 13 14 #region 单发 15 ///16 /// 单发 17 /// 18 class SmsSingleSender 19 { 20 #region 变量 21 ///22 /// appId 23 /// 24 private int appId; 25 ///26 /// appkey 27 /// 28 private string appkey; 29 ///30 /// url 31 /// 32 private string url = "https://yun.tim.qq.com/v5/tlssmssvr/sendsms"; 33 ///34 /// util 35 /// 36 private SmsSenderUtil util = new SmsSenderUtil(); 37 #endregion 38 39 #region 构造 40 ///41 /// 构造函数 42 /// 43 /// 44 /// 45 public SmsSingleSender(int sdkappid, string appkey) 46 { 47 this.appId = sdkappid; 48 this.appkey = appkey; 49 } 50 #endregion 51 52 #region 普通单发短信接口 53 ///54 /// 普通单发短信接口,明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名 55 /// 56 /// 短信类型,0 为普通短信,1 营销短信 57 /// 不带国家码的手机号 58 /// 信息内容,必须与申请的模板格式一致,否则将返回错误 59 /// 短信码号扩展号,格式为纯数字串,其他格式无效。默认没有开通 60 /// 服务端原样返回的参数,可填空 61 ///SmsSingleSenderResult 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 else101 {102 result = new SmsSingleSenderResult();103 result.result = -1;104 result.errmsg = "http error " + response.StatusCode + " " + responseStr;105 }106 return result;107 }108 #endregion109 110 #region 指定模板单发111 ///112 /// 指定模板单发113 /// 114 /// 不带国家码的手机号115 /// 模板 id116 /// 模板参数列表,如模板 {1}...{2}...{3},那么需要带三个参数117 /// 短信签名,如果使用默认签名,该字段可缺省118 /// 扩展码,可填空119 /// 服务端原样返回的参数,可填空120 ///SmsSingleSenderResult 121 public SmsSingleSenderResult SendWithParam(string phoneNumber, int templId, ListtemplParams, 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 else161 {162 result = new SmsSingleSenderResult();163 result.result = -1;164 result.errmsg = "http error " + response.StatusCode + " " + responseStr;165 }166 return result;167 }168 #endregion169 }170 #endregion171 172 #region 单发结果173 /// 174 /// 单发结果175 /// 176 class SmsSingleSenderResult177 {178 ///179 /// 错误码,0 表示成功(计费依据),非 0 表示失败180 /// 181 public int result { set; get; }182 ///183 /// 错误消息,result 非 0 时的具体错误信息184 /// 185 public string errmsg { set; get; }186 ///187 /// 用户的 session 内容,腾讯 server 回包中会原样返回188 /// 189 public string ext { set; get; }190 ///191 /// 本次发送标识 id,标识一次短信下发记录192 /// 193 public string sid { set; get; }194 ///195 /// 短信计费的条数196 /// 197 public int fee { set; get; }198 ///199 /// ToString()200 /// 201 ///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 #endregion208 209 #region 群发210 /// 211 /// 群发212 /// 213 class SmsMultiSender214 {215 #region 变量216 ///217 /// appId218 /// 219 private int appId;220 ///221 /// appkey222 /// 223 private string appkey;224 ///225 /// url226 /// 227 private string url = "https://yun.tim.qq.com/v5/tlssmssvr/sendmultisms2";228 ///229 /// util230 /// 231 private SmsSenderUtil util = new SmsSenderUtil();232 #endregion233 234 #region 构造235 ///236 /// 构造237 /// 238 /// 239 /// 240 public SmsMultiSender(int sdkappid, string appkey)241 {242 this.appId = sdkappid;243 this.appkey = appkey;244 }245 #endregion246 247 #region 普通群发短信接口248 ///249 /// 普通群发短信接口,明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名250 ///【注意】 海外短信无群发功能251 /// 252 /// 短信类型,0 为普通短信,1 营销短信253 /// 254 /// 不带国家码的手机号列表255 /// 信息内容,必须与申请的模板格式一致,否则将返回错误256 /// 扩展码,可填空257 /// 服务端原样返回的参数,可填空258 ///SmsMultiSenderResult 259 public SmsMultiSenderResult Send(SmsType type, ListphoneNumbers, 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 else295 {296 result = new SmsMultiSenderResult();297 result.result = -1;298 result.errmsg = "http error " + response.StatusCode + " " + responseStr;299 }300 return result;301 }302 #endregion303 304 #region 指定模板群发305 /// 306 /// 指定模板群发307 /// 【注意】海外短信无群发功能308 /// 309 /// 不带国家码的手机号列表310 /// 模板 id311 /// 模板参数列表312 /// 签名,如果填空,系统会使用默认签名313 /// 扩展码,可以填空314 /// 服务端原样返回的参数,可以填空315 ///SmsMultiSenderResult 316 public SmsMultiSenderResult SendWithParam(ListphoneNumbers, int templId, List 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 else353 {354 result = new SmsMultiSenderResult();355 result.result = -1;356 result.errmsg = "http error " + response.StatusCode + " " + responseStr;357 }358 return result;359 }360 #endregion361 }362 #endregion363 364 #region 群发结果365 /// 366 /// 群发结果367 /// 368 class SmsMultiSenderResult369 {370 public class Detail371 {372 ///373 /// 错误码,0 表示成功(计费依据),非 0 表示失败374 /// 375 public int result { get; set; }376 ///377 /// 错误消息,result 非 0 时的具体错误信息378 /// 379 public string errmsg { get; set; }380 ///381 /// 手机号码382 /// 383 public string mobile { get; set; }384 ///385 /// 国家码386 /// 387 public string nationcode { get; set; }388 ///389 /// 本次发送标识 id,标识一次短信下发记录390 /// 391 public string sid { get; set; }392 ///393 /// 短信计费的条数394 /// 395 public int fee { get; set; }396 ///397 /// ToString()398 /// 399 ///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;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 else422 {423 return String.Format(424 "SmsMultiSenderResult\nresult {0}\nerrmsg {1}\next {2}\n",425 result, errmsg, ext);426 }427 }428 }429 #endregion430 431 #region 公共类432 /// 433 /// 公共类434 /// 435 class SmsSenderUtil436 {437 ///438 /// 国家码439 /// 440 public static string nationCode = "86";441 ///442 /// 随机数生成器443 /// 444 private Random random = new Random();445 446 #region GetPostHttpConn447 ///448 /// GetPostHttpConn449 /// 450 /// 451 ///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 #endregion460 461 #region 生成随机数462 /// 463 /// 生成随机数464 /// 465 ///466 public long GetRandom()467 {468 return random.Next(999999) % 900000 + 100000;469 }470 #endregion471 472 #region 获取请求发起时间473 /// 474 /// 获取请求发起时间,475 /// unix 时间戳(单位:秒),如果和系统时间相差超过 10 分钟则会返回失败476 /// 477 ///478 public long GetCurTime()479 {480 Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;481 return unixTimestamp;482 }483 #endregion484 485 #region 字符串转SHA256486 /// 487 /// 字符串转SHA256488 /// 489 /// 490 ///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 /// 499 /// 将二进制的数值转换为 16 进制字符串,如 "abc" => "616263"500 /// 501 /// 502 ///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 #endregion516 517 #region 将单发回包解析成结果对象518 /// 519 /// 将单发回包解析成结果对象520 /// 521 /// 522 ///523 public SmsSingleSenderResult ResponseStrToSingleSenderResult(string str)524 {525 SmsSingleSenderResult result = JsonConvert.DeserializeObject (str);526 return result;527 }528 #endregion529 530 #region 将群发回包解析成结果对象531 /// 532 /// 将群发回包解析成结果对象533 /// 534 /// 535 ///536 public SmsMultiSenderResult ResponseStrToMultiSenderResult(string str)537 {538 SmsMultiSenderResult result = JsonConvert.DeserializeObject (str);539 return result;540 }541 #endregion542 543 #region List 转JArray544 /// 545 /// List 547 /// 548 ///转JArray546 /// 549 public JArray SmsParamsToJSONArray(List templParams)550 {551 JArray smsParams = new JArray();552 foreach (string templParamsElement in templParams)553 {554 smsParams.Add(templParamsElement);555 }556 return smsParams;557 }558 #endregion559 560 #region PhoneNumbersToJSONArray561 /// 562 /// PhoneNumbersToJSONArray563 /// 564 /// 565 /// 566 ///567 public JArray PhoneNumbersToJSONArray(string nationCode, List phoneNumbers)568 {569 JArray tel = new JArray();570 int i = 0;571 do572 {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 #endregion581 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 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 phoneNumbers = new List ();601 phoneNumbers.Add(phoneNumber);602 return CalculateSigForTempl(appkey, random, curTime, phoneNumbers);603 }604 605 public string CalculateSig(string appkey, long random, long curTime, List 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 #endregion617 }618 #endregion619 }
demo下载路径为:
Redis下载地址:
下载msi格式的安装文件。
1.运行安装程序,单击next按钮。
2.勾选接受许可协议中的条款,单击next按钮。
3.选择安装目录,勾选添加到环境变量,单击next按钮。
4.端口号以及防火墙添加例外,单击next按钮。
5.是否设置最大内存限制,默认不勾选,单击next按钮。
6.开始安装,单击Insatll按钮。
7.等待安装,耗时不超过一分钟。
8.安装完成,单击Finsh按钮。
9.安装目录文件如下所示。
10.可以从服务中查看到redis服务已经正常运行。
一、软件安装
Redis下载地址:
因为官方并不支持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上说将在下一篇博文()中向大家解释为什么他选择6379作为默认端口号。而现在这篇博文出炉,在解释了Redis的LRU机制之后,如期向大家解释了采用6379作为默认端口的原因。6379在是手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字。
二、基本用法
redis是以kev-value形式进行数据存储的,value有字符串、哈希表、列表、集合、有序集合等。
一些命令的使用,可以参考学习。
配置文件的使用,redis.windows-service.conf(以windows服务运行时修改),
1.密码修改 # requirepass foobared //去掉注释#,将foobared替换为你自己的密码 2.文件命名修改 dbfilename dump.rdb // xxxx.rdb
三、C#使用Redis
1)使用到的第三方dll:
2)搜集到的RedisHelper方法,增加了批量操作
1 ///2 /// Redis操作 3 /// 4 public class RedisHelper 5 { 6 ///7 /// 连接redis库的Number 8 /// 9 private int DbNum { set; get; } 10 private readonly ConnectionMultiplexer _conn; 11 ///12 /// 自定义键前缀 13 /// 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 ///39 /// 保存单个key value 40 /// 41 /// Redis Key 42 /// 保存的值 43 /// 过期时间 44 ///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 /// 52 /// 保存多个key value 53 /// 54 /// 键值对 55 ///56 public bool StringSet(List > keyValues) 57 { 58 List > newkeyValues = 59 keyValues.Select(p => new KeyValuePair (AddSysCustomKey(p.Key), p.Value)).ToList(); 60 return Do(db => db.StringSet(newkeyValues.ToArray())); 61 } 62 63 /// 64 /// 保存一个对象 65 /// 66 ///67 /// 68 /// 69 /// 70 /// 71 public bool StringSet (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 /// 79 /// 获取单个key的值 80 /// 81 /// Redis Key 82 ///83 public byte[] StringGet(string key) 84 { 85 key = AddSysCustomKey(key); 86 return Do(db => db.StringGet(key)); 87 } 88 89 /// 90 /// 获取多个Key 91 /// 92 /// Redis Key集合 93 ///94 public RedisValue[] StringGet(List listKey) 95 { 96 List newKeys = listKey.Select(AddSysCustomKey).ToList(); 97 return Do(db => db.StringGet(ConvertRedisKeys(newKeys))); 98 } 99 100 /// 101 /// 获取一个key的对象 102 /// 103 ///104 /// 105 /// 106 public T StringGet (string key) 107 { 108 key = AddSysCustomKey(key); 109 return Do(db => ConvertObj (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 /// 131 /// 为数字增长val 132 /// 133 /// 134 /// 可以为负 135 ///增长后的值 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 ///143 /// 为数字减少val 144 /// 145 /// 146 /// 可以为负 147 ///减少后的值 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 ///159 /// 保存单个key value 160 /// 161 /// Redis Key 162 /// 保存的值 163 /// 过期时间 164 ///165 public async Task 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 /// 172 /// 保存多个key value 173 /// 174 /// 键值对 175 ///176 public async Task StringSetAsync(List > keyValues) 177 { 178 List > newkeyValues = 179 keyValues.Select(p => new KeyValuePair (AddSysCustomKey(p.Key), p.Value)).ToList(); 180 return await Do(db => db.StringSetAsync(newkeyValues.ToArray())); 181 } 182 183 /// 184 /// 保存一个对象 185 /// 186 ///187 /// 188 /// 189 /// 190 /// 191 public async Task StringSetAsync (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 /// 199 /// 获取单个key的值 200 /// 201 /// Redis Key 202 ///203 public async Task StringGetAsync(string key) 204 { 205 key = AddSysCustomKey(key); 206 return await Do(db => db.StringGetAsync(key)); 207 } 208 209 /// 210 /// 获取多个Key 211 /// 212 /// Redis Key集合 213 ///214 public async Task StringGetAsync(List listKey) 215 { 216 List newKeys = listKey.Select(AddSysCustomKey).ToList(); 217 return await Do(db => db.StringGetAsync(ConvertRedisKeys(newKeys))); 218 } 219 220 /// 221 /// 获取一个key的对象 222 /// 223 ///224 /// 225 /// 226 public async Task StringGetAsync (string key) 227 { 228 key = AddSysCustomKey(key); 229 string result = await Do(db => db.StringGetAsync(key)); 230 return ConvertObj (result); 231 } 232 233 /// 234 /// 为数字增长val 235 /// 236 /// 237 /// 可以为负 238 ///增长后的值 239 public async TaskStringIncrementAsync(string key, double val = 1) 240 { 241 key = AddSysCustomKey(key); 242 return await Do(db => db.StringIncrementAsync(key, val)); 243 } 244 245 /// 246 /// 为数字减少val 247 /// 248 /// 249 /// 可以为负 250 ///减少后的值 251 public async TaskStringDecrementAsync(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 /// 266 /// 判断某个数据是否已经被缓存 267 /// 268 /// 269 /// 270 ///271 public bool HashExists(string key, string dataKey) 272 { 273 key = AddSysCustomKey(key); 274 return Do(db => db.HashExists(key, dataKey)); 275 } 276 277 /// 278 /// 存储数据到hash表 279 /// 280 ///281 /// 282 /// 283 /// 284 /// 285 public bool HashSet (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 /// 296 /// 移除hash中的某值 297 /// 298 /// 299 /// 300 ///301 public bool HashDelete(string key, string dataKey) 302 { 303 key = AddSysCustomKey(key); 304 return Do(db => db.HashDelete(key, dataKey)); 305 } 306 307 /// 308 /// 移除hash中的多个值 309 /// 310 /// 311 /// 312 ///313 public long HashDelete(string key, List dataKeys) 314 { 315 key = AddSysCustomKey(key); 316 //List dataKeys1 = new List () {"1","2"}; 317 return Do(db => db.HashDelete(key, dataKeys.ToArray())); 318 } 319 320 /// 321 /// 从hash表获取数据 322 /// 323 ///324 /// 325 /// 326 /// 327 public T HashGet (string key, string dataKey) 328 { 329 key = AddSysCustomKey(key); 330 return Do(db => 331 { 332 string value = db.HashGet(key, dataKey); 333 return ConvertObj (value); 334 }); 335 } 336 337 /// 338 /// 为数字增长val 339 /// 340 /// 341 /// 342 /// 可以为负 343 ///增长后的值 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 ///351 /// 为数字减少val 352 /// 353 /// 354 /// 355 /// 可以为负 356 ///减少后的值 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 ///364 /// 获取hashkey所有Redis key 365 /// 366 ///367 /// 368 /// 369 public List HashKeys (string key) 370 { 371 key = AddSysCustomKey(key); 372 return Do(db => 373 { 374 RedisValue[] values = db.HashKeys(key); 375 return ConvetList (values); 376 }); 377 } 378 379 #endregion 同步方法 380 381 #region 异步方法 382 383 /// 384 /// 判断某个数据是否已经被缓存 385 /// 386 /// 387 /// 388 ///389 public async Task HashExistsAsync(string key, string dataKey) 390 { 391 key = AddSysCustomKey(key); 392 return await Do(db => db.HashExistsAsync(key, dataKey)); 393 } 394 395 /// 396 /// 存储数据到hash表 397 /// 398 ///399 /// 400 /// 401 /// 402 /// 403 public async Task HashSetAsync (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 /// 414 /// 移除hash中的某值 415 /// 416 /// 417 /// 418 ///419 public async Task HashDeleteAsync(string key, string dataKey) 420 { 421 key = AddSysCustomKey(key); 422 return await Do(db => db.HashDeleteAsync(key, dataKey)); 423 } 424 425 /// 426 /// 移除hash中的多个值 427 /// 428 /// 429 /// 430 ///431 public async Task HashDeleteAsync(string key, List dataKeys) 432 { 433 key = AddSysCustomKey(key); 434 //List dataKeys1 = new List () {"1","2"}; 435 return await Do(db => db.HashDeleteAsync(key, dataKeys.ToArray())); 436 } 437 438 /// 439 /// 从hash表获取数据 440 /// 441 ///442 /// 443 /// 444 /// 445 public async Task HashGeAsync (string key, string dataKey) 446 { 447 key = AddSysCustomKey(key); 448 string value = await Do(db => db.HashGetAsync(key, dataKey)); 449 return ConvertObj (value); 450 } 451 452 /// 453 /// 为数字增长val 454 /// 455 /// 456 /// 457 /// 可以为负 458 ///增长后的值 459 public async TaskHashIncrementAsync(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 /// 466 /// 为数字减少val 467 /// 468 /// 469 /// 470 /// 可以为负 471 ///减少后的值 472 public async TaskHashDecrementAsync(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 /// 479 /// 获取hashkey所有Redis key 480 /// 481 ///482 /// 483 /// 484 public async Task
> HashKeysAsync (string key) 485 { 486 key = AddSysCustomKey(key); 487 RedisValue[] values = await Do(db => db.HashKeysAsync(key)); 488 return ConvetList (values); 489 } 490 491 #endregion 异步方法 492 493 #endregion Hash 494 495 #region List 496 497 #region 同步方法 498 499 /// 500 /// 移除指定ListId的内部List的值 501 /// 502 /// 503 /// 504 public void ListRemove(string key, T value) 505 { 506 key = AddSysCustomKey(key); 507 Do(db => db.ListRemove(key, ConvertJson(value))); 508 } 509 510 /// 511 /// 获取指定key的List 512 /// 513 /// 514 ///515 public List ListRange (string key) 516 { 517 key = AddSysCustomKey(key); 518 return Do(redis => 519 { 520 var values = redis.ListRange(key); 521 return ConvetList (values); 522 }); 523 } 524 525 /// 526 /// 入队 527 /// 528 /// 529 /// 530 public void ListRightPush(string key, T value) 531 { 532 key = AddSysCustomKey(key); 533 Do(db => db.ListRightPush(key, ConvertJson(value))); 534 } 535 536 /// 537 /// 出队 538 /// 539 ///540 /// 541 /// 542 public T ListRightPop (string key) 543 { 544 key = AddSysCustomKey(key); 545 return Do(db => 546 { 547 var value = db.ListRightPop(key); 548 return ConvertObj (value); 549 }); 550 } 551 552 /// 553 /// 入栈 554 /// 555 ///556 /// 557 /// 558 public void ListLeftPush (string key, T value) 559 { 560 key = AddSysCustomKey(key); 561 Do(db => db.ListLeftPush(key, ConvertJson(value))); 562 } 563 564 /// 565 /// 出栈 566 /// 567 ///568 /// 569 /// 570 public T ListLeftPop (string key) 571 { 572 key = AddSysCustomKey(key); 573 return Do(db => 574 { 575 var value = db.ListLeftPop(key); 576 return ConvertObj (value); 577 }); 578 } 579 580 /// 581 /// 获取集合中的数量 582 /// 583 /// 584 ///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 /// 596 /// 移除指定ListId的内部List的值 597 /// 598 /// 599 /// 600 public async TaskListRemoveAsync (string key, T value) 601 { 602 key = AddSysCustomKey(key); 603 return await Do(db => db.ListRemoveAsync(key, ConvertJson(value))); 604 } 605 606 /// 607 /// 获取指定key的List 608 /// 609 /// 610 ///611 public async Task
> ListRangeAsync (string key) 612 { 613 key = AddSysCustomKey(key); 614 var values = await Do(redis => redis.ListRangeAsync(key)); 615 return ConvetList (values); 616 } 617 618 /// 619 /// 入队 620 /// 621 /// 622 /// 623 public async TaskListRightPushAsync (string key, T value) 624 { 625 key = AddSysCustomKey(key); 626 return await Do(db => db.ListRightPushAsync(key, ConvertJson(value))); 627 } 628 629 /// 630 /// 出队 631 /// 632 ///633 /// 634 /// 635 public async Task ListRightPopAsync (string key) 636 { 637 key = AddSysCustomKey(key); 638 var value = await Do(db => db.ListRightPopAsync(key)); 639 return ConvertObj (value); 640 } 641 642 /// 643 /// 入栈 644 /// 645 ///646 /// 647 /// 648 public async Task ListLeftPushAsync (string key, T value) 649 { 650 key = AddSysCustomKey(key); 651 return await Do(db => db.ListLeftPushAsync(key, ConvertJson(value))); 652 } 653 654 /// 655 /// 出栈 656 /// 657 ///658 /// 659 /// 660 public async Task ListLeftPopAsync (string key) 661 { 662 key = AddSysCustomKey(key); 663 var value = await Do(db => db.ListLeftPopAsync(key)); 664 return ConvertObj (value); 665 } 666 667 /// 668 /// 获取集合中的数量 669 /// 670 /// 671 ///672 public async Task 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 /// 687 /// 添加 688 /// 689 /// 690 /// 691 /// 692 public bool SortedSetAdd(string key, T value, double score) 693 { 694 key = AddSysCustomKey(key); 695 return Do(redis => redis.SortedSetAdd(key, ConvertJson (value), score)); 696 } 697 698 /// 699 /// 删除 700 /// 701 /// 702 /// 703 public bool SortedSetRemove(string key, T value) 704 { 705 key = AddSysCustomKey(key); 706 return Do(redis => redis.SortedSetRemove(key, ConvertJson(value))); 707 } 708 709 /// 710 /// 获取全部 711 /// 712 /// 713 ///714 public List SortedSetRangeByRank (string key) 715 { 716 key = AddSysCustomKey(key); 717 return Do(redis => 718 { 719 var values = redis.SortedSetRangeByRank(key); 720 return ConvetList (values); 721 }); 722 } 723 724 /// 725 /// 获取集合中的数量 726 /// 727 /// 728 ///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 /// 740 /// 添加 741 /// 742 /// 743 /// 744 /// 745 public async TaskSortedSetAddAsync (string key, T value, double score) 746 { 747 key = AddSysCustomKey(key); 748 return await Do(redis => redis.SortedSetAddAsync(key, ConvertJson (value), score)); 749 } 750 751 /// 752 /// 删除 753 /// 754 /// 755 /// 756 public async TaskSortedSetRemoveAsync (string key, T value) 757 { 758 key = AddSysCustomKey(key); 759 return await Do(redis => redis.SortedSetRemoveAsync(key, ConvertJson(value))); 760 } 761 762 /// 763 /// 获取全部 764 /// 765 /// 766 ///767 public async Task
> SortedSetRangeByRankAsync (string key) 768 { 769 key = AddSysCustomKey(key); 770 var values = await Do(redis => redis.SortedSetRangeByRankAsync(key)); 771 return ConvetList (values); 772 } 773 774 /// 775 /// 获取集合中的数量 776 /// 777 /// 778 ///779 public async Task 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 /// 792 /// 删除单个key 793 /// 794 /// redis key 795 ///是否删除成功 796 public bool KeyDelete(string key) 797 { 798 key = AddSysCustomKey(key); 799 return Do(db => db.KeyDelete(key)); 800 } 801 802 ///803 /// 删除多个key 804 /// 805 /// rediskey 806 ///成功删除的个数 807 public long KeyDelete(Listkeys) 808 { 809 List newKeys = keys.Select(AddSysCustomKey).ToList(); 810 return Do(db => db.KeyDelete(ConvertRedisKeys(newKeys))); 811 } 812 813 /// 814 /// 判断key是否存储 815 /// 816 /// redis key 817 ///818 public bool KeyExists(string key) 819 { 820 key = AddSysCustomKey(key); 821 return Do(db => db.KeyExists(key)); 822 } 823 824 /// 825 /// 重新命名key 826 /// 827 /// 就的redis key 828 /// 新的redis key 829 ///830 public bool KeyRename(string key, string newKey) 831 { 832 key = AddSysCustomKey(key); 833 return Do(db => db.KeyRename(key, newKey)); 834 } 835 836 /// 837 /// 设置Key的时间 838 /// 839 /// redis key 840 /// 841 ///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 /// 853 /// Redis发布订阅 订阅 854 /// 855 /// 856 /// 857 public void Subscribe(string subChannel, Actionhandler = 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 /// 874 /// Redis发布订阅 发布 875 /// 876 ///877 /// 878 /// 879 /// 880 public long Publish (string channel, T msg) 881 { 882 ISubscriber sub = _conn.GetSubscriber(); 883 return sub.Publish(channel, ConvertJson(msg)); 884 } 885 886 /// 887 /// Redis发布订阅 取消订阅 888 /// 889 /// 890 public void Unsubscribe(string channel) 891 { 892 ISubscriber sub = _conn.GetSubscriber(); 893 sub.Unsubscribe(channel); 894 } 895 896 ///897 /// Redis发布订阅 取消全部订阅 898 /// 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 ///925 /// 设置前缀 926 /// 927 /// 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(Func func) 944 { 945 var database = _conn.GetDatabase(DbNum); 946 return func(database); 947 } 948 949 public string ConvertJson (T value) 950 { 951 string result = value is string ? value.ToString() : JsonConvert.SerializeObject(value); 952 return result; 953 } 954 955 public T ConvertObj (RedisValue value) 956 { 957 return JsonConvert.DeserializeObject (value); 958 } 959 960 private List ConvetList (RedisValue[] values) 961 { 962 List result = new List (); 963 foreach (var item in values) 964 { 965 var model = ConvertObj (item); 966 result.Add(model); 967 } 968 return result; 969 } 970 971 private RedisKey[] ConvertRedisKeys(List redisKeys) 972 { 973 return redisKeys.Select(redisKey => (RedisKey)redisKey).ToArray(); 974 } 975 976 #endregion 辅助方法 977 978 #region 批量操作 979 980 #region 批量写Key-Value 981 /// 982 /// 批量写Key-Value 983 /// 984 /// 985 ///986 public bool StringWriteBatch(List > 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 catch1001 {1002 }1003 return result;1004 }1005 #endregion1006 1007 #region 批量读Key-Value1008 /// 1009 /// 批量读Key-Value1010 /// 1011 ///1012 /// 1013 /// 1014 public List StringReadBatch (List lstKey)1015 {1016 List > valueList = new List >();1017 List lstResult = new List ();1018 try1019 {1020 var db = _conn.GetDatabase();1021 var batch = db.CreateBatch();1022 foreach (var item in lstKey)1023 {1024 Task value = batch.StringGetAsync(item);1025 valueList.Add(value);1026 }1027 batch.Execute();1028 1029 foreach (var item in valueList)1030 {1031 T t = ConvertObj (item.Result);1032 lstResult.Add(t);1033 }1034 }1035 catch1036 {1037 }1038 return lstResult;1039 }1040 1041 /// 1042 /// 批量读操作,返回DataSe集合1043 /// 1044 /// 1045 ///1046 public DataSet StringReadBatch(List lstKey)1047 {1048 if (lstKey == null || lstKey.Count < 1) return null;1049 List > valueList = new List >();1050 DataSet ds = new DataSet();1051 try1052 {1053 var db = _conn.GetDatabase();1054 var batch = db.CreateBatch();1055 foreach (var item in lstKey)1056 {1057 Task value = batch.StringGetAsync(item);1058 valueList.Add(value);1059 }1060 batch.Execute();1061 1062 foreach (var item in valueList)1063 {1064 DataTable t = ConvertObj (item.Result);1065 ds.Tables.Add(t);1066 }1067 }1068 catch1069 {1070 }1071 return ds;1072 }1073 #endregion1074 1075 #region 批量写Hash1076 /// 1077 /// 批量写Hash1078 /// 1079 /// 1080 ///1081 public bool HashWriteBatch(List > keyValues)1082 {1083 bool result = false;1084 try1085 {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 catch1096 {1097 }1098 return result;1099 }1100 #endregion1101 1102 #region 批量读Hash1103 /// 1104 /// 批量读Hash1105 /// 1106 /// hash键和field1107 ///1108 public List HashReadBatch (List > keyFields)1109 {1110 List > valueList = new List >();1111 List lstResult = new List ();1112 try1113 {1114 var db = _conn.GetDatabase();1115 var batch = db.CreateBatch();1116 foreach (var item in keyFields)1117 {1118 Task 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 (redisValue);1129 lstResult.Add(t);1130 }1131 }1132 }1133 catch1134 {1135 }1136 return lstResult;1137 }1138 #endregion1139 1140 #endregion
3)单例模式
1 ///2 /// ConnectionMultiplexer对象管理帮助类 3 /// 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 ConcurrentDictionaryConnectionCache = new ConcurrentDictionary (); 15 16 /// 17 /// 单例获取 18 /// 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 ///38 /// 缓存获取 39 /// 40 /// 41 ///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 /// 70 /// 配置更改时 71 /// 72 /// 73 /// 74 private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e) 75 { 76 Console.WriteLine("Configuration changed: " + e.EndPoint); 77 } 78 79 ///80 /// 发生错误时 81 /// 82 /// 83 /// 84 private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e) 85 { 86 Console.WriteLine("ErrorMessage: " + e.Message); 87 } 88 89 ///90 /// 重新建立连接之前的错误 91 /// 92 /// 93 /// 94 private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e) 95 { 96 Console.WriteLine("ConnectionRestored: " + e.EndPoint); 97 } 98 99 ///100 /// 连接失败 , 如果重新连接成功你将不会收到这个通知101 /// 102 /// 103 /// 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 ///110 /// 更改集群111 /// 112 /// 113 /// 114 private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)115 {116 Console.WriteLine("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint);117 }118 119 ///120 /// redis类库错误121 /// 122 /// 123 /// 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连接字符串