一、前言
特别不喜欢麻烦的一个人,最近碰到了微信开发。下载下来了一些其他人写的微信开发“框架”,但是被恶心到了,实现的太臃肿啦。
最不喜欢的就是把微信返回的xml消息在组装成实体类,所以会比较臃肿,现在都提倡轻量级,所以有什么办法可以避免大量实体类的存在呢。
当然,还有包装的比较繁杂,看完官方API后,再看"框架",让人感觉一头雾水,不够清晰、明了。
二、我的实现思路
我的微信SDK(不敢自称框架),最重要的实现2个目标:
1.轻量级,就是要摒弃实体类,尽量少的申明Entity,减少SDK的体量;
2.简单、明了,就是SDK类的划分和官方API保持一致,让人一看就懂你的用意。
用户发送请是首先POST到微信服务器的,然后微信服务器在POST到我的服务器,这个接受的消息是xml,我猜测为什么是xml,而不是更轻量级的json,是为了更好的兼容性,毕竟xml更通用一些(说错了,请指出来)。而我们主动调用微信的一些API时,它返回的是json格式,我靠,要死啊,高大上啊。你们的副总裁张小龙不知道这事吗?好吧,这样其实也可以的。
其实,调用微信的工作原理很简单,没有必要上来就框架什么的,我相信是个合格的程序员都能做出来。
我们的服务器只需要一个GET,和一个POST就可以和微信通信了,从这一点来看,设计的还是比较人性化的,赞一个。GET用于接通微信服务的校验,验证;POST用于接收微信服务器过来的消息,然后将Response组装好返回即可。
三、上代码
好了,废话不多说了。
由于微信服务器Post给我们的是xml消息,返回的是json,所以需要互转。这样就存在3种类型的format,这也是大量的框架定义实体类导致框架不够轻量级的的原因之所在。
实现第一个目标,我主要用到了.net Framework4.0的Dynamic特性,和一个将xml字符串自动转换成Dynamic Object的DynamicXml.cs类,还有一个将json字符串自动转换成Dynamic Object的DynamicJson.cs类。
苦苦寻觅,终于让我找到了我想要的。
1.以下是DynamicXml.cs类,文件头有原作者的版权信息。
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*--------------------------------------------------------------------------
* https://www.captechconsulting.com/blog/kevin-hazzard/fluent-xml-parsing-using-cs-dynamic-type-part-1
* 博客园网友 夜の魔王 友情借用此代码,用于微信开发。
* http://www.cnblogs.com/deepleo/*--------------------------------------------------------------------------*/using System;using System.Collections.Generic;using System.Linq;using System.Dynamic;using System.Xml.Linq;using System.Collections;public class DynamicXml : DynamicObject, IEnumerable
{ private readonly List<XElement> _elements; public DynamicXml(string text)
{ var doc = XDocument.Parse(text);
_elements = new List<XElement> { doc.Root };
} protected DynamicXml(XElement element)
{
_elements = new List<XElement> { element };
} protected DynamicXml(IEnumerable<XElement> elements)
{
_elements = new List<XElement>(elements);
} public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null; if (binder.Name == "Value")
result = _elements[0].Value; else if (binder.Name == "Count")
result = _elements.Count; else
{ var attr = _elements[0].Attribute(XName.Get(binder.Name)); if (attr != null)
result = attr; else
{ var items = _elements.Descendants(XName.Get(binder.Name)); if (items == null || items.Count() == 0) return false;
result = new DynamicXml(items);
}
} return true;
} public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{ int ndx = (int)indexes[0];
result = new DynamicXml(_elements[ndx]); return true;
} public IEnumerator GetEnumerator()
{ foreach (var element in _elements) yield return new DynamicXml(element);
}
}
登录后复制
View Code
这个代码我也没仔细看,反正能用,没出过差错。
2.以下是DynamicJson.cs类,文件头有原作者的版权信息
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*--------------------------------------------------------------------------
* DynamicJson
* ver 1.2.0.0 (May. 21th, 2010)
*
* created and maintained by neuecc <ils@neue.cc>
* licensed under Microsoft Public License(Ms-PL)
* http://neue.cc/* http://dynamicjson.codeplex.com/
* 博客园网友 夜の魔王 友情借用此代码,用于微信开发。
* http://www.cnblogs.com/deepleo/*--------------------------------------------------------------------------*/using System;using System.Collections;using System.Collections.Generic;using System.Diagnostics;using System.Dynamic;using System.IO;using System.Linq;using System.Reflection;using System.Runtime.Serialization.Json;using System.Text;using System.Xml;using System.Xml.Linq;namespace Codeplex.Data
{ public class DynamicJson : DynamicObject
{ private enum JsonType
{
@string, number, boolean, @object, array, @null
} // public static methods
/// <summary>from JsonSring to DynamicJson</summary>
public static dynamic Parse(string json)
{ return Parse(json, Encoding.Unicode);
} /// <summary>from JsonSring to DynamicJson</summary>
public static dynamic Parse(string json, Encoding encoding)
{ using (var reader = JsonReaderWriterFactory.CreateJsonReader(encoding.GetBytes(json), XmlDictionaryReaderQuotas.Max))
{ return ToValue(XElement.Load(reader));
}
} /// <summary>from JsonSringStream to DynamicJson</summary>
public static dynamic Parse(Stream stream)
{ using (var reader = JsonReaderWriterFactory.CreateJsonReader(stream, XmlDictionaryReaderQuotas.Max))
{ return ToValue(XElement.Load(reader));
}
} /// <summary>from JsonSringStream to DynamicJson</summary>
public static dynamic Parse(Stream stream, Encoding encoding)
{ using (var reader = JsonReaderWriterFactory.CreateJsonReader(stream, encoding, XmlDictionaryReaderQuotas.Max, _ => { }))
{ return ToValue(XElement.Load(reader));
}
} /// <summary>create JsonSring from primitive or IEnumerable or Object({public property name:property value})</summary>
public static string Serialize(object obj)
{ return CreateJsonString(new XStreamingElement("root", CreateTypeAttr(GetJsonType(obj)), CreateJsonNode(obj)));
} // private static methods
private static dynamic ToValue(XElement element)
{ var type = (JsonType)Enum.Parse(typeof(JsonType), element.Attribute("type").Value); switch (type)
{ case JsonType.boolean: return (bool)element; case JsonType.number: return (double)element; case JsonType.@string: return (string)element; case JsonType.@object: case JsonType.array: return new DynamicJson(element, type); case JsonType.@null: default: return null;
}
} private static JsonType GetJsonType(object obj)
{ if (obj == null) return JsonType.@null; switch (Type.GetTypeCode(obj.GetType()))
{ case TypeCode.Boolean: return JsonType.boolean; case TypeCode.String: case TypeCode.Char: case TypeCode.DateTime: return JsonType.@string; case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: case TypeCode.SByte: case TypeCode.Byte: return JsonType.number; case TypeCode.Object: return (obj is IEnumerable) ? JsonType.array : JsonType.@object; case TypeCode.DBNull: case TypeCode.Empty: default: return JsonType.@null;
}
} private static XAttribute CreateTypeAttr(JsonType type)
{ return new XAttribute("type", type.ToString());
} private static object CreateJsonNode(object obj)
{ var type = GetJsonType(obj); switch (type)
{ case JsonType.@string: case JsonType.number: return obj; case JsonType.boolean: return obj.ToString().ToLower(); case JsonType.@object: return CreateXObject(obj); case JsonType.array: return CreateXArray(obj as IEnumerable); case JsonType.@null: default: return null;
}
} private static IEnumerable<XStreamingElement> CreateXArray<T>(T obj) where T : IEnumerable
{ return obj.Cast<object>()
.Select(o => new XStreamingElement("item", CreateTypeAttr(GetJsonType(o)), CreateJsonNode(o)));
} private static IEnumerable<XStreamingElement> CreateXObject(object obj)
{ return obj.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Select(pi => new { Name = pi.Name, Value = pi.GetValue(obj, null) })
.Select(a => new XStreamingElement(a.Name, CreateTypeAttr(GetJsonType(a.Value)), CreateJsonNode(a.Value)));
} private static string CreateJsonString(XStreamingElement element)
{ using (var ms = new MemoryStream()) using (var writer = JsonReaderWriterFactory.CreateJsonWriter(ms, Encoding.Unicode))
{
element.WriteTo(writer);
writer.Flush(); return Encoding.Unicode.GetString(ms.ToArray());
}
} // dynamic structure represents JavaScript Object/Array
readonly XElement xml; readonly JsonType jsonType; /// <summary>create blank JSObject</summary>
public DynamicJson()
{
xml = new XElement("root", CreateTypeAttr(JsonType.@object));
jsonType = JsonType.@object;
} private DynamicJson(XElement element, JsonType type)
{
Debug.Assert(type == JsonType.array || type == JsonType.@object);
xml = element;
jsonType = type;
} public bool IsObject { get { return jsonType == JsonType.@object; } } public bool IsArray { get { return jsonType == JsonType.array; } } /// <summary>has property or not</summary>
public bool IsDefined(string name)
{ return IsObject && (xml.Element(name) != null);
} /// <summary>has property or not</summary>
public bool IsDefined(int index)
{ return IsArray && (xml.Elements().ElementAtOrDefault(index) != null);
} /// <summary>delete property</summary>
public bool Delete(string name)
{ var elem = xml.Element(name); if (elem != null)
{
elem.Remove(); return true;
} else return false;
} /// <summary>delete property</summary>
public bool Delete(int index)
{ var elem = xml.Elements().ElementAtOrDefault(index); if (elem != null)
{
elem.Remove(); return true;
} else return false;
} /// <summary>mapping to Array or Class by Public PropertyName</summary>
public T Deserialize<T>()
{ return (T)Deserialize(typeof(T));
} private object Deserialize(Type type)
{ return (IsArray) ? DeserializeArray(type) : DeserializeObject(type);
} private dynamic DeserializeValue(XElement element, Type elementType)
{ var value = ToValue(element); if (value is DynamicJson)
{
value = ((DynamicJson)value).Deserialize(elementType);
} return Convert.ChangeType(value, elementType);
} private object DeserializeObject(Type targetType)
{ var result = Activator.CreateInstance(targetType); var dict = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanWrite)
.ToDictionary(pi => pi.Name, pi => pi); foreach (var item in xml.Elements())
{
PropertyInfo propertyInfo; if (!dict.TryGetValue(item.Name.LocalName, out propertyInfo)) continue; var value = DeserializeValue(item, propertyInfo.PropertyType);
propertyInfo.SetValue(result, value, null);
} return result;
} private object DeserializeArray(Type targetType)
{ if (targetType.IsArray) // Foo[] { var elemType = targetType.GetElementType();
dynamic array = Array.CreateInstance(elemType, xml.Elements().Count()); var index = 0; foreach (var item in xml.Elements())
{
array[index++] = DeserializeValue(item, elemType);
} return array;
} else // List<Foo> { var elemType = targetType.GetGenericArguments()[0];
dynamic list = Activator.CreateInstance(targetType); foreach (var item in xml.Elements())
{
list.Add(DeserializeValue(item, elemType));
} return list;
}
} // Delete
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
{
result = (IsArray) ? Delete((int)args[0])
: Delete((string)args[0]); return true;
} // IsDefined, if has args then TryGetMember
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{ if (args.Length > 0)
{
result = null; return false;
}
result = IsDefined(binder.Name); return true;
} // Deserialize or foreach(IEnumerable)
public override bool TryConvert(ConvertBinder binder, out object result)
{ if (binder.Type == typeof(IEnumerable) || binder.Type == typeof(object[]))
{ var ie = (IsArray) ? xml.Elements().Select(x => ToValue(x))
: xml.Elements().Select(x => (dynamic)new KeyValuePair<string, object>(x.Name.LocalName, ToValue(x)));
result = (binder.Type == typeof(object[])) ? ie.ToArray() : ie;
} else
{
result = Deserialize(binder.Type);
} return true;
} private bool TryGet(XElement element, out object result)
{ if (element == null)
{
result = null; return false;
}
result = ToValue(element); return true;
} public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{ return (IsArray) ? TryGet(xml.Elements().ElementAtOrDefault((int)indexes[0]), out result)
: TryGet(xml.Element((string)indexes[0]), out result);
} public override bool TryGetMember(GetMemberBinder binder, out object result)
{ return (IsArray) ? TryGet(xml.Elements().ElementAtOrDefault(int.Parse(binder.Name)), out result)
: TryGet(xml.Element(binder.Name), out result);
} private bool TrySet(string name, object value)
{ var type = GetJsonType(value); var element = xml.Element(name); if (element == null)
{
xml.Add(new XElement(name, CreateTypeAttr(type), CreateJsonNode(value)));
} else
{
element.Attribute("type").Value = type.ToString();
element.ReplaceNodes(CreateJsonNode(value));
} return true;
} private bool TrySet(int index, object value)
{ var type = GetJsonType(value); var e = xml.Elements().ElementAtOrDefault(index); if (e == null)
{
xml.Add(new XElement("item", CreateTypeAttr(type), CreateJsonNode(value)));
} else
{
e.Attribute("type").Value = type.ToString();
e.ReplaceNodes(CreateJsonNode(value));
} return true;
} public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
{ return (IsArray) ? TrySet((int)indexes[0], value)
: TrySet((string)indexes[0], value);
} public override bool TrySetMember(SetMemberBinder binder, object value)
{ return (IsArray) ? TrySet(int.Parse(binder.Name), value)
: TrySet(binder.Name, value);
} public override IEnumerable<string> GetDynamicMemberNames()
{ return (IsArray) ? xml.Elements().Select((x, i) => i.ToString())
: xml.Elements().Select(x => x.Name.LocalName);
} /// <summary>Serialize to JsonString</summary>
public override string ToString()
{ // <foo type="null"></foo> is can't serialize. replace to <foo type="null" />
foreach (var elem in xml.Descendants().Where(x => x.Attribute("type").Value == "null"))
{
elem.RemoveNodes();
} return CreateJsonString(new XStreamingElement("root", CreateTypeAttr(jsonType), xml.Elements()));
}
}
}
登录后复制
View Code
这个代码我也依旧没仔细看,反正也能用,没出过差错。
这个最核心的拦路虎解决了,后面的事情就顺理成章的进行啦。
3.基础支持API包装
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*--------------------------------------------------------------------------
* BasicAPI.cs
*Auth:deepleo
* Date:2013.12.31
* Email:2586662969@qq.com
*--------------------------------------------------------------------------*/using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net.Http;using Codeplex.Data;using System.IO;namespace Deepleo.Weixin.SDK
{ /// <summary>
/// 对应微信API的 "基础支持" /// </summary>
public class BasicAPI
{ /// <summary>
/// 检查签名是否正确: /// http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
/// </summary>
/// <param name="signature"></param>
/// <param name="timestamp"></param>
/// <param name="nonce"></param>
/// <param name="token">AccessToken</param>
/// <returns>
/// true: check signature success /// false: check failed, 非微信官方调用! /// </returns>
public static bool CheckSignature(string signature, string timestamp, string nonce, string token, out string ent)
{ var arr = new[] { token, timestamp, nonce }.OrderBy(z => z).ToArray(); var arrString = string.Join("", arr); var sha1 = System.Security.Cryptography.SHA1.Create(); var sha1Arr = sha1.ComputeHash(Encoding.UTF8.GetBytes(arrString));
StringBuilder enText = new StringBuilder(); foreach (var b in sha1Arr)
{
enText.AppendFormat("{0:x2}", b);
}
ent = enText.ToString(); return signature == enText.ToString();
} /// <summary>
/// 获取AccessToken /// http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token
/// </summary>
/// <param name="grant_type"></param>
/// <param name="appid"></param>
/// <param name="secrect"></param>
/// <returns>access_toke</returns>
public static dynamic GetAccessToken( string appid, string secrect)
{ var url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type={0}&appid={1}&secret={2}", "client_credential", appid, secrect); var client = new HttpClient(); var result = client.GetAsync(url).Result; if (!result.IsSuccessStatusCode) return string.Empty; var token = DynamicJson.Parse(result.Content.ReadAsStringAsync().Result); return token;
} /// <summary>
/// 上传多媒体文件 /// http://mp.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD%E5%A4%9A%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6
/// 1.上传的媒体文件限制: ///图片(image) : 1MB,支持JPG格式 ///语音(voice):1MB,播放长度不超过60s,支持MP4格式 ///视频(video):10MB,支持MP4格式 ///缩略图(thumb):64KB,支持JPG格式 ///2.媒体文件在后台保存时间为3天,即3天后media_id失效 /// </summary>
/// <param name="token"></param>
/// <param name="type"></param>
/// <param name="file"></param>
/// <returns>media_id</returns>
public static string UploadMedia(string token, string type, string file)
{ var url = string.Format("http://api.weixin.qq.com/cgi-bin/media/upload?access_token={0}&type={1}&filename={2}", token, type, Path.GetFileName(file)); var client = new HttpClient(); var result = client.PostAsync(url, new StreamContent(new FileStream(file, FileMode.Open, FileAccess.Read))); if (!result.Result.IsSuccessStatusCode) return string.Empty; var media = DynamicJson.Parse(result.Result.Content.ReadAsStringAsync().Result); return media.media_id;
}
}
}
登录后复制
View Code
4.发送消息包装
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*--------------------------------------------------------------------------
* SendMessageAPI.cs
*Auth:deepleo
* Date:2013.12.31
* Email:2586662969@qq.com
*--------------------------------------------------------------------------*/using System;using System.Collections.Generic;using System.Linq;using System.Text;using Codeplex.Data;using System.Net;using System.Net.Http;namespace Deepleo.Weixin.SDK
{ /// <summary>
/// 对应微信API的 "发送消息” /// </summary>
public class SendMessageAPI
{ /// <summary>
/// 被动回复消息 /// </summary>
/// <param name="message">微信服务器推送的消息</param>
/// <param name="executor">用户自定义的消息执行者</param>
/// <returns></returns>
public static string Relay(WeixinMessage message, IWeixinExecutor executor)
{ return executor.Execute(message);
} /// <summary>
/// 主动发送客服消息 /// http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF
/// 当用户主动发消息给公众号的时候 /// 开发者在一段时间内(目前为24小时)可以调用客服消息接口,在24小时内不限制发送次数。 /// </summary>
/// <param name="token"></param>
/// <param name="msg">json格式的消息,具体格式请参考微信官方API</param>
/// <returns></returns>
public static bool Send(string token, string msg)
{ var client = new HttpClient(); var task = client.PostAsync(string.Format("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={0}", token), new StringContent(msg)).Result; return task.IsSuccessStatusCode;
}
}
}
登录后复制
View Code
5.其他代码就不一一贴出来了。可以在文章最后自行下载完整代码查阅。
6.处理与微信服务器通信的WeixinController.cs,WeixinExecutor.cs
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Text;using System.Web;using System.Web.Mvc;using System.Xml.Linq;using Deepleo.Weixin.SDK;using Deepleo.NewTon.Web.Services;using System.Xml;using Deepleo.NewTon.Framework.Services.Admin;using Deepleo.Log;namespace Deepleo.NewTon.Web.Controllers
{ public class WeixinController : Controller
{ public WeixinController()
{
} /// <summary>
/// 微信后台验证地址(使用Get),微信后台的“接口配置信息”的Url /// </summary> [HttpGet]
[ActionName("Index")] public ActionResult Get(string signature, string timestamp, string nonce, string echostr)
{ var token = new SettingsService().Get().Token; if (string.IsNullOrEmpty(_token)) return Content("请先设置Token!"); var ent = ""; if (!BasicAPI.CheckSignature(signature, timestamp, nonce, _token, out ent))
{ new WeixinLogService().Create(new Framework.Entities.WeixinLog("get(failed)", string.Format("(get weixin)signature:{0},timestamp:{1},nonce:{2},echostr:{3},ent:{4},token:{5}",
signature, timestamp, nonce, echostr, ent, _token))); return Content("参数错误!");
}
return Content(echostr); //返回随机字符串则表示验证通过 } /// <summary>
/// 用户发送消息后,微信平台自动Post一个请求到这里,并等待响应XML。 /// </summary> [HttpPost]
[ActionName("Index")] public ActionResult Post(string signature, string timestamp, string nonce, string echostr)
{
WeixinMessage message = null; using (var streamReader = new StreamReader(Request.InputStream))
{
message = AcceptMessageAPI.Parse(streamReader.ReadToEnd());
} var response = new WeixinExecutor().Execute(message); return new ContentResult
{
Content = response,
ContentType = "text/xml",
ContentEncoding = System.Text.UTF8Encoding.UTF8
};
}
}
}
登录后复制
View Code
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/*--------------------------------------------------------------------------
* WeixinExecutor.cs
*Auth:deepleo
* Date:2013.12.31
* Email:2586662969@qq.com
*--------------------------------------------------------------------------*/using System;using System.Collections.Generic;using System.Linq;using System.Web;using Deepleo.Weixin.SDK;using System.Text;using System.Text.RegularExpressions;namespace Deepleo.Weixin
{ public class WeixinExecutor : IWeixinExecutor
{ public WeixinExecutor()
{
} public string Execute(WeixinMessage message)
{ var result = ""; string openId = message.Body.FromUserName.Value; var myUserName = message.Body.ToUserName.Value; switch (message.Type)
{ case WeixinMessageType.Text: string userMessage = message.Body.Content.Value;
result = RepayText(openId, myUserName, "欢迎使用"); break; case WeixinMessageType.Event: string eventType = message.Body.Event.Value.ToLower(); string eventKey = message.Body.EventKey.Value; switch (eventType)
{ case "subscribe":
result = RepayText(openId, myUserName, "欢迎订阅"); break; case "unsubscribe":
result = RepayText(openId, myUserName, "欢迎再来"); break; case "scan":
result = RepayText(openId, myUserName, "欢迎使用"); break; case "location"://用户进入应用时记录用户地理位置
#region location var lat = message.Body.Latitude.Value.ToString(); var lng = message.Body.Longitude.Value.ToString(); var pcn = message.Body.Precision.Value.ToString(); #endregion
break; case "click": switch (eventKey)//refer to: Recources/menu.json { case "myaccount": #region 我的账户
result = RepayText(openId, myUserName, "我的账户."); #endregion
break; default:
result = string.Format("<xml><ToUserName><![CDATA[{0}]]></ToUserName>" + "<FromUserName><![CDATA[{1}]]></FromUserName>" + "<CreateTime>{2}</CreateTime>" + "<MsgType><![CDATA[text]]></MsgType>" + "<Content><![CDATA[{3}]]></Content>" + "</xml>",
openId, myUserName, DateTime.Now.ToBinary(), "没有响应菜单事件"); break;
} break;
} break; default:
result = string.Format("<xml><ToUserName><![CDATA[{0}]]></ToUserName>" + "<FromUserName><![CDATA[{1}]]></FromUserName>" + "<CreateTime>{2}</CreateTime>" + "<MsgType><![CDATA[text]]></MsgType>" + "<Content><![CDATA[{3}]]></Content>" + "</xml>",
openId, myUserName, DateTime.Now.ToBinary(), string.Format("未处理消息类型:{0}", message.Type)); break;
} return result;
} private string RepayText(string toUserName, string fromUserName, string content)
{ return string.Format("<xml><ToUserName><![CDATA[{0}]]></ToUserName>" + "<FromUserName><![CDATA[{1}]]></FromUserName>" + "<CreateTime>{2}</CreateTime>" + "<MsgType><![CDATA[text]]></MsgType>" + "<Content><![CDATA[{3}]]></Content>" + "</xml>",
toUserName, fromUserName, DateTime.Now.ToBinary(), content);
} private string RepayNews(string toUserName, string fromUserName, List<WeixinNews> news)
{ var couponesBuilder = new StringBuilder();
couponesBuilder.Append(string.Format("<xml><ToUserName><![CDATA[{0}]]></ToUserName>" + "<FromUserName><![CDATA[{1}]]></FromUserName>" + "<CreateTime>{2}</CreateTime>" + "<MsgType><![CDATA[news]]></MsgType>" + "<ArticleCount>{3}</ArticleCount><Articles>",
toUserName, fromUserName,
DateTime.Now.ToBinary(),
news.Count
)); foreach (var c in news)
{
couponesBuilder.Append(string.Format("<item><Title><![CDATA[{0}]]></Title>" + "<Description><![CDATA[{1}]]></Description>" + "<PicUrl><![CDATA[{2}]]></PicUrl>" + "<Url><![CDATA[{3}]]></Url>" + "</item>",
c.Title, c.Description, c.PicUrl, c.Url
));
}
couponesBuilder.Append("</Articles></xml>"); return couponesBuilder.ToString();
}
} public class WeixinNews
{ public string Title { set; get; } public string Description { set; get; } public string PicUrl { set; get; } public string Url { set; get; }
}
}
登录后复制
以上就是分享一篇基于.NET的微信SDK的详细内容,更多请关注靠谱客其它相关文章!
最后
以上就是活力心情最近收集整理的关于分享一篇基于.NET的微信SDK的全部内容,更多相关分享一篇基于.NET内容请搜索靠谱客的其他文章。
发表评论 取消回复