反射实现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>

反射实现Model修改前后的内容对比 【API调用】腾讯云短信 Windows操作系统下Redis服务安装图文详解 Redis入门学习的更多相关文章

  1. 反射实现Model修改前后的内容对比

    在开发过程中,我们会遇到这样一个问题,编辑了一个对象之后,我们想要把这个对象修改了哪些内容保存下来,以便将来查看和追责. 首先我们要创建一个User类 public class User { priv ...

  2. 腾讯云短信 nodejs 接入, 通过验证码修改手机示例

    腾讯云短信 nodejs 接入, 通过验证码修改手机示例 参考:腾讯云短信文档国内短信快速入门qcloudsms Node.js SDK文档中心>短信>错误码 nodejs sdk 使用示 ...

  3. TortoiseGit学习系列之TortoiseGit基本操作修改提交项目(图文详解)

    前面博客 TortoiseGit学习系列之TortoiseGit基本操作克隆项目(图文详解) TortoiseGit基本操作修改提交项目 项目克隆完成后(可以将克隆 clone 理解为 下载,检出 c ...

  4. Android(java)学习笔记254:ContentProvider使用之内容观察者(观察发出去的短信)

    1.新建一个案例如下: 2. 不需要添加权限,同时这里布局文件不做修改,来到MainActivity,如下: package com.itheima.sendsmslistener; import a ...

  5. Android(java)学习笔记198:ContentProvider使用之内容观察者(观察发出去的短信)

    1.新建一个案例如下: 2. 不需要添加权限,同时这里布局文件不做修改,来到MainActivity,如下: package com.itheima.sendsmslistener; import a ...

  6. Java反射详解:入门+使用+原理+应用场景

    反射非常强大和有用,现在市面上绝大部分框架(spring.mybatis.rocketmq等等)中都有反射的影子,反射机制在框架设计中占有举足轻重的作用. 所以,在你Java进阶的道路上,你需要掌握好 ...

  7. 全网最详细的实用的搜索工具Listary和Everything对比的区别【堪称比Everything要好】(图文详解)

    不多说,直接上干货! 引言 无论是工作还是科研,我们都希望工作既快又好,然而大多数时候却迷失在繁杂的重复劳动中,久久无法摆脱繁杂的事情.   你是不是曾有这样一种想法:如果我有哆啦A梦的口袋,只要拿出 ...

  8. ubuntu系统复制到其他地方或克隆后,如何正确修改IP及MAC地址的解决方案(图文详解)

    修改ip地址 永久修改MAC地址 方法一: 1)编辑“/etc/init.d/rc.local”文件(sudo gedit /etc/init.d/rc.local) 2)在此配置文件的最后面加上如( ...

  9. Navicat for Mysql修改MySQL数据库密码,图文详解

    1.创建一个连接 2.打开连接 3.按照图示123依次点击 4.输入新密码 5.查看实现修改密码功能的SQL语句(此步骤非必须) 6.最关键的一步:点击保存 7.出现如下现象,恭喜你,修改密码成功! ...

随机推荐

  1. Python+Selenium 自动化测试获取测试报告内容并发送邮件

    这里封装一个send_mail()方法,用于测试完成后读取测试报告内容,并将测试结果通过邮件发送到接收人 # coding: utf-8 import smtplib from email.mime. ...

  2. C#面试问题及答案

    1.遇到高并发的问题如何解决? 优化SQL语句 多线程 分布式服务器 集群 拆表2.Dictionary和ConurrentDictionary的区别? 后者是线程安全的 前者适用于单线程3.Dict ...

  3. flatpickr插件的使用

    flatpickr功能强大的日期时间选择器插件 日期格式化 <input class=flatpickr data-date-format="d-m-Y"> <i ...

  4. 获取url上的参数

    var aa = '?name=hss&age=13';        function strToObj(str){            if(typeof str === 'undefi ...

  5. HDU1401 Solitaire

    题目描述:8×8的棋盘上有4个棋子,棋子的运动方法如下:1.如果其上/下/左/右一格没有棋子,则可以去;2.如果其上/下/左/右一格有棋子,而且沿原方向再跳一步没有,则可以去. 给出初始结束位置,问8 ...

  6. 19Spring返回通知&异常通知&环绕通知

    在前置通知和后置通知的基础上加上返回通知&异常通知&环绕通知 代码: package com.cn.spring.aop.impl; //加减乘除的接口类 public interfa ...

  7. LINUX:Contos7.0 / 7.2 LAMP+R 下载安装Apache篇

    文章来源:http://www.cnblogs.com/hello-tl/p/7568803.html 更新时间:2017-09-21 15:38 简介 LAMP+R指Linux+Apache+Mys ...

  8. MapReduce架构与执行流程

    一.MapReduce是用于解决什么问题的? 每一种技术的出现都是用来解决实际问题的,否则必将是昙花一现,那么MapReduce是用来解决什么实际的业务呢? 首先来看一下MapReduce官方定义: ...

  9. SQL SERVER占用CPU过高排查和优化

    操作系统是Windows2008R2 ,数据库是SQL2014 64位. 近阶段服务器出现过几次死机,管理员反馈机器内存使用率100%导致机器卡死.于是做了个监测服务器的软件实时记录CPU数据,几日观 ...

  10. 关于c# .net爬虫

    刚开始听到爬虫这两个字眼的时候感觉挺稀奇的,之前并没有接触过爬虫,正好这会手上没事,于是便百度了一下. 1.网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种 ...