.NET开发微信公众号:消息处理实例

.NET开发微信公众号:消息处理实例

一.前言

微信公众平台的消息处理还是比较完善的,有最基本的文本消息,到图文消息,到图片消息,语音消息,视频消息,音乐消息其基本原理都是一样的,只不过所post的xml数据有所差别,在处理消息之前,我们要认真阅读,官方给我们的文档:http://mp.weixin.qq.com/wiki/14/89b871b5466b19b3efa4ada8e577d45e.html。首先我们从最基本的文本消息处理开始。

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[你好]]></Content>
</xml>

我们可以看到这是消息处理的一个最基本的模式,有发送者,接受者,创建时间,类型,内容等等。

首先我们来创建一个消息处理的类,这个类用来捕获,所有的消息请求,根据不同的消息请求类型来处理不同的消息回复。

public class WeiXinService
 {
  /// <summary>
  /// TOKEN
  /// </summary>
  private const string TOKEN = "finder";
  /// <summary>
  /// 签名
  /// </summary>
  private const string SIGNATURE = "signature";
  /// <summary>
  /// 时间戳
  /// </summary>
  private const string TIMESTAMP = "timestamp";
  /// <summary>
  /// 随机数
  /// </summary>
  private const string NONCE = "nonce";
  /// <summary>
  /// 随机字符串
  /// </summary>
  private const string ECHOSTR = "echostr";
  /// <summary>
  /// 
  /// </summary>
  private HttpRequest Request { get; set; }
  /// <summary>
  /// 构造函数
  /// </summary>
  /// <param name="request"></param>
  public WeiXinService(HttpRequest request)
  {
   this.Request = request;
  }
  /// <summary>
  /// 处理请求,产生响应
  /// </summary>
  /// <returns></returns>
  public string Response()
  {
   string method = Request.HttpMethod.ToUpper();
   //验证签名
   if (method == "GET")
   {
    if (CheckSignature())
    {
     return Request.QueryString[ECHOSTR];
    }
    else
    {
     return "error";
    }
   }

   //处理消息
   if (method == "POST")
   {
    return ResponseMsg();
   }
   else
   {
    return "无法处理";
   }
  }

  /// <summary>
  /// 处理请求
  /// </summary>
  /// <returns></returns>
  private string ResponseMsg()
  {
   string requestXml = CommonWeiXin.ReadRequest(this.Request);
   IHandler handler = HandlerFactory.CreateHandler(requestXml);
  
   if (handler != null)
   {
    return handler.HandleRequest();
   }

   return string.Empty;
  }
  /// <summary>
  /// 检查签名
  /// </summary>
  /// <param name="request"></param>
  /// <returns></returns>
  private bool CheckSignature()
  {
   string signature = Request.QueryString[SIGNATURE];
   string timestamp = Request.QueryString[TIMESTAMP];
   string nonce = Request.QueryString[NONCE];

   List<string> list = new List<string>();
   list.Add(TOKEN);
   list.Add(timestamp);
   list.Add(nonce);
   //排序
   list.Sort();
   //拼串
   string input = string.Empty;
   foreach (var item in list)
   {
    input += item;
   }
   //加密
   string new_signature = SecurityUtility.SHA1Encrypt(input);
   //验证
   if (new_signature == signature)
   {
    return true;
   }
   else
   {
    return false;
   }
  }
 }

在来看看我们的首先是如何捕获消息的。首页Default.ashx的代码如下

  public void ProcessRequest(HttpContext context)
  {
   context.Response.ContentType = "text/html";
   

   string postString = string.Empty;
   if (HttpContext.Current.Request.HttpMethod.ToUpper() == "POST")
   {
    //由微信服务接收请求,具体处理请求
    WeiXinService wxService = new WeiXinService(context.Request);
    string responseMsg = wxService.Response();
    context.Response.Clear();
    context.Response.Charset = "UTF-8";
    context.Response.Write(responseMsg);
    context.Response.End();
   }
   else
   {
    string token = "wei2414201";
    if (string.IsNullOrEmpty(token))
    {
     return;
    }

    string echoString = HttpContext.Current.Request.QueryString["echoStr"];
    string signature = HttpContext.Current.Request.QueryString["signature"];
    string timestamp = HttpContext.Current.Request.QueryString["timestamp"];
    string nonce = HttpContext.Current.Request.QueryString["nonce"];

    if (!string.IsNullOrEmpty(echoString))
    {
     HttpContext.Current.Response.Write(echoString);
     HttpContext.Current.Response.End();
    }
   }


  }

