消息类型
最基的接口。
public interface IEntityBase{}
所有请求响应的基接口。
public interface IMessageBase : IEntityBase
{
string ToUserName{get;set;}
string FromUserName{get;set;}
DateTime CreateTime{get;set;}
}
请求的基接口。
public interface IRequestMessageBase
{
RequestMsgType MsgType{get;}
string Encrypt{get;set;}
long MsgId{get;set;}
}
请求的基类
public class RequestMessageBase : IRequestMessageBase
{
public virutal RequestMsgType MsgType
{
get {return ReuqstMsgType.Text;}
}
public string Encrypt{get;}
public RequestMessageBase(){}
public long MsgId{get;set;}
}
文本类型的请求消息
public class RequestMessageText : RequestMessageBase, IRequestMessageBase,IRequestText
{
public override ReqestMsgType MsgType
{
get {return RequestMsgType.Text;}
}
public string Content{get;set;}
}
图片请求消息
publci class RequestMessageImage : RequestMessageBase, IRequestMessageBase
{
public override ReqestMsgType MsgType
{
get {return RequestMsgType.Image;}
}
public string MediaId{get;set;}
public string PicUrl{get;set;}
}
其它请求消息
- RequestMessageVoice
- RequestMessageVideo
- RequestMessageShortVideo
- RequestMessageLocation
- RequestMessageLink
- RequestMessageEventBase
事件基接口。
public interface IReqestMessageEventBase : IRequestMessageBase
{
Event Event{get;}
}
事件基类。
public class RequestMessageEventBase : RequestMessageBase, IRequestMessageEventBase
{
public override ReqeustMsgType MsgType
{
get {return RequestMsgType.Event;}
}
public virtual Event Event
{
get {return Event.ENTER;}
}
}
事件消息基类的子类还有其它共同属性,通过一个接口来实现。
public interface IRequestMessageEventKey
{
string EventKey{get;set;}
}
事件订阅消息
public class RequestMessageEvent_Subscribe : RequestMessageEventBase, IRequestMessageEventBase, IRequestMessageEventKy
{
public override Event Event
{
get {return Evnet.Subscribe;}
}
//场景中二维码带的参数
public string EventKey{get;set;}
//场景中二维码的ticket
public string Ticket{get;set;}
}
取消订阅事件消息
public class RequestMessageEvent_Unsubscribe : RequestMessageEventBase, IRequestMessageEventBase
{
public override Event Event
{
get {return Event.unsubscribe;}
}
}
- 进入回话事件消息:RequestMessageEvent_Enter
- 公众号二维码扫描事件消息:RequestMessageEvent_Scan
- 获取用户地理位置事件消息:RequestMessageEvent_Location
- 点击菜单事件消息:RequestMessageEvent_Click
- URL跳转事件消息:RequestMessageEvent_View
- 扫码事件消息:RequestMessageEvent_Scancode_Push
- 扫码事件弹出提示框:RequestMessageEvent_Scancode_Waitingmsg
- 弹出拍照发图事件消息:RequestMessageEvent_Pic_Sysphoto
- 弹出拍照或相册发图事件消息:RequestMessageEvent_Pic_Photo_Or_Album
- 弹出微信相册发图事件消息:RequestMessageEvent_Locaiton_Select
- 群发结果事件消息:RequestMessageEvent_MassSendJobFinish
- 模板推送结束事件消息:RequestMessageEvent_TemplateSendJobFinish
- 卡卷通过审核事件消息:RequestMessageEvent_Card_Pass_Check
- 卡卷未通过审核事件消息:RequestMessageEvent_Card_Not_Pass_Check
- 领取卡卷事件消息:RequestMessageEvent_User_Get_Card
- 删除卡券事件消息:RequestMessageEvent_User_Del_Card
- 客服接入会话事件消息:RequestMessageEvent_Kf_Create_Session
- 客服关闭会话事件消息:RequestMessageEvent_Kf_Close_Session
- 客服转接会话事件消息:RequestMessageEvent_Kf_Switch_Session
- 门店审核结果通过事件消息:RequestMessageEvent_Poi_Check_Notify
- wifi连网事件消息:RequestMessageEvent_WifiConnected
- 卡券核销事件消息:RequestMessageEvent_User_Consume_Card
- 从卡券进入公众号会话:RequestMessageEvent_User_Enter_Session_From_Card
- 进入会员卡事件消息:RequestMessageEvent_User_View_Card
- 微小店订单付款通知事件消息:RequestMessageEvent_Merchant_Order
- 接收会员信息事件消息:RequestMessageEvent_Submit_Membercard_User_Info
- 摇一摇事件通知消息:RequestMessageEvent_ShakearoundUserShake
响应消息
响应也有基接口和基类。
public class ResponseMessageBase : IResponseMessageBase
{
//注意,在响应的基类中没有MsgId,这意味着,应用程序回复微信服务器的消息必须一次成功,如果不成功,客户端收到的信息是:公众号暂时无法提供服务,请稍后再试。例如,微信服务器连续发了3条MsgId一样的消息到应用服务器,如果应用服务器没有对消息去重,会分别响应三次请求,客户端只会收到最后一次发送的信息
public virutal ResponseMsgType MsgType
{
get {return ResponseMsgType.Text;}
}
//从请求消息返回响应类型实例
public static T CreateFromRequestMessage<T>(IRequestMessageBase requestMessage) where T : ResponseMessageBase
{
try{
var tType = typeof(T);
var responseName = tType.Name.Replace("ResponseMessage","");
ResponseMsgType msgType = (ResponseMsgType)Enum.Parse(typeof(ReesponseMsgType), responseName);
return CreateFromRequestMessage(requestMessage, msgType) as T;
}
catch(Exception ex)
{
throw new WeixinException();
}
}
}
图文的响应消息
public class ResponseMssageNews : ResponseMessageBase, IResponseMessageBase
{
new public virutal ResponseMsgType MsgType
{
get {return ResponseMsgType.News;}
}
public int ArticalCount
{
get {
return Articles = null ? 0 : ArTICALS.Count;
}
set{
}
}
public List<Article> Articles{get;set;}
public ResponseMessageNews()
{
Articles = new List<Article>();
}
}
最多10条图文。
使用MessageHandler
public class CustomMessageHandler : MessageHandler<CustomMessageContext>
{
public CustomMessageHandler(Stream inputStream, PostModel postModel) : base(intpuStream, postModel)
{
}
//必须重写的方法
//如果所有的方法不生效,用这个兜底
public override IResponseMessageBae DefaultResponseMessage(IRequestMessageBase requestMessage)
{
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "";
return responseMessage;
}
public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage)
{
}
}
MessageHandler
中有很多方法,虚方法可以重写。
public class MessageHandler
{
//抽象方法必须被重写
//抽象方法是没有方法体的
public abstract IResponseMessageBase DefaultReposneMessage(IRequestMessageBase requestMessage);
//虚方法不一定需要被重写
//在OnTextRequest或OnEventRequest之前被触发
//如果返回null,继续执行OnTextRequest或OnEventRequest
//如果返回不是Null,终止执行OnTextRequest或OnEventRequest
//如果客户端传来的是事件消息,会将RequestmessageEvent自动转换成RequestMessageText类型,其中RequestMessageText.Content就是RequestMessageEvent.EventKey
public virutal IResponseMessageBase OnTextOrEventRequest(RequestMessageText requestMessage)
{
}
...
public virutal IResponseMessageBase OnEvent_LocaltionRequest(RequestMessageEvent_Location requestMessage){};
}
在控制器中的使用
[HttpPost]
[Actionname("Index")]
public ActionResult Post(PostModel postModel)
{
if(!CheckSignature.Check(postModel.Signature, postModel.Timestamp, postModel.Nonce, Token))
{
return Content();
}
postModel.Token = "";
postModel.EncodingAESKey = "";
postMode.AppId = AppId;
var messageHandle = new CustomMessageHandler(Request.InputStream, postModel);
messageHandler.Execute();
return new FixWeixinBugWeixinResult(messageHandler);
}
MessageHandler
的OnExecuting
和OnEecuted
方法
public class CustomMessageHandler
{
public override void OnExecuting()
{
}
public override void OnExecuted()
{
}
}
用户上下文
客户端的信息如何保存下来呢?放到一个集合类里,对数量做规定。
public class MessageContainer<T> : List<T>
{
}
所有的消息会进入消息队列。
public class MessageQueue<TM, TRequest, TResponse> : List<TM>
where TM : class, IMessageContext<TRequest, TResponse>,new()
where TRequest : IRequestmessageBase
where TResponse : IResponseMessageBase
{
}
单个用户的信息放在了MessageContext
中,从接口开始。
public interface IMessageContext<TRequest, TResponse>
where TRequest : IRequestMessageBase
where TResponse : IResponseMessageBase
{
string UserName
DateTime LastAcitveTime
MessageContianer<TRequest> RequestMessages
MessageContainer<TResponse> ResponseMessages
int MaxRecordCount
object StorageData//存储用户状态
Double? ExpireMinutes;
AppStoreState AppStoreState;
//上下文移除时触发
event EventHandler<WeixinContextRemovedEventArgs<TRequest, TResponse>> MessageContextRemoved;
void OnRemoved();//消息删除时触发
}
上下文的实现类。
public class MessageContext<TRequest, TResponse> : IMessageContext<TRequest, TResponse>
where TRequest : IRequestMessageBae
where TResponse : IResponseMessageBase
{
private int _maxRecourdCount;
public string UserName{get;set;}
public DateTime LastActiveTime{get;set;}
public MessageContainer<TRequest> RequestMessages{get;set;}
public MessageContainer<TResponse> ResponseMessages{get;set;}
public int MaxRecourdCount
{
get
{
return _maxRecourdCount;
}
set
{
RequestMessages.MaxRecordCount= value;
ResponseMessages.MaxRecourdCOunt = value;
_maxRecourdCount = value;
}
}
public object StorageData{get;set;}
public Double? ExpireMinutes{get;set;}
publci AppStoreState AppStoreState{get;set;}
public virutal event EventHandler<WeixinContextRemovedEventArgs<TRequest, TResponse>> MessageCOntextRemoved = null;
public messageContext()
{
RequestMessages = new MessageContainer<TRequest>(MaxRecountCount);
ResponseMessages = new MessageContainer<TResponse>(MaxRecourdCount);
LastActiveTime = DateTime.Now;
}
private void OnMessageContextRemoved(WeixinContextRemovedEventArgs<TRequest, TResponse> e)
{
EventHadnler<WeixinContextRemovedEventArgs<TReqeust, TRespone>> temp = MessageContextRemoved;
if(temp!=null)
{
temp(this,e);
}
}
public virutal void OnRemoved()
{
var onRemoveArg = new WeixinContextRemovedEventArgs<TRequest, TResponse>(this);
OnMssageContextRemoved(onRemovedArg);
}
}
自定义一个上下文
publci class CustomMessageContext : MessageContext<IRequestMessageBase, IResponseMessageBase>
{
public CustomMessageContext()
{
base.MessageContextRemoved += CustmMessageContext_MessageContextRemoved;
}
void CustomMessageContext_MessageContextRemovied(object sender, WeixinContextRemovedEventArs<IRequestMessageBase, IResponsMessageBase> e)
{
var messageContex = e.MessageContext as CustomMessageContext;
if(messageContext ==null) return;
//TODO:
}
}
全局上下文
WeixinContext
- 所有单个用户的上下文
- 不是静态类,在同一个应用中创建多个全局上下文
- MessageHandler中有一个静态的WeiXinContext,所有任何MessageHandler的子类中都可以获取到WeixinContext,它是全局的、唯一的
- Dictionary<string, TM> MessageCollection,所有单个用户MessageContext的集合,不能操作
- MessageQueue<TM, TRequest, TResponse>,所有单个用户MessageContext的队列
消息去重
去重设置一
messageHandler.OmitRepeatedMessage = false;
去重设置二
public CustomMessageHandler(Stream inputStream, PostModel postModelk, int maxRecourdCOunt = 0) : base(inputStream, postModel, maxRecourdCount)
{
base.OmitRepeatedMessageFunc = requestMessage => {
var textRequestMessage = requestMessage as RquestMessageText;
if(textRequuestMessage != null && textRequestMessage.Content == "")
{
return false;
}
}
}
消息加密
MessageHandler
考虑了加密情况。