一、相关实体类
依据接收到的xml消息模板来创建对应的实体类,相关xml消息我就不在这里写了,可以去官方文档中查看https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140453
1.用户发送的xml消息通用节点
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/// <summary>
/// Message 的摘要说明
/// </summary>
public class BaseMessage
{
public BaseMessage()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
//开发者微信号
public string ToUserName;
//发送方帐号(一个OpenID)
public string FromUserName;
//消息创建时间 (整型)
public string CreateTime;
// 消息类型,图片为image
public string MsgType;
}
2、文本消息
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/// <summary>
/// TextMessage 的摘要说明
/// </summary>
public class TextMessage: BaseMessage
{
public TextMessage()
{
}
//消息内容
public string Content;
}
3、图片消息
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/// <summary>
/// ImgMessage 的摘要说明
/// </summary>
public class Img:BaseMessage
{
public Img()
{
}
//图片链接(由系统生成)
public string PicUrl;
//图片消息媒体id,可以调用获取临时素材接口拉取数据
public string MediaId;
//消息id,64位整型
public string MsgId;
}
4、链接
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/// <summary>
/// LINK 的摘要说明
/// </summary>
public class Link:BaseMessage
{
public Link()
{
}
// 消息标题
private string Title;
// 消息描述
private string Description;
//消息链接
private string Url;
//消息id,64位整型
private string MsgId;
}
5、语音消息
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/// <summary>
/// VoiceMessage 的摘要说明
/// </summary>
public class Voice:BaseMessage
{
public Voice()
{
}
//语音消息媒体id,可以调用获取临时素材接口拉取数据。
public string MediaId;
/// <summary>
///语音格式,如amr,speex等
/// </summary>
public string Format;
//语音识别结果,UTF8编码
public string Recognition;
//消息id,64位整型
public string MsgId;
}
6、视频消息
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/// <summary>
/// VideoMessage 的摘要说明
/// </summary>
public class Video:BaseMessage
{
public Video()
{
}
//视频消息媒体id,可以调用获取临时素材接口拉取数据
public string MediaId;
//视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
public string ThumbMediaId;
//消息id,64位整型
public string MsgId;
}
二、消息回复及事件处理
被动消息回复,包含了文本、语音、图片、视频、音乐、图文,下面值写了前四个和相应的事件如:扫码关注、点击等事件,具体可参考https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140543。
using System;
using System.Collections.Generic;
using System.Web;
using System.IO;
using System.Text;
using System.Web.Security;
using System.Xml;
/// <summary>
/// 接受/发送消息帮助类
/// </summary>
public class MessageHelper
{
//返回消息
public string ReturnMessage(string postStr)
{
string responseContent = "";
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(new System.IO.MemoryStream(System.Text.Encoding.GetEncoding("UTF-8").GetBytes(postStr)));
XmlNode MsgType = xmldoc.SelectSingleNode("/xml/MsgType");
if (MsgType != null)
{
switch (MsgType.InnerText)
{
case "event":
responseContent = EventHandle(xmldoc);//事件处理
break;
case "text":
responseContent = CommonApi.ReplayMesg<TextMessage>(xmldoc);//接受文本消息处理
break;
case "image":
responseContent = CommonApi.ReplayMesg<Img>(xmldoc);//接受图片消息处理
break;
case "voice":
responseContent = CommonApi.ReplayMesg<Voice>(xmldoc);//接受声音消息处理
break;
case "video":
responseContent = CommonApi.ReplayMesg<Video>(xmldoc);//接受视频消息处理(不好用)
break;
default:
break;
}
}
return responseContent;
}
//事件
public string EventHandle(XmlDocument xmldoc)
{
string responseContent = "";
XmlNode Event = xmldoc.SelectSingleNode("/xml/Event");
XmlNode EventKey = xmldoc.SelectSingleNode("/xml/EventKey");
XmlNode ToUserName = xmldoc.SelectSingleNode("/xml/ToUserName");
XmlNode FromUserName = xmldoc.SelectSingleNode("/xml/FromUserName");
if (Event != null)
{
//菜单单击事件
if (Event.InnerText.Equals("CLICK"))
{
if (EventKey.InnerText.Equals("V1001_TODAY_MUSIC"))// 这个V1001_TODAY_MUSIC就是菜单里面的key
{
responseContent = string.Format(ReplyType.TextMessage,
FromUserName.InnerText,
ToUserName.InnerText,
DateTime.Now.Ticks,
"正在开发中,敬请期待!");
}
if (EventKey.InnerText.Equals("V1001_GOOD"))// 这个V1001_TODAY_MUSIC就是菜单里面的key
{
responseContent = string.Format(ReplyType.TextMessage,
FromUserName.InnerText,
ToUserName.InnerText,
DateTime.Now.Ticks,
"谢谢君的点赞,我们会更加努力的!");
}
if (EventKey.InnerText.Equals("V1001_TODAY_SINGER"))//获取文章 这个V1001_TODAY_SINGER就是菜单里面的key
{
responseContent = string.Format(ReplyType.Articles,
FromUserName.InnerText,
ToUserName.InnerText,
DateTime.Now.Ticks,2,
"", "", "http://cet.neea.edu.cn/query/images/160330152.png", ""
,
"大学英语四六级成绩查询", "今天我们就来看看英语如何学习。。。。", "http://cet.neea.edu.cn/query/images/160330152.png", "http://cet.neea.edu.cn/cet");
}
}
else if (Event.InnerText.Equals("scancode_waitmsg")) //扫码推事件且弹出“消息接收中”提示框的事件推送
{
if (EventKey.InnerText.Equals("rselfmenu_0_0")) //点击防伪扫描
{ //....处理返回逻辑
XmlNode ScanResult = xmldoc.SelectSingleNode("/xml/ScanCodeInfo/ScanResult");
responseContent = string.Format(ReplyType.TextMessage,
FromUserName.InnerText,
ToUserName.InnerText,
DateTime.Now.Ticks,
ScanResult.InnerText);
}
}//关注时触发
else if (Event.InnerText.Equals("subscribe"))
{
responseContent = string.Format(ReplyType.TextMessage,
FromUserName.InnerText,
ToUserName.InnerText,
DateTime.Now.Ticks,
"谢谢君的关注,我们会更加努力的!");
}//取消关注触发
else if (Event.InnerText.Equals("unsubscribe"))
{
}
else if (Event.InnerText.Equals("SCAN"))
{
responseContent = string.Format(ReplyType.TextMessage,
FromUserName.InnerText,
ToUserName.InnerText,
DateTime.Now.Ticks,
"谢谢君的关注,我们会更加努力的!");
}
}
return responseContent;
}
//写入日志
public static void WriteLog(string text)
{
StreamWriter sw = new StreamWriter(HttpContext.Current.Server.MapPath(".") + "\\log.txt", true);
sw.WriteLine(text);
sw.Close();
}
}
三、通用的API类
获取token、发送post请求、解析json、利用反射实现消息回复通用模板等方法类
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Web;
using System.Xml;
/// <summary>
/// IWeixinAction 的摘要说明
/// </summary>
public class CommonApi
{
public CommonApi()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
/// <summary>
/// 获取凭证接口
/// </summary>
/// <param name="grant_type">获取access_token填写client_credential</param>
/// <param name="appid">第三方用户唯一凭证</param>
/// <param name="secret">第三方用户唯一凭证密钥,既appsecret</param>
/// <returns></returns>
public static string GetAccessToken(string appid, string secret)
{
string token = OperationXml.GetXMLToken();
if (token == "")
{
string strJson = RequestUrl(string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", appid, secret));
token = GetJsonValue(strJson, "access_token");
OperationXml.UpdateXMLToken(token, DateTime.Now);
}
return token;
}
public static string RequestUrl(string strUrl)
{
// 设置参数
HttpWebRequest request = WebRequest.Create(strUrl) as HttpWebRequest;
CookieContainer cookieContainer = new CookieContainer();
request.CookieContainer = cookieContainer;
request.AllowAutoRedirect = true;
request.Method = "POST";
request.ContentType = "text/html";
request.Headers.Add("charset", "utf-8");
//发送请求并获取相应回应数据
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
//直到request.GetResponse()程序才开始向目标网页发送Post请求
Stream responseStream = response.GetResponseStream();
StreamReader sr = new StreamReader(responseStream, Encoding.UTF8);
//返回结果网页(html)代码
string content = sr.ReadToEnd();
return content;
}
#region 解析用户列表json字符串,返回昵称为nickName的openid
public string getValue(string json,string nickName) {
JObject jobj = JObject.Parse(json);
JToken jtoken = jobj["data"];
for (int i = 0; i < jtoken["openid"].Children().Count(); i++)
{
//获取该用户的信息
string result = GetResult("https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + CommonApi.GetAccessToken("wxadf0f0c801b521fa", "35e3c8aeaa8c12d2bc76c1c12570bc96") + "&openid=" + jtoken["openid"][i].ToString());
JObject resultObj = JObject.Parse(result);
string nickname = resultObj["nickname"].ToString();
if (nickname.Equals(nickName))
return jtoken["openid"][i].ToString();
}
return null;
}
#endregion
#region 获取响应url的json字符串
public string GetResult(string posturl)
{
Stream instream = null;
StreamReader sr = null;
HttpWebResponse response = null;
HttpWebRequest request = null;
Encoding encoding = Encoding.UTF8;
// 准备请求...
try
{
// 设置参数
request = WebRequest.Create(posturl) as HttpWebRequest;
CookieContainer cookieContainer = new CookieContainer();
request.CookieContainer = cookieContainer;
request.AllowAutoRedirect = true;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
//发送请求并获取相应回应数据
response = request.GetResponse() as HttpWebResponse;
//直到request.GetResponse()程序才开始向目标网页发送Post请求
instream = response.GetResponseStream();
sr = new StreamReader(instream, encoding);
//返回结果网页(html)代码
string content = sr.ReadToEnd();
return content;
}
catch (Exception ex)
{
string err = ex.Message;
return string.Empty;
}
}
#endregion
#region 获取Json字符串某节点的值
/// <summary>
/// 获取Json字符串某节点的值
/// </summary>
public static string GetJsonValue(string jsonStr, string key)
{
string result = string.Empty;
if (!string.IsNullOrEmpty(jsonStr))
{
key = "\"" + key.Trim('"') + "\"";
int index = jsonStr.IndexOf(key) + key.Length + 1;
if (index > key.Length + 1)
{
//先截逗号,若是最后一个,截“}”号,取最小值
int end = jsonStr.IndexOf(',', index);
if (end == -1)
{
end = jsonStr.IndexOf('}', index);
}
result = jsonStr.Substring(index, end - index);
result = result.Trim(new char[] { '"', ' ', '\''}); //过滤引号或空格
}
}
return result;
}
#endregion
#region 回复消息的xml模板
public static string ReplayMesg<T>(XmlDocument xmldoc)
{
Dictionary<string,string> dictionary=new Dictionary<string,string>();
//反射获取字段信息
T t = default(T);
t=Activator.CreateInstance<T>();
FieldInfo[] infos= t.GetType().GetFields();
foreach (FieldInfo info in infos)
{
dictionary.Add(info.Name,xmldoc.SelectSingleNode("/xml/"+info.Name).InnerText);
}
//获取信息xml模板
string messageFormat= typeof(ReplyType).GetProperty(t.GetType().Name).GetValue(null).ToString();
switch (dictionary["MsgType"])
{
case "text": return getFormat(dictionary, messageFormat, new object[] { dictionary["Content"]});
case "image": return getFormat(dictionary, messageFormat, new object[] {dictionary["MediaId"] });
case "voice": return getFormat(dictionary, messageFormat, new object[] { dictionary["MediaId"] });
case "video": return getFormat(dictionary, messageFormat, new object[] { dictionary["MediaId"], "title", "description" });
}
return null;
}
private static string getFormat(Dictionary<string, string> dictionary, string messageFormat,params object []arr)
{
string responseContent = string.Empty;
object[] arrs = new object[arr.Length+3];
arrs[0]=dictionary["FromUserName"];
arrs[1]= dictionary["ToUserName"];
arrs[2] = DateTime.Now.Ticks;
arr.CopyTo(arrs,3);
return responseContent = string.Format(messageFormat,arrs);
}
#endregion
}
四、存储Token及创建时间在xml中
每次Token的获取有效期为7200s,所以在获取是需要判断是否失效或者存在,如果为否则就获取新的Token并存储在xml中
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
/// <summary>
/// OperationXml 的摘要说明
/// </summary>
public class OperationXml
{
public OperationXml()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
/// <summary>
/// 获取XML文件路径
/// </summary>
public static string xmlName = AppDomain.CurrentDomain.BaseDirectory + @"AccessToken.xml";
/// <summary>
/// 读取XML Token
/// </summary>
/// <param name="xmlUrl"></param>
/// <returns></returns>
public static string GetXMLToken()
{
try
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlName);
XmlNode xn = xmlDoc.SelectSingleNode("ACCESS_TOKEN");
XmlElement xe = (XmlElement)xn;//将子节点类型转换为XmlElement类型
string Token = "";
string CreateTime = "";
foreach (XmlNode xn1 in xe)//遍历
{
XmlElement xe2 = (XmlElement)xn1;//转换类型
if (xe2.Name == "Token")//如果找到
{
Token = xe2.InnerText;//则修改
}
if (xe2.Name == "CreateTime")//如果找到
{
CreateTime = xe2.InnerText;//则修改
}
}
int seconds = 0;
if (CreateTime.Trim() != "")
{
DateTime ct = Convert.ToDateTime(CreateTime);
TimeSpan ts = (DateTime.Now - ct);
seconds =ts.Days*24*60*60+ts.Hours*60*60+ts.Seconds+Convert.ToInt32(ts.Milliseconds*0.001);
}
MessageHelper.WriteLog("Token:" + Token);
if (seconds > 7200 || seconds == 0)
{
return "";
}
else
{
return Token;
}
}
catch (Exception ex)
{
MessageHelper.WriteLog("异常:" + ex.ToString());
return "";
}
}
/// <summary>
/// 修改Token
/// </summary>
/// <param name="token"></param>
/// <param name="createTime"></param>
public static void UpdateXMLToken(string token, DateTime createTime)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlName);
XmlNode xn = xmlDoc.SelectSingleNode("ACCESS_TOKEN");
XmlElement xe = (XmlElement)xn;//将子节点类型转换为XmlElement类型
foreach (XmlNode xn1 in xe)//遍历
{
XmlElement xe2 = (XmlElement)xn1;//转换类型
if (xe2.Name == "Token")//如果找到
{
xe2.InnerText = token;//则修改
}
if (xe2.Name == "CreateTime")//如果找到
{
xe2.InnerText = createTime.ToString();//则修改
}
}
xmlDoc.Save(xmlName);
}
}
五、消息回复xml模板
这类中有一些没有用到的,就没有对他进行更改,我先应该可以能够看出来,用的话就需要自己去改了哦。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/// <summary>
/// ReplyType 的摘要说明
/// //回复类型
/// </summary>
public class ReplyType
{
public ReplyType()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
/// <summary>
/// 普通文本消息
/// </summary>
public static string TextMessage
{
get
{
return @"<xml>
<ToUserName><![CDATA[{0}]]></ToUserName>
<FromUserName><![CDATA[{1}]]></FromUserName>
<CreateTime>{2}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[{3}]]></Content>
</xml>";
}
}
/// <summary>
/// 图片消息
/// </summary>
public static string Img
{
get
{
return @"<xml>
<ToUserName><![CDATA[{0}]]></ToUserName>
<FromUserName><![CDATA[{1}]]></FromUserName>
<CreateTime>{2}</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA[{3}]]></MediaId>
</Image>
</xml>";
}
}
/// <summary>
/// 图文消息
/// </summary>
public static string Articles
{
get
{
return @"<xml>
<ToUserName><![CDATA[{0}]]></ToUserName>
<FromUserName><![CDATA[{1}]]></FromUserName>
<CreateTime>{2}</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>{3}</ArticleCount>
<Articles>
<item>
<Title><![CDATA[{4}]]></Title>
<Description><![CDATA[{5}]]></Description>
<PicUrl><![CDATA[{6}]]></PicUrl>
<Url><![CDATA[{7}]]></Url>
</item>
<item>
<Title><![CDATA[{8}]]></Title>
<Description><![CDATA[{9}]]></Description>
<PicUrl><![CDATA[{10}]]></PicUrl>
<Url><![CDATA[{11}]]></Url>
</item>
</Articles>
</xml>";
}
}
/// <summary>
/// 语言消息
/// </summary>
public static string Voice
{
get
{
return @"<xml>
<ToUserName><![CDATA[{0}]]></ToUserName>
<FromUserName><![CDATA[{1}]]></FromUserName>
<CreateTime>{2}</CreateTime>
<MsgType><![CDATA[voice]]></MsgType>
<Voice>
<MediaId><![CDATA[{3}]]></MediaId>
</Voice>
</xml>";
}
}
/// <summary>
/// 视频消息
/// </summary>
public static string Video
{
get
{
return @"<xml>
<ToUserName><![CDATA[{0}]]></ToUserName>
<FromUserName><![CDATA[{1}]]></FromUserName>
<CreateTime>{2}</CreateTime>
<MsgType><![CDATA[video]]></MsgType>
<Video>
<MediaId><![CDATA[{3}]]></MediaId>
<Title><![CDATA[{4}]]></Title>
<Description><![CDATA[{5}]]></Description>
</Video>
</xml>";
}
}
/// <summary>
/// 音乐消息
/// </summary>
public static string Music
{
get
{
return @"<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[music]]></MsgType>
<Music>
<Title><![CDATA[TITLE]]></Title>
<Description><![CDATA[DESCRIPTION]]></Description>
<MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl>
<HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl>
<ThumbMediaId><![CDATA[media_id]]></ThumbMediaId>
</Music>
</xml>";
}
}
/// <summary>
/// 位置信息
/// </summary>
public static string Location
{
get
{
return @"<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1351776360</CreateTime>
<MsgType><![CDATA[location]]></MsgType>
<Location_X>23.134521</Location_X>
<Location_Y>113.358803</Location_Y>
<Scale>20</Scale>
<Label><![CDATA[位置信息]]></Label>
<MsgId>1234567890123456</MsgId>
</xml>";
}
}
/// <summary>
/// 公众平台官网链接
/// </summary>
public static string Link
{
get
{
return @"<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1351776360</CreateTime>
<MsgType><![CDATA[link]]></MsgType>
<Title><![CDATA[公众平台官网链接]]></Title>
<Description><![CDATA[公众平台官网链接]]></Description>
<Url><![CDATA[url]]></Url>
<MsgId>1234567890123456</MsgId>
</xml>";
}
}
}