接收普通消息
普通消息是指员工向企业号应用发送的消息,包括文本、图片、语音、视频、地理位置等类型。普通消息会推送到每个应用在管理端设置的URL(以下假设该URL为http://api.3dept.com)。
- 请求说明
Http请求方式: POST
http://api.3dept.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS×tamp=13500001234&nonce=123412323
text消息
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <MsgId>1234567890123456</MsgId> <AgentID>1</AgentID> </xml>
参数
说明
ToUserName
企业号CorpID
FromUserName
员工UserID
CreateTime
消息创建时间(整型)
MsgType
消息类型,此时固定为:text
Content
文本消息内容
MsgId
消息id,64位整型
AgentID
企业应用的id,整型。可在应用的设置页面查看
参数 | 说明 |
ToUserName | 企业号CorpID |
FromUserName | 员工UserID |
CreateTime | 消息创建时间(整型) |
MsgType | 消息类型,此时固定为:text |
Content | 文本消息内容 |
MsgId | 消息id,64位整型 |
AgentID | 企业应用的id,整型。可在应用的设置页面查看 |
image消息
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[image]]></MsgType> <PicUrl><![CDATA[this is a url]]></PicUrl> <MediaId><![CDATA[media_id]]></MediaId> <MsgId>1234567890123456</MsgId> <AgentID>1</AgentID> </xml>
参数
说明
ToUserName
企业号CorpID
FromUserName
员工UserID
CreateTime
消息创建时间(整型)
MsgType
消息类型,此时固定为:image
PicUrl
图片链接
MediaId
图片媒体文件id,可以调用获取媒体文件接口拉取数据
MsgId
消息id,64位整型
AgentID
企业应用的id,整型。可在应用的设置页面查看
参数 | 说明 |
ToUserName | 企业号CorpID |
FromUserName | 员工UserID |
CreateTime | 消息创建时间(整型) |
MsgType | 消息类型,此时固定为:image |
PicUrl | 图片链接 |
MediaId | 图片媒体文件id,可以调用获取媒体文件接口拉取数据 |
MsgId | 消息id,64位整型 |
AgentID | 企业应用的id,整型。可在应用的设置页面查看 |
voice消息
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1357290913</CreateTime> <MsgType><![CDATA[voice]]></MsgType> <MediaId><![CDATA[media_id]]></MediaId> <Format><![CDATA[Format]]></Format> <MsgId>1234567890123456</MsgId> <AgentID>1</AgentID> </xml>
参数
说明
ToUserName
企业号CorpID
FromUserName
员工UserID
CreateTime
消息创建时间(整型)
MsgType
消息类型,此时固定为:voice
MediaId
语音媒体文件id,可以调用获取媒体文件接口拉取数据
Format
语音格式,如amr,speex等
MsgId
消息id,64位整型
AgentID
企业应用的id,整型。可在应用的设置页面查看
参数 | 说明 |
ToUserName | 企业号CorpID |
FromUserName | 员工UserID |
CreateTime | 消息创建时间(整型) |
MsgType | 消息类型,此时固定为:voice |
MediaId | 语音媒体文件id,可以调用获取媒体文件接口拉取数据 |
Format | 语音格式,如amr,speex等 |
MsgId | 消息id,64位整型 |
AgentID | 企业应用的id,整型。可在应用的设置页面查看 |
video消息
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1357290913</CreateTime> <MsgType><![CDATA[video]]></MsgType> <MediaId><![CDATA[media_id]]></MediaId> <ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId> <MsgId>1234567890123456</MsgId> <AgentID>1</AgentID> </xml>
参数
说明
ToUserName
企业号CorpID
FromUserName
员工UserID
CreateTime
消息创建时间(整型)
MsgType
消息类型,此时固定为:video
MediaId
视频媒体文件id,可以调用获取媒体文件接口拉取数据
ThumbMediaId
视频消息缩略图的媒体id,可以调用获取媒体文件接口拉取数据
MsgId
消息id,64位整型
AgentID
企业应用的id,整型。可在应用的设置页面查看
参数 | 说明 |
ToUserName | 企业号CorpID |
FromUserName | 员工UserID |
CreateTime | 消息创建时间(整型) |
MsgType | 消息类型,此时固定为:video |
MediaId | 视频媒体文件id,可以调用获取媒体文件接口拉取数据 |
ThumbMediaId | 视频消息缩略图的媒体id,可以调用获取媒体文件接口拉取数据 |
MsgId | 消息id,64位整型 |
AgentID | 企业应用的id,整型。可在应用的设置页面查看 |
location消息
<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> <AgentID>1</AgentID> </xml>
参数
说明
ToUserName
企业号CorpID
FromUserName
员工UserID
CreateTime
消息创建时间(整型)
MsgType
消息类型,此时固定为:location
Location_X
地理位置纬度
Location_Y
地理位置经度
Scale
地图缩放大小
Label
地理位置信息
MsgId
消息id,64位整型
AgentID
企业应用的id,整型。可在应用的设置页面查看
参数 | 说明 |
ToUserName | 企业号CorpID |
FromUserName | 员工UserID |
CreateTime | 消息创建时间(整型) |
MsgType | 消息类型,此时固定为:location |
Location_X | 地理位置纬度 |
Location_Y | 地理位置经度 |
Scale | 地图缩放大小 |
Label | 地理位置信息 |
MsgId | 消息id,64位整型 |
AgentID | 企业应用的id,整型。可在应用的设置页面查看 |
---------------------------------------日志开始----------------------------------------------------------
整个被动响应的代码图如下
根据以上信息,我们创建如下几个类,
分组代码图:
类图:
RequestBase为所有接受信息基类,普通消息可直接继承
RequestEvent继承RequestBase,为事件消息的基类
微信接收信息分两种:
一种是接收普通消息(直接继承RequestBase类)
另一种是接收事件(继承RequestEvent类)
微信的消息类型结构如图所示
RequestBase.cs
/// <summary>
/// 接受消息基类
/// </summary>
public class RequestBase
{
public bool LoadStatus = true;
public string ErrorMsg = String.Empty;
/// <summary>
/// 如果消息类型或消息事件没处理,通过这个构造实例化XML_Request对象
/// </summary>
/// <param name="table"></param>
/// <param name="LoaderrorMsg"></param>
public RequestBase(Dictionary<string, string> table, string LoaderrorMsg)
{
this.ToUserName = table["ToUserName"];
this.FromUserName = table["FromUserName"];
this.CreateTime = table["CreateTime"];
this.MsgType = table["MsgType"];
this.AgentID = table["AgentID"];
LoadStatus = false;
ErrorMsg = LoaderrorMsg;
}
public RequestBase(Dictionary<string, string> table)
{
this.ToUserName = table["ToUserName"];
this.FromUserName = table["FromUserName"];
this.CreateTime = table["CreateTime"];
this.MsgType = table["MsgType"];
this.AgentID = table["AgentID"];
}
/// <summary>
/// 微信企业号
/// </summary>
public string ToUserName { set; get; }
/// <summary>
/// 员工UserID
/// </summary>
public string FromUserName { set; get; }
/// <summary>
/// 消息创建时间 (整型)
/// </summary>
public string CreateTime { set; get; }
/// <summary>
/// 消息类型
/// </summary>
public string MsgType { set; get; }
/// <summary>
/// 应用程序ID
/// </summary>
public string AgentID { set; get; }
}
RequestText.cs
/// <summary>
/// 文本消息
/// </summary>
public class RequestText : RequestBase
{
/*
<xml>
<ToUserName><![CDATA[wx78fc2f1a2c006ec1]]></ToUserName>
<FromUserName><![CDATA[garson_zhang@163.com]]></FromUserName>
<CreateTime>1413269690</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[22]]></Content>
<MsgId>4634274969423970332</MsgId>
<AgentID>1</AgentID>
</xml>
*/
public RequestText(Dictionary<string, string> table)
: base(table)
{
this.Content = table["Content"];
this.MsgId = table["MsgId"];
}
public string Content { set; get; }
public string MsgId { set; get; }
}
RequestEvent.cs
/// <summary>
/// 上报菜单事件
/// </summary>
public class RequestEvent : RequestBase
{
public RequestEvent(Dictionary<string, string> table)
: base(table)
{
this.Event = table["Event"];
}
public string Event { set; get; }
}
RequestEvent_Click.cs
/// <summary>
/// 上报菜单点击事件
/// </summary>
public class RequestEvent_Click : RequestEvent
{
/*
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[CLICK]]></Event>
<EventKey><![CDATA[EVENTKEY]]></EventKey>
<AgentID>1</AgentID>
</xml>
*/
public RequestEvent_Click(Dictionary<string, string> table)
: base(table)
{
//this.ToUserName = table["ToUserName"];
//this.FromUserName = table["FromUserName"];
//this.CreateTime = table["CreateTime"];
//this.MsgType = table["MsgType"];
this.EventKey = table["EventKey"];
}
public string EventKey { set; get; }
}
LoadXML.cs,把XML子付出啊转换为对应的消息类型
/// </summary>
/// 消息工厂
/// </summary>
public class LoadXML
{
public static RequestBase GetRequest(string XML)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(XML);
XmlNode root = doc.FirstChild;
Dictionary<string, string> table = new Dictionary<string, string>();
foreach (XmlNode v in root.ChildNodes)
{
table.Add(v.Name, v.InnerText);
}
RequestBase xmlRequest = null;
switch (table["MsgType"])
{
case RequestMessageType.text:
{
xmlRequest = new RequestText(table);
}; break;
case RequestMessageType.fevent:
{
switch (table["Event"])
{
case RequestMessageEventType.click:
{
xmlRequest = new RequestEvent_Click(table);
}; break;
default:
{
xmlRequest = new RequestBase(table, "此点击事件无效,服务器没有处理该事件的操作!\r\n事件类型:" + table["Event"]);
}; break;
}
}; break;
default:
{
xmlRequest = new RequestBase(table, "服务器没有处理该消息的操作!\r\n消息类型:" + table["MsgType"]);
}; break;
}
return xmlRequest;
}
}
-----------------------------------------------------------功能实现-----------------------------------------------------------------------------------------
定义一个加密解密类,继承自WXBizMsgCrypt
/// <summary>
/// 响应消息,处理中心
/// </summary>
public class WXBizMsgCryptAPI : WXBizMsgCrypt
{
#region 字段属性
/// <summary>
/// Token可由企业任意填写,用于生成签名
/// </summary>
public string Token { get; set; }
/// <summary>
/// EncodingAESKey用于消息体的加密,是AES密钥的Base64编码
/// </summary>
public string EncodingAESKey { get; set; }
/// <summary>
/// 集团ID
/// </summary>
public string CorpID { get; set; }
/// <summary>
/// 微信加密签名,msg_signature结合了企业填写的token、请求中的timestamp、nonce参数、加密的消息体
/// </summary>
public string msg_signature { get; set; }
/// <summary>
/// 时间戳,对应URL参数的timestamp
/// </summary>
public string timestamp { get; set; }
/// <summary>
/// 随机串,对应URL参数的nonce
/// </summary>
public string nonce { get; set; }
/// <summary>
/// 加密的随机字符串,以msg_encrypt格式提供。需要解密并返回echostr明文,解密后有random、msg_len、msg、$CorpID四个字段,其中msg即为echostr明文
/// </summary>
public string echostr { get; set; }
#endregion 字段属性
public WXBizMsgCryptAPI(string stoken, string sEncodingAESKey, string sCorpID, string signature, string stimestamp, string snonce)
: base(stoken, sEncodingAESKey, sCorpID)
{
Token = stoken;
EncodingAESKey = sEncodingAESKey;
CorpID = sCorpID;
msg_signature = signature;
timestamp = stimestamp;
nonce = snonce;
}
/// <summary>
/// 检验消息的真实性,并且获取解密后的明文
/// </summary>
/// <param name="sReqData">密文,对应POST请求的数据</param>
/// <param name="sMsg">解密后的原文,当return返回0时有效</param>
/// <returns>成功0,失败返回对应的错误码</returns>
public int DecryptMsg(string sReqData, ref string sMsg)
{
return this.DecryptMsg(msg_signature, timestamp, nonce, sReqData, ref sMsg);
}
/// <summary>
/// 将企业号回复用户的消息加密打包
/// </summary>
/// <param name="sReplyMsg">企业号待回复用户的消息,xml格式的字符串</param>
/// <param name="sEncryptMsg">加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串,当return返回0时有效</param>
/// <returns>成功0,失败返回对应的错误码</returns>
public int EncryptMsg(string sReplyMsg, ref string sEncryptMsg)
{
return this.EncryptMsg(sReplyMsg, timestamp, nonce, ref sEncryptMsg);
}
/// <summary>
/// 获得加密后的XML,返回给微信服务器
/// </summary>
/// <param name="sReqTimeStamp"></param>
/// <param name="sReqNonce"></param>
/// <returns></returns>
public string GetDocument(string sRespData, string sReqTimeStamp, string sReqNonce)
{
//string sRespData = xmlPost.GetXML();
string sEncryptMsg = ""; //xml格式的密文
int ret = EncryptMsg(sRespData, sReqTimeStamp, sReqNonce, ref sEncryptMsg);
if (ret != 0)
{
System.Console.WriteLine("ERR: EncryptMsg Fail, ret: " + ret);
return "";
}
// TODO:
// 加密成功,企业需要将加密之后的sEncryptMsg返回
return sEncryptMsg;
// HttpUtils.SetResponse(sEncryptMsg);
}
/// <summary>
/// 获得加密后的XML,返回给微信服务器
/// </summary>
/// <returns></returns>
public string GetDocument(string sRespData)
{
//string sRespData = xmlPost.GetXML();
string sEncryptMsg = ""; //xml格式的密文
int ret = EncryptMsg(sRespData, ref sEncryptMsg);
if (ret != 0)
{
System.Console.WriteLine("ERR: EncryptMsg Fail, ret: " + ret);
return "";
}
// TODO:
// 加密成功,企业需要将加密之后的sEncryptMsg返回
return sEncryptMsg;
// HttpUtils.SetResponse(sEncryptMsg);
}
}
消息处理类CustomMessageHandler:
public class CustomMessageHandler
{
/// <summary>
/// 微信企业号相应中心
/// </summary>
WXBizMsgCryptAPI apidata;
/// <summary>
/// 当前消息类
/// </summary>
RequestBase CurrentMessage;
/// <summary>
/// 要返回(响应)的xml文档
/// </summary>
public Response_Base ResponseDocument;
/// <summary>
/// 是否取消操作,当产生错误,或者异常发生的时候,不处理,直接返还错误消息
/// </summary>
private bool CancelHandle = false;
/// <summary>
/// 最大上下文消息数
/// </summary>
public int MaxMsgContextCount { get; set; }
/// <summary>
/// 最大命令数
/// </summary>
public int MaxCommandContextCount { get; set; }
private static MessageContext MsgContext = new MessageContext(MsgContext_MsgContextChanged);
/// <summary>
/// 这里需要添加的命令
/// </summary>
/// <param name="CurrentMsg"></param>
private static void MsgContext_MsgContextChanged(RequestBase CurrentMsg)
{
if (false)
MsgContext.InsertCommandContext(CurrentMsg);
}
public MessageContextHandler CurrentMessageContext
{
get
{
return MsgContext.GetMessageContext(CurrentMessage.FromUserName);
}
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="sapidata"></param>
/// <param name="InputStream"></param>
/// <param name="MaxMsgContextCount">最大上下文消息数</param>
/// <param name="MaxCommandContextCount">最大上下文命令数</param>
public CustomMessageHandler(WXBizMsgCryptAPI sapidata, System.IO.Stream InputStream, int MaxMsgContextCount, int MaxCommandContextCount)
{
MsgContext.MsgContextMaxCount = MaxMsgContextCount;
MsgContext.MsgCommandMaxCount = MaxCommandContextCount;
apidata = sapidata;
InputStream.Position = 0;
StreamReader reader = new StreamReader(InputStream);
string sReqData = reader.ReadToEnd();//加密XML信息
string sMsg = ""; // 解析之后的XML明文
//本地调试的时候跳过解密,因为本地调试直接发送的就是未经过加密的xml明文
int ret = apidata.DecryptMsg(sReqData, ref sMsg);
//sMsg = sReqData;
string tt = String.Format("用户发送消息解密后的明文:\r\n{0}", sMsg);
CommonTools.WriteText(tt);
if (ret != 0)
{
SetResponse.WriteContent("错误!");
return;
}
CurrentMessage = LoadXML.GetRequest(sMsg);
if (CurrentMessage.LoadStatus == false)
{
OnErrorResponse(CurrentMessage);
}
else
MsgContext.InsertMsgContext(CurrentMessage);
}
/// <summary>
/// 处理指令,响应
/// </summary>
public void Execute()
{
if (CancelHandle) return;//终止处理
switch (CurrentMessage.MsgType.ToLower())
{
case RequestMessageType.text:
{
OnTextResponse(CurrentMessage as RequestText);
}; break;
case RequestMessageType.fevent:
{
switch ((CurrentMessage as RequestEvent).Event.ToLower())
{
case RequestMessageEventType.click:
{
OnEventResponse_Click(CurrentMessage as RequestEvent_Click);
}; break;
default:
{
OnErrorResponse(CurrentMessage.FromUserName, CurrentMessage.ToUserName, "此点击事件无效,服务器没有处理该事件的操作!\r\n事件类型:" + RequestMessageType.fevent);
}; break;
}
}; break;
default:
{
OnErrorResponse(CurrentMessage.FromUserName, CurrentMessage.ToUserName, "服务器没有处理该消息的操作!\r\n消息类型:" + CurrentMessage.MsgType);
}; break;
}
}
public string Document { get; set; }
#region 响应
/// <summary>
/// 回复text消息
/// </summary>
/// <param name="Content">指令</param>
void OnTextResponse(RequestText currentMessage)
{
DoTextResponse(currentMessage.FromUserName, currentMessage.ToUserName, currentMessage.Content);
}
/// <summary>
/// 相应点击菜单事件
/// </summary>
/// <param name="currentMessage"></param>
void OnEventResponse_Click(RequestEvent_Click currentMessage)
{
DoTextResponse(currentMessage.FromUserName, currentMessage.ToUserName, currentMessage.EventKey);
}
/// <summary>
/// 回复错误消息
/// </summary>
/// <param name="Content">指令</param>
void OnErrorResponse(RequestBase currentMessage)
{
CancelHandle = true;
SetDocument_Text(currentMessage.FromUserName, currentMessage.ToUserName, currentMessage.ErrorMsg);
}
/// <summary>
/// 回复错误消息
/// </summary>
/// <param name="Content">指令</param>
void OnErrorResponse(string FromUserName, string ToUserName ,string ErrorMsg)
{
CancelHandle = true;
SetDocument_Text(FromUserName, ToUserName, ErrorMsg);
}
#endregion
#region 指令处理
/// <summary>
/// 处理文本指令
/// </summary>
/// <param name="FromUserName"></param>
/// <param name="ToUserName"></param>
/// <param name="Content"></param>
void DoTextResponse(string FromUserName, string ToUserName, string Content)
{
string xaData = XAData.GetXAData(FromUserName, Content);
//string xaData = String.Format("你刚刚发送了:{0}", CurrentMessageContext.Contents[0]);
StringBuilder Recodes = new StringBuilder();
//Recodes.AppendFormat("\r\n您一共发送了{0}条消息\r\n", CurrentMessageContext.Contents.Length);
//foreach (string str in CurrentMessageContext.Contents)
//{
// Recodes.AppendFormat("{0}\r\n", str);
//}
Recodes.AppendFormat("\r\n<a href=\"http://xinaoknitting.wicp.net:8088/WX/AttendCardTime.aspx?U=" + CurrentMessage.FromUserName + "\">点击这里</a>查看当月考勤。");
SetDocument_Text(FromUserName, ToUserName, xaData + Recodes.ToString());
}
/// <summary>
/// 返回Text消
/// </summary>
/// <param name="FromUserName"></param>
/// <param name="ToUserName"></param>
/// <param name="xaData"></param>
void SetDocument_Text(string FromUserName, string ToUserName, string xaData)
{
//生成text响应类
Response_Text XML = new Response_Text(FromUserName, ToUserName, xaData);
Document = apidata.GetDocument(XML.GetXML());
}
#endregion
}
MsgRecode
/// <summary>
/// 上下文消息标识
/// </summary>
public class MsgRecode
{
/// <summary>
/// 微信企业号
/// </summary>
public string ToUserName { set; get; }
/// <summary>
/// 员工UserID
/// </summary>
public string FromUserName { set; get; }
/// <summary>
/// 消息创建时间 (整型)
/// </summary>
public string CreateTime { set; get; }
/// <summary>
/// 消息类型
/// </summary>
public string MsgType { set; get; }
/// <summary>
/// 应用程序ID
/// </summary>
public string AgentID { set; get; }
/// <summary>
/// 消息内容
/// </summary>
public string Content { set; get; }
}
MessageContextHandler
public class MessageContextHandler
{
List<MsgRecode> lstMsgContext;//消息上下文
List<MsgRecode> lstCommandContext;//命令上下文
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 消息上下文
/// </summary>
public string[] Contents
{
get
{
return GetContent(lstMsgContext);
}
}
/// <summary>
/// 命令上下文
/// </summary>
public string[] Commands
{
get
{
return GetContent(lstCommandContext);
}
}
public MessageContextHandler(string UserName, List<MsgRecode> MsgContextList, List<MsgRecode> CommandContextList)
{
this.UserName = UserName;
lstMsgContext = MsgContextList;
lstCommandContext = CommandContextList;
}
#region 自定义函数
private string[] GetContent(List<MsgRecode> lst)
{
string[] tmp = new string[lst.Count];
for (int i = 0; i < lst.Count; i++)
tmp[i] = lst[i].Content;
return tmp;
}
#endregion
}
MessageContext
public delegate void CurrentMsgContextChanged(RequestBase CurrentMsg);
/// <summary>
/// 消息上下文
/// </summary>
public class MessageContext
{
Dictionary<string, List<MsgRecode>> dcMsgConText=new Dictionary<string,List<MsgRecode>>();
Dictionary<string, List<MsgRecode>> dcCommandContext=new Dictionary<string,List<MsgRecode>>();
public event CurrentMsgContextChanged MsgContextChanged;
public MessageContext(CurrentMsgContextChanged msgContextChanged)
{
MsgContextChanged = msgContextChanged;
}
//消息上下文
List<MsgRecode> GetMsgContentContext(string userName)
{
if (!dcMsgConText.ContainsKey(userName))
dcMsgConText.Add(userName, new List<MsgRecode>());
return dcMsgConText[userName];
}
//命令上下文
List<MsgRecode> GetCommandContext(string userName)
{
if (!dcCommandContext.ContainsKey(userName))
dcCommandContext.Add(userName, new List<MsgRecode>());
return dcCommandContext[userName];
}
public MessageContextHandler GetMessageContext(string userName)
{
var Msg = GetMsgContentContext(userName);
var Command = GetCommandContext(userName);
MessageContextHandler handler = new MessageContextHandler(userName, Msg, Command);
return handler;
}
private int _msgcontextmaxcount = 1;
/// <summary>
/// 最大上下文消息树
/// </summary>
public int MsgContextMaxCount
{
get
{
return _msgcontextmaxcount;
}
set
{
_msgcontextmaxcount = value > 0 ? value : 1;
}
}
private int _msgcommandmaxcount = 1;
/// <summary>
/// 最大上下文命令数
/// </summary>
public int MsgCommandMaxCount
{
get
{
return _msgcommandmaxcount;
}
set
{
_msgcommandmaxcount = value > 0 ? value : 1;
}
}
/// <summary>
/// 添加消息记录
/// </summary>
/// <param name="request"></param>
public void InsertMsgContext(RequestBase request)
{
MsgRecode mr = GetMsgContext(request);
IntMsgContentContext(mr);
if (MsgContextChanged != null)
MsgContextChanged(request);
}
/// <summary>
/// 添加消息记录
/// </summary>
/// <param name="request"></param>
/// <param name="IsCommand">是否是命令,如果是命令,则为true,也可以用MsgContextChanged事件来调用</param>
public void InsertMsgContext(RequestBase request, bool IsCommand)
{
MsgRecode mr = GetMsgContext(request);
IntMsgContentContext(mr);
if (IsCommand == true)
InsertCommandContext(request);
}
/// <summary>
/// 添加命令记录
/// </summary>
/// <param name="request"></param>
public void InsertCommandContext(RequestBase request)
{
MsgRecode mr = GetMsgContext(request);
IntCommandContext(mr);
}
#region 自定义辅助函数
void IntMsgContentContext(MsgRecode mr)
{
var lstMsgContext = GetMsgContentContext(mr.FromUserName);
while (lstMsgContext.Count >= MsgContextMaxCount)
lstMsgContext.RemoveAt(lstMsgContext.Count);
lstMsgContext.Insert(0, mr);
}
void IntCommandContext(MsgRecode mr)
{
var lstCommandContext = GetCommandContext(mr.FromUserName);
while (lstCommandContext.Count >= MsgCommandMaxCount)
lstCommandContext.RemoveAt(lstCommandContext.Count);
lstCommandContext.Insert(0, mr);
}
private MsgRecode GetMsgContext(RequestBase request)
{
MsgRecode mr = new MsgRecode()
{
ToUserName = request.ToUserName,
FromUserName = request.FromUserName,
CreateTime = request.CreateTime,
MsgType = request.MsgType,
AgentID = request.AgentID
};
if (request is RequestText)
mr.Content = (request as RequestText).Content;
return mr;
}
#endregion
}
/// <summary>
/// 被动响应消息基类
/// </summary>
public class Response_Base
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="msgType"></param>
public Response_Base(string msgType)
{
this.MsgType = msgType;
}
///// <summary>
///// 获得XML明文
///// </summary>
///// <returns></returns>
//public abstract string GetXML();
/// <summary>
/// 员工UserID
/// </summary>
public string ToUserName { get; set; }
/// <summary>
/// 企业号CorpID
/// </summary>
public string FromUserName { get; set; }
/// <summary>
/// 消息创建时间(整型)
/// </summary>
public string CreateTime { get; set; }
/// <summary>
/// 消息类型,:text,image,voice,video,news
/// </summary>
public string MsgType { get; set; }
public virtual string GetXML()
{
throw new Exception("没有重写GetXML方法");
}
}
/// <summary>
/// 被动响应消息text
/// </summary>
public class Response_Text : Response_Base
{
/*
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[this is a test]]></Content>
</xml>
*/
string xmlformat = @" <xml>
<ToUserName><![CDATA[{0}]]></ToUserName>
<FromUserName><![CDATA[{1}]]></FromUserName>
<CreateTime>{2}</CreateTime>
<MsgType><![CDATA[{3}]]></MsgType>
<Content><![CDATA[{4}]]></Content>
</xml>";
/// <summary>
/// 构造函数
/// </summary>
/// <param name="toUser">员工UserID </param>
/// <param name="fromUser">企业号CorpID </param>
/// <param name="content">文本消息内容 </param>
/// <param name="createTime">消息创建时间(整型),参考:APITools.GetCreateTime()</param>
public Response_Text(string toUser, string fromUser, string content, string createTime)
: base(RequestMessageType.text)
{
this.ToUserName = toUser;
this.FromUserName = fromUser;
this.Content = content;
this.CreateTime = createTime;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="toUser">员工UserID </param>
/// <param name="fromUser">企业号CorpID </param>
/// <param name="content">文本消息内容 </param>
public Response_Text(string toUser, string fromUser, string content)
: base(RequestMessageType.text)
{
this.ToUserName = toUser;
this.FromUserName = fromUser;
this.Content = content;
this.CreateTime = CorpTools.GetCreateTime();
}
/// <summary>
/// 获得XML文本
/// </summary>
/// <returns></returns>
public override string GetXML()
{
return String.Format(xmlformat, ToUserName, FromUserName, CreateTime, MsgType, Content);
}
/// <summary>
/// 文本消息内容
/// </summary>
public string Content { get; set; }
}
代码贴完了,接下来是接口调用:
public void ProcessRequest(HttpContext context)
{
WriteText("开始回调:" + context.Request.Url.ToString());
//微信接入的测试
string token = ConfigurationManager.AppSettings["CorpToken"];//从配置文件获取Token
string CorpID = ConfigurationManager.AppSettings["CorpID"];//从配置文件获取Token
string EncodingAESKey = ConfigurationManager.AppSettings["EncodingAESKey"];//从配置文件获取Token
int MaxMsgContextCount = ConvertEx.ToInt(ConfigurationManager.AppSettings["MaxMsgContextCount"], 10);//最大上下文消息数
int MaxCommandContextCount = ConvertEx.ToInt(ConfigurationManager.AppSettings["MaxCommandContextCount"], 3);//最大命令数
string signature = context.Request["msg_signature"];
string timestamp = context.Request["timestamp"];
string nonce = context.Request["nonce"];
if (context.Request.HttpMethod == "GET")//验证
{
WriteText("Get验证");
string echostr = context.Request["echostr"];
StringBuilder Txt=new StringBuilder();
Txt.Append("Get微信接口验证\r\n");
Txt.AppendFormat("signature:{0}\r\n", signature);
Txt.AppendFormat("timestamp:{0}\r\n", timestamp);
Txt.AppendFormat("nonce:{0}\r\n", nonce);
Txt.AppendFormat("echostr:{0}\r\n", echostr);
Txt.AppendFormat("EncodingAESKey:{0}\r\n", EncodingAESKey);
Txt.AppendFormat("CorpID:{0}\r\n", CorpID);
Txt.AppendFormat("CorpToken:{0}\r\n", token);
CommonTools.WriteText(Txt.ToString());
string sEchoStr = "";
bool check = CheckSignatureQY.Check(signature, timestamp, nonce, echostr
, EncodingAESKey, CorpID, ref sEchoStr, token);//True表示成功
//WriteText(check ? "True" : "False");
//check为True成功,Flase失败,失败信息在SechoStr
CommonTools.WriteText("结果为:" + (check ? "True" : "False"));
CommonTools.WriteText("验证返回字符串为:" + sEchoStr);
WriteContent(sEchoStr); //返回随机字符串则表示验证通过
}
else//消息
{
//记录发送的消息
string url = context.Request.Url.ToString();
context.Request.InputStream.Position = 0;
StreamReader reader = new StreamReader(context.Request.InputStream);
string sReqData = reader.ReadToEnd();//加密XML信息
string str=String.Format("URL\r\n{0}\r\nXML\r\n{1}",url,sReqData);
WriteText(str);
WXBizMsgCryptAPI apidata = new WXBizMsgCryptAPI(token, EncodingAESKey, CorpID, signature, timestamp, nonce);
CustomMessageHandler messageHandler = new CustomMessageHandler(apidata,context.Request.InputStream,MaxMsgContextCount,MaxCommandContextCount);
try
{
messageHandler.Execute();
WriteContent(messageHandler.Document);
return;
}
catch (Exception ex)
{
WriteContent("");
}
finally
{
}
}
}
private void WriteText(string p)
{
CommonTools.WriteText(p);
}
public bool IsReusable
{
get
{
return false;
}
}
private void WriteContent(string str)
{
HttpContext.Current.Response.Write(str);
}