知识点
相关文章
更多最近更新
更多微信开发之.Net
2019-03-02 00:57|来源: 网路
撸主是一个新手,最近几天在研究微信服务号交互,上网搜了搜C#的代码,再结合自己的习惯,下面把代码解析一下,其中有些代码非本人原创。
首先,你要有个公众服务号,只有服务号才可以自定义菜单,没有条件的可以申请订阅号,然后再申请测试服务号。
微信调用服务端的接口其实分为2个部分,第一,验证此消息是否是微信发出来的,这通过get参数获取,像这样"?signature=eebf87348f23a73debd0e8a4235bb4e798099365&echostr=5964279561876822008×tamp=1388992504&nonce=1388667053",其中signature是验证签名,我们要做的就是把提交微信网站的token,timestamp和nonce参数通过计算签名与signature参数比对,如果正确则证明这个是微信官方的信息,具体的代码是这样的。
public static bool VerifySignature(string token, string signature, string timeStamp, string nonce) { //基本检查 if (string.IsNullOrEmpty(signature)) { return false; } //签名验证 string[] stringArray = { token, timeStamp, nonce }; //排序 Array.Sort(stringArray); //计算签名 string calculatedSignature = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile( string.Join(string.Empty, stringArray), System.Web.Configuration.FormsAuthPasswordFormat.SHA1.ToString()); return calculatedSignature != null && calculatedSignature.ToLower() == signature; }
如果验证通过的话一定要给微信返回信号,否则微信会认为无响应的。!
/// <summary> /// 告知微信服务器,已通过验证 /// </summary> public static void EchoPass() { //响应微信验证 HttpContext.Current.Response.Write(HttpContext.Current.Request["echostr"]); HttpContext.Current.Response.Flush(); }
其中参数echostr是微信服务器随机生成的,直接返回即可。
响应完成后就需要我们的应用程序来处理信息了,首先必须判断返回来的是哪种信息。
微信的信息种类有: 文本消息:text , 图片消息:image ,事件消息:event , 语音消息:voice ,视频消息: video ,地理位置消息:location ,链接消息:link
消息主体就是第二部分了,内容在Request.InputStream中,需要解析成xml文件,xml格式大概是这样的:
<xml><ToUserName><![CDATA[收件人]]></ToUserName> <FromUserName><![CDATA[发件人]]></FromUserName> <CreateTime>1389084129</CreateTime> <MsgType><![CDATA[event]]></MsgType> <Event><![CDATA[CLICK]]></Event> <EventKey><![CDATA[ceshi1]]></EventKey> </xml>
上面的是一个事件的消息,事件就是点击服务号的自定义菜单。
接下来就是解析xml成具体的实例了,关于消息的处理我是这样解决的(一部分借鉴别人给的代码,再结合自己的习惯):
1.首先是定义个消息类

1 /// <summary> 2 /// 消息的父类 3 /// </summary> 4 public abstract class Message 5 { 6 /// <summary> 7 /// 收信人 8 /// </summary> 9 public string ToUserName { get; set; } 10 /// <summary> 11 /// 发信人 12 /// </summary> 13 public string FromUserName { get; set; } 14 /// <summary> 15 /// 创建时间 16 /// </summary> 17 public long CreateTime { get; set; } 18 /// <summary> 19 /// 消息类型 20 /// </summary> 21 public string MsgType { get; set; } 22 23 /// <summary> 24 /// 消息的类型:Send接收的消息,Reply发送的消息 25 /// </summary> 26 public MessageDirection Direction { get; set; } 27 /// <summary> 28 /// 将xml文档转换为具体的接收实例 29 /// </summary> 30 /// <param name="node"></param> 31 /// <returns></returns> 32 protected abstract Message Parse(XmlNode node); 33 34 public override string ToString() 35 { 36 return string.Empty; 37 } 38 39 /// <summary> 40 /// 得到具体的消息处理实例 41 /// </summary> 42 /// <param name="xmlStream"></param> 43 /// <returns></returns> 44 public static Message GetInstance(Stream xmlStream) 45 { 46 if (xmlStream == null || xmlStream.Length == 0) 47 { 48 return null; 49 } 50 //得到请求的内容 51 byte[] bytes = new byte[xmlStream.Length]; 52 xmlStream.Read(bytes, 0, (int)xmlStream.Length); 53 string xml = Encoding.UTF8.GetString(bytes); 54 return GetInstance(xml); 55 } 56 /// <summary> 57 /// 得到具体的消息处理实例 58 /// </summary> 59 /// <param name="xml"></param> 60 /// <returns></returns> 61 public static Message GetInstance(string xml) 62 { 63 XmlDocument doc = new XmlDocument(); 64 Message message = null; 65 try 66 { 67 doc.LoadXml(xml); 68 XmlNode firstNode = doc.FirstChild; 69 if (firstNode == null) 70 { 71 return null; 72 } 73 //消息类型 74 XmlNode tempNode = firstNode.SelectSingleNode("MsgType"); 75 if (tempNode == null) 76 { 77 return null; 78 } 79 message = GetInstance(tempNode); 80 if (message != null) 81 { 82 return message.Parse(doc.FirstChild); 83 } 84 return message; 85 } 86 catch (Exception ex) 87 { 88 return null; 89 } 90 } 91 92 private static Message GetInstance(XmlNode node) 93 { 94 switch (node.InnerText) 95 { 96 case MessageType.Text: return new TextSendMessage(); 97 case MessageType.Image: return null; 98 case MessageType.Link: return null; 99 case MessageType.Location: return null; 100 case MessageType.Music: return null; 101 case MessageType.Video: return null; 102 case MessageType.Voice: return null; 103 case MessageType.Event: return new EventSendMessage(); 104 default: return null; 105 } 106 } 107 108 }
2.具体的消息类型,我就弄了个文本和事件,首先是文本:
/// <summary> /// 处理消息类 /// </summary> public abstract class TextMessage : Message { public TextMessage() { this.MsgType = MessageType.Text; } public string Content { get; set; } protected override Message Parse(System.Xml.XmlNode node) { return null; } }
消息分为接收的和回复的,先是接收的:

/// <summary> /// 处理消息类 /// </summary> public class TextSendMessage : TextMessage { public TextSendMessage() { this.Direction = MessageDirection.Send; } public string MsgId { get; set; } protected override Message Parse(XmlNode node) { //发送者 XmlNode tempNode = node.SelectSingleNode("FromUserName"); if (tempNode == null) { return null; } this.FromUserName = tempNode.InnerText; //接收者 tempNode = node.SelectSingleNode("ToUserName"); if (tempNode == null) { return null; } this.ToUserName = tempNode.InnerText; //创建时间 tempNode = node.SelectSingleNode("CreateTime"); if (tempNode == null) { return null; } this.CreateTime = Convert.ToInt64(tempNode.InnerText); //消息内容 tempNode = node.SelectSingleNode("Content"); if (tempNode == null) { return null; } this.Content = tempNode.InnerText; //消息ID tempNode = node.SelectSingleNode("MsgId"); if (tempNode == null) { return null; } this.MsgId = tempNode.InnerText; return this; } public override string ToString() { return string.Format("<xml>" + Environment.NewLine + "<ToUserName><![CDATA[{0}]]></ToUserName>" + Environment.NewLine + "<FromUserName><![CDATA[{1}]]></FromUserName>" + Environment.NewLine + "<CreateTime>{2}</CreateTime>" + Environment.NewLine + "<MsgType><![CDATA[{3}]]></MsgType>" + Environment.NewLine + "<Content><![CDATA[{4}]]></Content>" + Environment.NewLine + "<MsgId>{5}</MsgId>" + Environment.NewLine + "</xml>", ToUserName, FromUserName, CreateTime, MsgType, Content, MsgId); } }
然后是回复的:
public class TextReplyMessage:TextMessage { public TextReplyMessage() { this.Direction = MessageDirection.Reply; } public string FuncFlag { get; set; } public override string ToString() { return string.Format("<xml>" + Environment.NewLine + "<ToUserName><![CDATA[{0}]]></ToUserName>" + Environment.NewLine + "<FromUserName><![CDATA[{1}]]></FromUserName>" + Environment.NewLine + "<CreateTime>{2}</CreateTime>" + Environment.NewLine + "<MsgType><![CDATA[{3}]]></MsgType>" + Environment.NewLine + "<Content><![CDATA[{4}]]></Content>" + Environment.NewLine + "<FuncFlag>{5}</FuncFlag>" + Environment.NewLine + "</xml>", ToUserName, FromUserName, CreateTime, MsgType, Content, FuncFlag); } }
接下来是事件处理:

/// <summary> /// 事件的处理 /// </summary> public abstract class EventMessage : Message { public EventMessage() { this.MsgType = MessageType.Event; } public string Event { get; set; } public string EventKey { get; set; } protected override Message Parse(XmlNode node) { //发送者 XmlNode tempNode = node.SelectSingleNode("FromUserName"); if (tempNode == null) { return null; } FromUserName = tempNode.InnerText; //接收者 tempNode = node.SelectSingleNode("ToUserName"); if (tempNode == null) { return null; } ToUserName = tempNode.InnerText; //创建时间 tempNode = node.SelectSingleNode("CreateTime"); if (tempNode == null) { return null; } CreateTime = Convert.ToInt64(tempNode.InnerText); //事件(subscribe/unsubscribe/CLICK) tempNode = node.SelectSingleNode("Event"); if (tempNode == null) { return null; } Event = tempNode.InnerText; //事件Key(当Event=CLICK时,使用Key定位具体单击的是哪个菜单项) tempNode = node.SelectSingleNode("EventKey"); if (tempNode == null) { return null; } EventKey = tempNode.InnerText; return this; } public override string ToString() { return string.Format("<xml>" + Environment.NewLine + "<ToUserName><![CDATA[{0}]]></ToUserName>" + Environment.NewLine + "<FromUserName><![CDATA[{1}]]></FromUserName>" + Environment.NewLine + "<CreateTime>{2}</CreateTime>" + Environment.NewLine + "<MsgType><![CDATA[{3}]]></MsgType>" + Environment.NewLine + "<Event><![CDATA[{4}]]></Event>" + Environment.NewLine + "<EventKey>{5}</EventKey>" + Environment.NewLine + "</xml>", ToUserName, FromUserName, CreateTime, MsgType, Event, EventKey); } }
接收的事件信息
public class EventSendMessage:EventMessage { public EventSendMessage() { this.Direction = MessageDirection.Send; } }
现在就弄了这些,上面的只是接收微信的信息,有接收就得有处理回发数据。
定义一个消息处理中心(这个是网上的代码。。。)

/// <summary> /// 指令处理中心 /// </summary> public class InstructionHandlingCenter { public List<Instruction> InstructionList { get; private set; } public InstructionHandlingCenter() { this.InstructionList = new List<Instruction>(); } /// <summary> /// 指令注册 /// </summary> /// <param name="instruction"></param> public void RegisterInstruction(Instruction instruction) { if (!this.InstructionList.Contains(instruction)) { this.InstructionList.Add(instruction); } } /// <summary> /// 根据请求获取返回消息 /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> public Message GetReplyMessage(Message requestMessage) { foreach (var instruction in InstructionList) { if (instruction.MatchWith(requestMessage)) { return instruction.GetReplyInstance(requestMessage); } } return new TextReplyMessage { FromUserName = requestMessage.ToUserName, ToUserName = requestMessage.FromUserName, CreateTime = Convert.ToInt64(DateTime.Now.Ticks.ToString(System.Globalization.CultureInfo.InvariantCulture)), Content = "无效的指令请求!" }; } }
然后是处理回发数据的父类

/// <summary> /// 处理回发数据 /// </summary> public abstract class Instruction { public abstract string HelpMessage { get; } /// <summary> /// 检查指令是否与消息相匹配 /// </summary> /// <param name="message"></param> /// <returns></returns> public abstract bool MatchWith(Message message); /// <summary> /// 分析消息内容并返回对应响应值 /// </summary> /// <param name="message"></param> /// <returns></returns> public abstract Message GetReplyInstance(Message message); }
我只弄了2个,一个文本,一个事件
文本:

public class TextInstruction : Instruction { public override string HelpMessage { get { return "欢迎关注.........."; } } public override bool MatchWith(Message message) { return message is TextSendMessage; } public override Message GetReplyInstance(Message message) { return new TextReplyMessage() { FromUserName = message.ToUserName, ToUserName = message.FromUserName, CreateTime = Convert.ToInt64(DateTime.Now.Ticks.ToString(System.Globalization.CultureInfo.InvariantCulture)), Content = HelpMessage, FuncFlag = "1" }; } }
事件:

/// <summary> /// 事件处理 /// </summary> public class EventInstruction : Instruction { private string _helMessage = "事件触发"; public override string HelpMessage { get { return this._helMessage; } } public override bool MatchWith(Message message) { return message is EventSendMessage; } public override Message GetReplyInstance(Message message) { EventSendMessage esm = message as EventSendMessage; this._helMessage = esm.EventKey; return new TextReplyMessage() { FromUserName = message.ToUserName, ToUserName = message.FromUserName, CreateTime = Convert.ToInt64(DateTime.Now.Ticks.ToString(System.Globalization.CultureInfo.InvariantCulture)), Content = HelpMessage, FuncFlag = "1" }; } }
具体的逻辑自己控制。
这样,整体就基本完成了。
下面是调用:

/// <summary> /// WeiXinApi 的摘要说明 /// </summary> public class WeiXinApi : IHttpHandler { //微信服务号 protected readonly string WeiXinServerNo = "???"; //注册时指定的Token protected readonly string Token = "???"; //指令处理中心 private readonly InstructionHandlingCenter _instructionHandler = new InstructionHandlingCenter(); public void ProcessRequest(HttpContext context) { Save("ok", "test.txt"); Uri uri = context.Request.Url; if (uri != null) { Save(uri.PathAndQuery + "\r\n", "uri.txt"); } var stream = context.Request.InputStream; string result = null; if (stream != null && stream.Length > 0) { var bytes = new byte[stream.Length]; stream.Read(bytes, 0, (int)stream.Length); result = Encoding.UTF8.GetString(bytes); Save(result, "xml.txt"); } //初始化变量 InitializeVariables(); //验证签名 if (!WeiXinCommon.VerifySignature(Token)) { context.Response.Write("验证签名错误"); Save("验证签名错误", "result.txt"); return; } //响应微信验证 WeiXinCommon.EchoPass(); if (context.Request.InputStream == null || context.Request.InputStream.Length == 0) { Save("InputStream没有", "result.txt"); return; } //获取指令请求 Message requestMessage = Message.GetInstance(result); if (requestMessage == null) { context.Response.Write("获取指令请求为null(requestMessage)"); Save("获取指令请求为null(requestMessage)", "result.txt"); return; } var replyMessage = _instructionHandler.GetReplyMessage(requestMessage); if (replyMessage == null) { context.Response.Write("获取指令请求为null(replyMessage)"); Save("获取指令请求为null(replyMessage)", "result.txt"); return; } WeiXinCommon.SendReplyMessage(replyMessage); Save(replyMessage.ToString(), "result.txt"); } public bool IsReusable { get { return false; } } //初始化变量 private void InitializeVariables() { //初始化可处理的指令列表 if (_instructionHandler.InstructionList.Count == 0) { _instructionHandler.RegisterInstruction(new TextInstruction()); _instructionHandler.RegisterInstruction(new EventInstruction()); } } private void Save(string value, string fileName) { using (Stream stream = File.Open(HttpContext.Current.Server.MapPath(fileName), FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write)) { using (StreamWriter writer = new StreamWriter(stream, System.Text.Encoding.UTF8)) { writer.WriteLine(value); } } } }
大概就这样了,其实处理流程很简单,就是 验证-->通过的话告诉微信--> 接收消息,判断是什么类型的数据-->发给微信-->微信会根据ToUserName推送给指定的用户。
下面是代码附件:
http://files.cnblogs.com/pokemon/WeiXinDemo.rar
小弟只是一个新手,大家多交流才能进步!
转自:http://www.cnblogs.com/pokemon/p/3510286
相关问答
更多-
微信企业号是如何开发的?哪个微信第三方平台做得还不错?[2022-06-26]
微信企业号虽然功能很强大,但里面只有一些简单的应用,企业号提供接口,需要第三方公司来开发各种功能,我知道的有企微、动酷,做的还不错。 -
关于微信小程序开发的文档,在哪里可以下载[2022-03-23]
直接在百度输即速应用进入网站,下即速插件开发文档。 -
微信小程序开发需要注意哪些事项?[2022-11-04]
主要是在交货前充分做好程序测试,是否能满足你的需求。 另外,售后服务一定要有保证,如果有更新协议的话最好确定更新时间和周期; 基本上就这样,最好选择一些信誉比较好的公司吧。企业开发微信小程序要明确自己的需求。 把需求提交给产品进行设计。 设计和开发做好小程序后提交审核最终上线。 -
微信小程序开发教程[2022-04-11]
1. 微信小程序教程主要是前端技术。 2. 在学习下小程序的文档即可。 -
开发微信小程序多少钱[2022-04-03]
开发微信小程序,价格一般都是按照需求来决定的 当然市面上有很多免费建小程序的一些平台,但是本人是不建议去那些平台做的,有几个因素决定: 修改不方便,板块建的小程序是有局限性的,当小程序需要添加或者修改功能的时候都是不允许的 不方便推广,毕竟不是自己的东西,只是基于第三方平台构架的小程序,推广自己的小程序就相当于推广第三方平台 不适合长久使用,长久使用的小程序建议是自己开发一个,如果不懂开发的可以找 开利网络 开发一个小程序,对于后续的维护跟踪,以及修改都提供很有利的条件 这就是那么多人选择定制小程序,而不用 ... -
微信小程序开发里面有什么大商机?[2022-11-05]
1. 看你的资源是如何的。 2. 如果有好的技术就可以开发小程序。 3. 如果自己有实体的企业可以开发一个自己的小程序。 -
微信小程序有哪些开发方案[2022-05-08]
微信小程序”开发之前必须要完成和注册认证。 您好,开发微信小程序之前必须要完成注册认证,你也可以找微信第三方开发商,具体你可以百度一下。 微信小程序申请流程如下: 1. 进入微信公众平台官方网站,点击右上方“立即注册”。 2. 在选择注册账号类型的页面,点击左下方的“小程序”。 3. 填写需要注册的邮箱、密码以及验证码后,点击“注册”按钮。注意:需要之前没有在公众号注册过的邮箱,每个邮箱仅能申请一个小程序,填写完成以后会发送一封确认邮件到邮箱。 4. 登录注册用的邮箱,激活账号。 5. 接下来填写主题类型、 ... -
微信公众号开发多少钱[2022-10-27]
这个按照功能来算费用的。 有的功能比较简单开发费用就比较小,有些就会比较大。 一般情况下普通的开发3000-5000元足够满足了, 如果需要深度开发,那就要1万以上也是很正常的。 -
小猪cms真的免费开发微信小程序?[2022-05-03]
小猪cms本身就是收费的平台,何来免费这一说,不过是把原程序进行升级而已 -
微信公共平台开发适合的行业有哪些 ?[2022-04-10]
各个行业都有的。可以看下小猪CMS,,you shiyong