从上面的代码中我们可以看到WeiXinService.cs类中的消息相应至关重要。

  /// <summary>
  /// 处理请求
  /// </summary>
  /// <returns></returns>
  private string ResponseMsg()
  {
   string requestXml = CommonWeiXin.ReadRequest(this.Request);
   IHandler handler = HandlerFactory.CreateHandler(requestXml);
  
   if (handler != null)
   {
    return handler.HandleRequest();
   }

   return string.Empty;
  }

IHandler是一个消息处理接口,其下面有EventHandler,TextHandler处理类实现这个接口。代码如下

 /// <summary>
 /// 处理接口
 /// </summary>
 public interface IHandler
 {
  /// <summary>
  /// 处理请求
  /// </summary>
  /// <returns></returns>
  string HandleRequest();
 }

EventHandler

class EventHandler : IHandler
 {
  /// <summary>
  /// 请求的xml
  /// </summary>
  private string RequestXml { get; set; }
  /// <summary>
  /// 构造函数
  /// </summary>
  /// <param name="requestXml"></param>
  public EventHandler(string requestXml)
  {
   this.RequestXml = requestXml;
  }
  /// <summary>
  /// 处理请求
  /// </summary>
  /// <returns></returns>
  public string HandleRequest()
  {
   string response = string.Empty;
   EventMessage em = EventMessage.LoadFromXml(RequestXml);
   if (em.Event.Equals("subscribe", StringComparison.OrdinalIgnoreCase))//用来判断是不是首次关注
   {


    PicTextMessage tm = new PicTextMessage();//我自己创建的一个图文消息处理类
    tm.ToUserName = em.FromUserName;
    tm.FromUserName = em.ToUserName;
    tm.CreateTime = CommonWeiXin.GetNowTime();
    response = tm.GenerateContent();

   }

   return response;
  }
 }

TextHandler

 /// <summary>
 /// 文本信息处理类
 /// </summary>
 public class TextHandler : IHandler
 {
  string openid { get; set; }
  string access_token { get; set; }

  /// <summary>
  /// 请求的XML
  /// </summary>
  private string RequestXml { get; set; }
  /// <summary>
  /// 构造函数
  /// </summary>
  /// <param name="requestXml">请求的xml</param>
  public TextHandler(string requestXml)
  {
   this.RequestXml = requestXml;
  }
  /// <summary>
  /// 处理请求
  /// </summary>
  /// <returns></returns>
  public string HandleRequest()
  {
   string response = string.Empty;
   TextMessage tm = TextMessage.LoadFromXml(RequestXml);
   string content = tm.Content.Trim();
   if (string.IsNullOrEmpty(content))
   {
    response = "您什么都没输入,没法帮您埃";
   }
   else
   {
     string username = System.Configuration.ConfigurationManager.AppSettings["weixinid"].ToString();
     AccessToken token = AccessToken.Get(username);
     access_token = token.access_token;
     openid = tm.FromUserName;
     response = HandleOther(content);
    
   }
   tm.Content = response;
   //进行发送者、接收者转换
   string temp = tm.ToUserName;
   tm.ToUserName = tm.FromUserName;
   tm.FromUserName = temp;
   response = tm.GenerateContent();
   return response;
  }
  /// <summary>
  /// 处理其他消息
  /// </summary>
  /// <param name="tm"></param>
  /// <returns></returns>
  private string HandleOther(string requestContent)
  {
   string response = string.Empty;
   if (requestContent.Contains("你好") || requestContent.Contains("您好"))
   {
    response = "您也好~";
   }else if (requestContent.Contains("openid") || requestContent.Contains("id") || requestContent.Contains("ID"))//用来匹配用户输入的关键字
   {
    response = "你的Openid: "+openid;
   }
   else if (requestContent.Contains("token") || requestContent.Contains("access_token"))
   {
    response = "你的access_token: " + access_token;
   }else 
   {
    response = "试试其他关键字吧。";
   }
   return response;
  }
 }

