分类: 其他平台
2017-12-19 17:21:48
【摘要】
进行微信公众号开发时,微信消息处理是比较重要的一块内容,但是微信接**互的数据结构比较多变。传统做法是使用xpath对节点进行判断和解析,代码不易维护。本文介绍使用xml序列化/反序列化的方式将微信的数据结构映射为.Net中的类并进行处理。
【正文】
微信接收到的消息包括普通消息和事件推送消息两类。消息的数据结构类似:
查看相应文档,消息体中都包含ToUserName、FromUserName、MsgType三个类型,可以通过MsgType来区分具体的消息类型。因此可以通过识别MsgType的消息值,使用工厂方法来解析出具体的微信消息。
1、对内置的Xml序列化/反序列化类进行初步封装
反序列化类:
public static T XmlDeserialize
{
if (string.IsNullOrEmpty(s))
throw new ArgumentNullException("s");
if (encoding == null)
throw new ArgumentNullException("encoding");
XmlSerializer mySerializer = new XmlSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream(encoding.GetBytes(s)))
{
using (StreamReader sr = new StreamReader(ms, encoding))
{
return (T)mySerializer.Deserialize(sr);
}
}
}
序列化类:
public static string XmlSerialize(object o, Encoding encoding)
{
using (MemoryStream stream = new MemoryStream())
{
XmlSerializeInternal(stream, o, encoding);
stream.Position = 0;
using (StreamReader reader = new StreamReader(stream, encoding))
{
return reader.ReadToEnd();
}
}
}
private static void XmlSerializeInternal(Stream stream, object o, Encoding encoding)
{
if (o == null)
throw new ArgumentNullException("o");
if (encoding == null)
throw new ArgumentNullException("encoding");
XmlSerializer serializer = new XmlSerializer(o.GetType());
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.NewLineChars = "\r\n";
settings.Encoding = encoding;
settings.IndentChars = " ";
settings.OmitXmlDeclaration = true;
using (XmlWriter writer = XmlWriter.Create(stream, settings))
{
// 强制指定命名空间,覆盖默认的命名空间
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
serializer.Serialize(writer, o, namespaces);
writer.Close();
}
}
在序列化的封装中,虽然不影响xml数据结构的正确性,但为保持和微信数据结构的完全一致,去掉xml默认的命名空间。
2、定义各类微信消息的基类和默认处理方法
[XmlRoot("xml")]
public class MsgRoot
{
public string ToUserName { get; set; }
public string FromUserName { get; set; }
public string CreateTime { get; set; }
public virtual string MsgType { get; set; }
public virtual string Handle()
{
return "";
}
}
3、为不同的消息定义各个实体类(以文本、图片、语音为例):
文本消息:
[XmlRoot("xml")]
public class Text : MsgRoot
{
public string Content { get; set; }
public string MsgId { get; set; }
}
图片消息:
[XmlRoot("xml")]
public class Image : MsgRoot
{
public string PicUrl { get; set; }
public string MediaId { get; set;}
public string MsgId { get; set; }
}
语音消息:
[XmlRoot("xml")]
public class Voice : MsgRoot
{
public string Format { get; set; }
public string MediaId { get; set; }
public string MsgId { get; set; }
public string Recognition { get; set; }
}
3、定义工厂方法反序列化接收到的微信消息
public class WechatReveiveMsgBuildFactory
{
public static MsgRoot CreateReiceiveMsg(string xml)
{
XmlDocument xmlParse = new XmlDocument();
xmlParse.LoadXml(xml);
var eventType = xmlParse.SelectSingleNode("xml/MsgType");
if(eventType == null)
{
return null;
}
switch(eventType.InnerText.ToLower()){
case "event":
return XmlHelper.XmlDeserialize
case "text":
return XmlHelper.XmlDeserialize
case "image":
return XmlHelper.XmlDeserialize
case "voice":
return XmlHelper.XmlDeserialize
case "video":
return XmlHelper.XmlDeserialize
case "shortvideo":
return XmlHelper.XmlDeserialize
case "location":
return XmlHelper.XmlDeserialize
case "link":
return XmlHelper.XmlDeserialize
default:
return XmlHelper.XmlDeserialize
}
}
}
4、在具体的消息结构中重写Handle方法实现具体的业务逻辑
微信消息相关文档请查看: