1. Vorwort
Ich bin eine Person, die ?rger besonders nicht mag. Ich bin kürzlich auf WeChat-Entwicklung gesto?en. Ich habe einige WeChat-Entwicklungs-?Frameworks“ heruntergeladen, die von anderen Leuten geschrieben wurden, aber ich war angewidert, dass die Implementierung zu aufgebl?ht war.
Was mir am wenigsten gef?llt, ist das Zusammenstellen der von WeChat zurückgegebenen XML-Nachrichten in Entit?tsklassen. Heutzutage wird eine Aufbl?hung empfohlen. Gibt es also eine M?glichkeit, eine gro?e Menge zu vermeiden? Anzahl der Entit?tsklassen?
Natürlich ist die Verpackung relativ kompliziert. Nach dem Lesen der offiziellen API fühlen sich die Leute beim Betrachten des ?Frameworks“ verwirrt und nicht klar genug .
2. Meine Implementierungsideen
Mein WeChat SDK (ich wage es nicht, mich selbst als Framework zu bezeichnen), das Wichtigste ist, zwei Ziele zu erreichen:
1. Leichtgewicht bedeutet, auf Entit?tsklassen zu verzichten, Entit?ten so wenig wie m?glich zu deklarieren und die Gr??e des SDK zu reduzieren.
2. Einfach und klar, das hei?t, die Aufteilung der SDK-Klassen stimmt mit der offiziellen überein API, damit es auf einen Blick leicht zu erkennen ist. Ich verstehe Ihre Absicht.
Der Benutzer sendet eine Anfrage, indem er zuerst an den WeChat-Server postet und dann den WeChat-Server an meinen Server sendet Kompatibilit?t, XML ist schlie?lich universeller (wenn ich falsch liege, weisen Sie bitte darauf hin). Wenn wir einige APIs auf WeChat aktiv aufrufen, wird das JSON-Format zurückgegeben. Verdammt, es ist so beeindruckend. Wei? Ihr Vizepr?sident Zhang Xiaolong nichts davon? Nun, das ist tats?chlich m?glich.
Tats?chlich ist das Funktionsprinzip des WeChat-Aufrufs sehr einfach. Ich glaube, dass kein qualifizierter Programmierer dies tun kann.
Unser Server ben?tigt nur einen GET und einen POST, um mit WeChat zu kommunizieren. Unter diesem Gesichtspunkt gef?llt mir das Design. GET wird verwendet, um eine Verbindung zum WeChat-Dienst herzustellen, und POST wird verwendet, um Nachrichten vom WeChat-Server zu empfangen und dann die Antwort zusammenzustellen und zurückzugeben.
3. Laden Sie den Code hoch
Okay, kein Unsinn mehr.
Da der WeChat-Server Post uns eine XML-Nachricht sendet und JSON zurückgibt, muss diese aneinander übertragen werden. Auf diese Weise gibt es drei Arten von Formaten. Dies ist auch der Grund, warum das Framework aufgrund der gro?en Anzahl von Framework-definierten Entit?tsklassen nicht leichtgewichtig genug ist.
Um das erste Ziel zu erreichen, habe ich haupts?chlich die Dynamic-Funktion von .net Framework 4.0 und eine DynamicXml.cs-Klasse verwendet, die XML-Zeichenfolgen automatisch in ein dynamisches Objekt konvertiert, und ein DynamicJson.cs Klasse , die JSON-Strings automatisch in dynamische Objekte konvertiert.
Nach langer Suche habe ich endlich gefunden, was ich wollte.1. Das Folgende ist die DynamicXml.cs-Klasse, und der Dateikopf enth?lt die Copyright-Informationen des ursprünglichen Autors.
/*-------------------------------------------------------------------------- * https://www.captechconsulting.com/blog/kevin-hazzard/fluent-xml-parsing-using-cs-dynamic-type-part-1 * 博客園網(wǎng)友 夜の魔王 友情借用此代碼,用于微信開(kāi)發(fā)。 * 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); } }
Code anzeigen
Ich habe mir diesen Code nicht genau angesehen , Jedenfalls funktioniert es, keine Fehler.
2.Das Folgende ist die DynamicJson.cs-Klasse. Der Dateiheader enth?lt die Copyright-Informationen des ursprünglichen Autors
/*-------------------------------------------------------------------------- * 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/ * 博客園網(wǎng)友 夜の魔王 友情借用此代碼,用于微信開(kāi)發(fā)。 * 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())); } } }
Code anzeigen
Ich habe mir diesen Code noch nicht genau angeschaut, aber er funktioniert trotzdem ohne Fehler.
Sobald dieses Kernhindernis gel?st ist, wird der Rest von selbst ablaufen.
3. Grundlegende Unterstützung für API-Verpackung
/*-------------------------------------------------------------------------- * 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> /// 對(duì)應(yīng)微信API的 "基礎(chǔ)支持" /// </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, 非微信官方調(diào)用! /// </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格式 ///語(yǔ)音(voice):1MB,播放長(zhǎng)度不超過(guò)60s,支持MP4格式 ///視頻(video):10MB,支持MP4格式 ///縮略圖(thumb):64KB,支持JPG格式 ///2.媒體文件在后臺(tái)保存時(shí)間為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; } } }
Code anzeigen
4.發(fā)送消息包裝
/*-------------------------------------------------------------------------- * 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> /// 對(duì)應(yīng)微信API的 "發(fā)送消息” /// </summary> public class SendMessageAPI { /// <summary> /// 被動(dòng)回復(fù)消息 /// </summary> /// <param name="message">微信服務(wù)器推送的消息</param> /// <param name="executor">用戶(hù)自定義的消息執(zhí)行者</param> /// <returns></returns> public static string Relay(WeixinMessage message, IWeixinExecutor executor) { return executor.Execute(message); } /// <summary> /// 主動(dòng)發(fā)送客服消息 /// 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 /// 當(dāng)用戶(hù)主動(dòng)發(fā)消息給公眾號(hào)的時(shí)候 /// 開(kāi)發(fā)者在一段時(shí)間內(nèi)(目前為24小時(shí))可以調(diào)用客服消息接口,在24小時(shí)內(nèi)不限制發(fā)送次數(shù)。 /// </summary> /// <param name="token"></param> /// <param name="msg">json格式的消息,具體格式請(qǐng)參考微信官方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.其他代碼就不一一貼出來(lái)了??梢栽谖恼伦詈笞孕邢螺d完整代碼查閱。
6.處理與微信服務(wù)器通信的WeixinController.cs,WeixinExecutor.cs
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> /// 微信后臺(tái)驗(yàn)證地址(使用Get),微信后臺(tái)的“接口配置信息”的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("請(qǐng)先設(shè)置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("參數(shù)錯(cuò)誤!"); } return Content(echostr); //返回隨機(jī)字符串則表示驗(yàn)證通過(guò) } /// <summary> /// 用戶(hù)發(fā)送消息后,微信平臺(tái)自動(dòng)Post一個(gè)請(qǐng)求到這里,并等待響應(yīng)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
/*-------------------------------------------------------------------------- * 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, "歡迎再來(lái)"); break; case "scan": result = RepayText(openId, myUserName, "歡迎使用"); break; case "location"://用戶(hù)進(jìn)入應(yīng)用時(shí)記錄用戶(hù)地理位置 #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 我的賬戶(hù) result = RepayText(openId, myUserName, "我的賬戶(hù)."); #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(), "沒(méi)有響應(yīng)菜單事件"); 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("未處理消息類(lèi)型:{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; } } }
Das obige ist der detaillierte Inhalt vonTeilen Sie einen Artikel basierend auf dem .NET WeChat SDK. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Hei?e KI -Werkzeuge

Undress AI Tool
Ausziehbilder kostenlos

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem v?llig kostenlosen KI-Gesichtstausch-Tool aus!

Hei?er Artikel

Hei?e Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Das neue Windows 11 SDK für Build 22523 enthüllte, dass Microsoft einen neuen Unsch?rfeeffekt für Windows 11 entwickelt. Dieser Effekt wird Tabbed genannt und gilt zus?tzlich zu Acryl und Glimmer. Das neue DWMWA_SYSTEMBACKDROP_TYPE im 22523 SDK, die ?ffentliche Win32-API für Mica, Acrylic und ihre seltsame neue ?Tab“-Mischung: pic.twitter.com/dbsu7ZFiIi – It’s All Back (@StartIsBack) 15. Dezember 2021 Verfügbar in den folgenden SDKs Beispielanwendung

Beherrschen Sie die wesentlichen F?higkeiten für die Sekund?rentwicklung des Java Hikvision SDK. Einführung: Mit der rasanten Entwicklung der Informationstechnologie wurden Videoüberwachungssysteme in verschiedenen Bereichen weit verbreitet eingesetzt. Als führender inl?ndischer Anbieter von Videoüberwachungsl?sungen nehmen die Produkte und Technologien von Hikvision seit jeher eine wichtige Position auf dem Markt ein. Um den Anforderungen verschiedener Projekte gerecht zu werden, stellt Hikvision Entwicklern ein SDK zur Durchführung sekund?rer Entwicklungen zur Verfügung. In diesem Artikel werden einige wesentliche F?higkeiten zur Beherrschung der Sekund?rentwicklung des Java Hikvision SDK vorgestellt und entsprechende Codebeispiele beigefügt. 1. Hikvision verstehen

Der vollst?ndige Name von SDK lautet ?Software Development Kit“, was auf Chinesisch ?Software Development Kit“ bedeutet. Dabei handelt es sich um eine Reihe von Tools, die von Herstellern von Hardwareplattformen, Betriebssystemen (OS) oder Programmiersprachen bereitgestellt werden. SDKs unterstützen Softwareentwickler bei der Erstellung von Anwendungen für bestimmte Plattformen, Systeme oder Programmiersprachen. Ein Basis-SDK besteht normalerweise aus einem Compiler, Debugger und einer Anwendungsprogrammierschnittstelle (API), kann aber auch andere Inhalte enthalten, wie zum Beispiel: Dokumentation, Bibliotheken, Laufzeit-/Entwicklungsumgebung, Test-/Analysetools, Netzwerkprotokolle usw.

Dieser Artikel bietet eine detaillierte Installationsanleitung für das PHP Alipay SDK, um Entwicklern dabei zu helfen, die Installation des SDK in wenigen einfachen Schritten abzuschlie?en.

PHP ist eine Open-Source-Skriptsprache, die in der Webentwicklung und serverseitigen Programmierung, insbesondere in der WeChat-Entwicklung, weit verbreitet ist. Heutzutage beginnen immer mehr Unternehmen und Entwickler, PHP für die WeChat-Entwicklung zu verwenden, da es sich zu einer wirklich leicht zu erlernenden und benutzerfreundlichen Entwicklungssprache entwickelt hat. Bei der WeChat-Entwicklung sind die Nachrichtenverschlüsselung und -entschlüsselung ein sehr wichtiges Thema, da sie die Datensicherheit betreffen. Bei Nachrichten ohne Verschlüsselungs- und Entschlüsselungsmethoden k?nnen Hacker leicht an die Daten gelangen, was eine Bedrohung für Benutzer darstellt.

Das WindowsAppSDK ist eine Reihe von Tools und APIs, die Entwickler in ihren Windows-Anwendungen verwenden k?nnen, um ?konsistente“ Funktionalit?t auf einer Vielzahl von Ger?ten unter Windows 10 (Version 1809 und h?her) und Windows 11 bereitzustellen. Es ist wirklich wichtig zu verstehen, dass es bestehende Anwendungstypen wie .NET oder Windows SDK nicht ersetzt, sondern lediglich ein einheitliches API-Toolset bereitstellt, das zur Erg?nzung Ihrer vorhandenen Anwendungen verwendet werden kann. Heute hat Microsoft Version 1.2 des Windows App SDK mit vielen neuen Funktionen ver?ffentlicht. Das Highlight dieser Version k?nnten Drittentwickler sein

Installation und Verwendung des WeChat Mini-Programms PHPSDK Mit der rasanten Entwicklung des mobilen Internets ist das WeChat Mini-Programm für immer mehr Unternehmen zu einer neuen M?glichkeit geworden, Gesch?fte abzuwickeln und Produkte zu bewerben. Das WeChat Mini-Programm PHPSDK bietet Entwicklern praktische und schnelle Entwicklungstools, die die Entwicklungseffizienz erheblich verbessern k?nnen. In diesem Artikel wird die Installation und Verwendung des WeChat-Applets PHPSDK vorgestellt. 1. Installieren Sie SDK 1. Laden Sie die Projektdatei auf GitHub herunter. PHPSDK ist ein Open-Source-Projekt.

Das SDK unter Linux ist ein Ordner, der Tools und Ressourcen wie Compiler, Debugger, Bibliotheksdateien, Header-Dateien usw. enth?lt. SDK ist die Abkürzung für ?Software Development Kit“, was Software Development Kit bedeutet. Es handelt sich um eine integrierte Umgebung, die Entwicklern zum Entwickeln und Erstellen von Anwendungen bereitgestellt wird, insbesondere solchen, die auf dem Linux-Betriebssystem ausgeführt werden.