HandlerFactory

 /// <summary>
 /// 处理器工厂类
 /// </summary>
 public class HandlerFactory
 {
  /// <summary>
  /// 创建处理器
  /// </summary>
  /// <param name="requestXml">请求的xml</param>
  /// <returns>IHandler对象</returns>
  public static IHandler CreateHandler(string requestXml)
  {
   IHandler handler = null;
   if (!string.IsNullOrEmpty(requestXml))
   {
    //解析数据
    XmlDocument doc = new System.Xml.XmlDocument();
    doc.LoadXml(requestXml);
    XmlNode node = doc.SelectSingleNode("/xml/MsgType");
    if (node != null)
    {
     XmlCDataSection section = node.FirstChild as XmlCDataSection;
     if (section != null)
     {
      string msgType = section.Value;

      switch (msgType)
      {
       case "text":
        handler = new TextHandler(requestXml);
        break;
       case "event":
        handler = new EventHandler(requestXml);
        break;
      }
     }
    }
   }

   return handler;
  }
 }

在这里基本的一些类已经完成了,现在我们来完成,关注我们的微信公众号,我们就发送一条图文消息,同时输入我们的一些关键字,返回一些消息,比如输入id返回用户的openid等等。

二.PicTextMessage

public class PicTextMessage : Message
 {
  /// <summary>
  /// 模板静态字段
  /// </summary>
  private static string m_Template;

  /// <summary>
  /// 默认构造函数
  /// </summary>
  public PicTextMessage()
  {
   this.MsgType = "news";
  }
  /// <summary>
  /// 从xml数据加载文本消息
  /// </summary>
  /// <param name="xml"></param>
  public static PicTextMessage LoadFromXml(string xml)
  {
   PicTextMessage tm = null;
   if (!string.IsNullOrEmpty(xml))
   {
    XElement element = XElement.Parse(xml);
    if (element != null)
    {
     tm = new PicTextMessage();
     tm.FromUserName = element.Element(CommonWeiXin.FROM_USERNAME).Value;
     tm.ToUserName = element.Element(CommonWeiXin.TO_USERNAME).Value;
     tm.CreateTime = element.Element(CommonWeiXin.CREATE_TIME).Value;
    }
   }

   return tm;
  }
  /// <summary>
  /// 模板
  /// </summary>
  public override string Template
  {
   get
   {
    if (string.IsNullOrEmpty(m_Template))
    {
     LoadTemplate();
    }

    return m_Template;
   }
  }
  /// <summary>
  /// 生成内容
  /// </summary>
  /// <returns></returns>
  public override string GenerateContent()
  {
   this.CreateTime = CommonWeiXin.GetNowTime();
   string str= string.Format(this.Template, this.ToUserName, this.FromUserName, this.CreateTime);
   return str;
  }


  /// <summary>
  /// 加载模板
  /// </summary>
  private static void LoadTemplate()
  {
   m_Template= @"<xml>
       <ToUserName><![CDATA[{0}]]></ToUserName>
       <FromUserName><![CDATA[{1}]]></FromUserName>
       <CreateTime>{2}</CreateTime>
       <MsgType><![CDATA[news]]></MsgType>
       <ArticleCount>1</ArticleCount>
       <Articles>
        <item>
        <Title><![CDATA[有位停车欢迎你!]]></Title> 
        <Description><![CDATA[如有问题请致电400-6238-136或直接在微信留言,我们将第一时间为您服务!]]></Description>
        <PicUrl><![CDATA[http://www.baidu.com/youwei.jpg]]></PicUrl>
        <Url><![CDATA[http://www.baidu.com]]></Url>
        </item>
       </Articles>
      </xml> ";
  }
 }

最后我们的效果如下所示;

.NET开发微信公众号:消息处理实例.NET开发微信公众号:消息处理实例

以上所述就是本文的全部内容了,希望大家能够喜欢