本章的内容来源是有朋友咨询怎么做微信公众号信息的收发消息功能,因此本着为社区做贡献的态度申请了个人公众号,然后尝试对接了一下接收公众号内容信息的流程;要说对接其实呢也算不上,因为个人账号只有简单的一些接收,被动回复等功能信息,不能群发和使用客服接口,所以本章主要分享的是怎么接受信息和被动发送回复信息的实例;
这种设置的东西,其实跟着官网设置就行了,不过本人根据官网文档一步一步设置的时候,还是遇到一些问题,因此这里需要记录下注意的关键点;首先我们登陆公众平台 -》开发 -》基本配置 -》点击 "修改配置"-》这个时候会出现以下截图:
填写上面内容的时候需要注意以下几点:
1. 接收的 url 地址必须外网能访问并且在 80 端口上
2. 第一次保存 "服务器配置" 时,必须在接收地址中以 get 方式获取的公众平台通知的 "echostr" 参数,然后返回输出这个 "echostr" 值给平台 (这样你在公众平台保存服务配置的时候才能成功),这个地方官网文字描述不是很突出,不重点看的话很难发现
到此,只要做到上面两点那么您 "服务器配置" 才能保存成功,千万仔细哦;
- 1 /// <summary>
- 2 /// 接收"服务配置"时通知的信息 格式如:signature=08c66dd8b2fd8fe43118965b336d6098642607f3&echostr=6917887702473243501×tamp=1491458849&nonce=1123949701
- 3 /// </summary>
- 4 /// <returns></returns>
- 5[HttpGet] 6 public string Get() 7 {
- 8 9
- var echostr = Request.Query["echostr"];
- 10
- if (string.IsNullOrWhiteSpace(echostr)) {
- return "别瞎搞。";
- }
- 11 12
- var sbLog = new StringBuilder(string.Empty);
- 13 sbLog.Append($ "method:get->echostr:{echostr}->");
- 14
- try 15 {
- 16 sbLog.Append($ "QueryString:{Request.QueryString.Value}->");
- 17
- }
- 18
- catch(Exception ex) 19 {
- 20 sbLog.Append($ "异常信息:{ex.Message}->");
- 21
- }
- 22
- finally 23 {
- 24 PublicTool.WriteLog(sbLog.ToString());
- 25
- }
- 26
- return echostr;
- 27
- }
接收 post 过来的用户发送的内容信息,目前公众平台通知的类型有: text: 文本消息 image:图形消息 voice:语音消息 video:视频消息 shortvideo:小视频消息 location:地理位置 link:链接消息;
- 1 /// <summary>
- 2 /// 接收post过来的用户发送的内容信息
- 3 /// </summary>
- 4 /// <returns></returns>
- 5[HttpPost] 6 public string Post() 7 {
- 8
- var sbLog = new StringBuilder(string.Empty);
- 9
- var now = DateTime.Now;
- 10
- var reStr = string.Empty; //返回信息,1.空表示不需要再通知 2.返回正规文本内容表示回复消息 3.其他信息表示需要再次通知内容
- 11 sbLog.Append($ "method:post->");
- 12
- try 13 {
- 14
- var str = string.Empty;
- 15 using(var stream = Request.Body) 16 {
- 17 using(var reader = new StreamReader(stream)) 18 {
- 19 str = reader.ReadToEnd();
- 20
- }
- 21
- }
- 22 sbLog.Append($ "str:{str}->");
- 23
- if (string.IsNullOrWhiteSpace(str)) {
- return reStr;
- }
- 24 25
- var data = PublicTool._XmlDeserialize(str);
- 26
- if (data == null) {
- return reStr;
- }
- 27 sbLog.Append($ "ToUserName:{data.ToUserName},FromUserName:{data.FromUserName},MsgType:{data.MsgType},CreateTime:{data.CreateTime}->");
- 28 29 //消息类型 对应枚举 MsgTypeEm
- 30
- switch (data.MsgType) 31 {
- 32
- case "text":
- 33 34
- break;
- 35
- case "image":
- 36
- break;
- 37
- case "voice":
- 38
- break;
- 39
- case "video":
- 40
- break;
- 41
- case "shortvideo":
- 42
- break;
- 43 44
- case "location":
- 45
- break;
- 46
- case "link":
- 47
- break;
- 48
- }
- 49 50 //自动回复信息(暂时:只有文字内容)
- 51
- var reHuaYu = string.Empty;
- 52
- if (data.Content.Contains("测试") || data.Content.Contains("ceshi")) 53 {
- 54 reHuaYu = "请尽量发一些有用的信息!";
- 55
- }
- 56
- else if (data.Content.Contains("你好") || data.Content.Contains("您好") || data.Content.Contains("群主") || data.Content.Contains("在么")) 57 {
- 58 reHuaYu = "您好,谢谢您的支持!";
- 59
- }
- 60 61
- if (!string.IsNullOrWhiteSpace(reHuaYu)) 62 {
- 63 reStr = string.Format(@"<xml>
- 64 <ToUserName><![CDATA[{0}]]></ToUserName>
- 65 <FromUserName><![CDATA[{1}]]></FromUserName>
- 66 <CreateTime>{2}</CreateTime>
- 67 <MsgType><![CDATA[{3}]]></MsgType>
- 68 <Content><![CDATA[{4}]]></Content>
- 69 </xml>", 70 data.FromUserName, 71 data.ToUserName, 72 now, 73 "text", 74 reHuaYu);
- 75
- }
- 76
- }
- 77
- catch(Exception ex) 78 {
- 79 sbLog.Append($ "异常信息:{ex.Message}->");
- 80
- }
- 81
- finally 82 {
- 83
- if (!string.IsNullOrEmpty(sbLog.ToString())) 84 {
- 85 PublicTool.WriteLog(sbLog.ToString());
- 86
- }
- 87
- }
- 88
- return reStr;
- 89
- }
本次我使用的是. netcore 的 webapi 来接收通知消息,但是当公众平台有 80 端口限制的时候,顿时我蒙了,因为我服务器 iis 上有一个项目是绑定了 80 端口的,这个时候如果使用 Kestrel 再绑定一个端口那肯定不行的;想到 iis 可以创建虚拟子应用程序 (多个子应用程序对应一个大的网站配置,这样 80 端口就可以共享了),思考着 Kestrel 是不是也可以呢,失望的是查了很多资料都暂时没有涉及到或者是我没有找到这方面的资料,因此只好放弃了;
下面分享下. netcore 中我操作 xml 序列化和反序列方法,首先需要引入 System.Xml.Serialization :
- 1 /// <summary>
- 2 /// xml字符串反序列化
- 3 /// </summary>
- 4 /// <typeparam name="T"></typeparam>
- 5 /// <param name="xml"></param>
- 6 /// <returns></returns>
- 7 public static T _XmlDeserialize(string xml) where T: class,
- new() 8 {
- 9 T t =
- default(T);
- 10
- if (string.IsNullOrEmpty(xml)) return t;
- 11 12 XmlSerializer serializer = new XmlSerializer(typeof(T));
- 13 using(var reader = new StringReader(xml)) 14 {
- 15 t = (T) serializer.Deserialize(reader);
- 16
- }
- 17
- return t;
- 18
- }
- 19 20 /// <summary>
- 21 /// xml序列化
- 22 /// </summary>
- 23 /// <param name="obj"></param>
- 24 /// <returns></returns>
- 25 public static string _XMLSerialize(object obj) 26 {
- 27 XmlSerializer xs = new XmlSerializer(obj.GetType());
- 28 StringBuilder strBuidler = new StringBuilder();
- 29 XmlWriterSettings setting = new XmlWriterSettings();
- 30 setting.OmitXmlDeclaration = true; //去掉xml版本声明
- 31 using(System.Xml.XmlWriter xw = System.Xml.XmlWriter.Create(strBuidler, setting)) 32 {
- 33 XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces();
- 34 xmlns.Add(string.Empty, string.Empty);
- 35 xs.Serialize(xw, obj, xmlns);
- 36
- }
- 37
- return strBuidler.ToString();
- 38
- }
文本日志
- 1 /// <summary>
- 2 /// 文本日志
- 3 /// </summary>
- 4 /// <param name="content"></param>
- 5 /// <param name="basePath"></param>
- 6 public static async void WriteLog(string content, string basePath = null) 7 {
- 8 basePath = basePath ? ?AppContext.BaseDirectory;
- 9
- var now = DateTime.Now;
- 10 11
- var year = now.ToString("yyyy");
- 12
- var month = now.ToString("MM");
- 13
- var date = now.ToString("dd");
- 14 15
- var fileName = $ "{now.ToString("HH ")}.txt";
- 16
- var path = Path.Combine(basePath, year, month, date, fileName);
- 17
- if (!System.IO.File.Exists(path)) 18 {
- 19 20 basePath = Path.Combine(basePath, year);
- 21
- if (!Directory.Exists(basePath)) {
- Directory.CreateDirectory(basePath);
- }
- 22 23 basePath = Path.Combine(basePath, month);
- 24
- if (!Directory.Exists(basePath)) {
- Directory.CreateDirectory(basePath);
- }
- 25 26 basePath = Path.Combine(basePath, date);
- 27
- if (!Directory.Exists(basePath)) {
- Directory.CreateDirectory(basePath);
- }
- 28 29 path = Path.Combine(basePath, fileName);
- 30
- }
- 31 using(FileStream stream = new FileStream(path, FileMode.Append, FileAccess.Write)) 32 {
- 33 using(var writer = new StreamWriter(stream)) 34 {
- 35 await writer.WriteLineAsync($ "{now.ToString("yyyy - MM - dd HH: mm: ss.fff ")}:{content}");
- 36
- }
- 37
- }
- 38
- }
总结一下吧:
有点好奇为什么微信公众平台使用的是 xml 格式数据来交互,不知道是出于什么考虑;从接口对接上来说很简单,就是平长的 get,post 方式来传递数据,需要注意的应该是一些细节上的问题吧;还有待解决 Kestrel 部署 netcore 时是否能创建多个子虚拟目录问题(如果您已经知道了这个答案,请不吝赐教,谢谢);最后发一张测试的公众号二维码,关注后输入:测试 或 您好,群主等信息会有我接口返回的自动回复信息;
来源: http://www.cnblogs.com/wangrudong003/p/6674816.html