首页 微信小程序 微信开发 分享一篇基于.NET的微信SDK

分享一篇基于.NET的微信SDK

Apr 27, 2017 pm 02:12 PM

一、前言

      特别不喜欢麻烦的一个人,最近碰到了微信开发。下载下来了一些其他人写的微信开发“框架”,但是被恶心到了,实现的太臃肿啦。

      最不喜欢的就是把微信返回的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类,文件头有原作者的版权信息。

/*--------------------------------------------------------------------------
 * 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类,文件头有原作者的版权信息

/*--------------------------------------------------------------------------
* 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&#39;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包装

/*--------------------------------------------------------------------------
* 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.发送消息包装

/*--------------------------------------------------------------------------
* 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

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

/*--------------------------------------------------------------------------
* 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的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

微软正在为 Windows 11 开发新的模糊效果 微软正在为 Windows 11 开发新的模糊效果 May 13, 2023 am 09:04 AM

用于build22523的新Windows11SDK透露,微软正在为Windows11开发新的模糊效果。该效果称为Tabbed,并且是对Acrylic和Mica的补充。22523SDK中的新DWMWA_SYSTEMBACKDROP_TYPE、云母、亚克力的公共Win32API及其奇怪的新“选项卡”混合:pic.twitter.com/dbsu7ZFiIi-一切都回来了(@StartIsBack)2021年12月15日可以在以下SDK的示例应用程序

掌握Java海康SDK二次开发的必备技巧 掌握Java海康SDK二次开发的必备技巧 Sep 06, 2023 am 08:10 AM

掌握Java海康SDK二次开发的必备技巧引言:随着信息技术的迅猛发展,视频监控系统在各个领域得到了广泛的应用。而作为国内领先的视频监控解决方案提供商,海康威视的产品和技术一直在市场中占据着重要的地位。为了满足不同项目的需求,海康威视提供了SDK供开发者进行二次开发。本文将介绍一些掌握Java海康SDK二次开发的必备技巧,并附上相应的代码示例。一、了解海康威视

Windows App SDK 1.2 现已上线,这是新功能 Windows App SDK 1.2 现已上线,这是新功能 May 12, 2023 pm 06:07 PM

WindowsAppSDK是一组工具和API,开发人员可以在其Windows应用程序中使用这些工具和API,以便在使用Windows10(版本1809及更高版本)和Windows11的各种设备上提供“一致”的功能。了解它确实很重要它不会取代现有的应用程序类型,例如.NET或WindowsSDK,它只是提供一个统一的API工具集,可以用来补充您现有的应用程序。今天,微软发布了具有许多新功能的WindowsAppSDK1.2版本。此版本的亮点可能是第三方开发人

sdk是什么 sdk是什么 Jan 06, 2023 pm 03:26 PM

sdk全称“Software Development Kit”,中文意思为“软件开发工具包”,是由硬件平台、操作系统(OS)或编程语言的制造商提供的一套工具。SDK可协助软件开发人员面向特定的平台、系统或编程语言创建应用。一个基本的SDK通常由编译器、调试器和应用编程接口(API)组成,但也可能包含其他内容,比如:文档、库、运行时/开发环境、测试/分析工具、网络协议等。

PHP微信开发:如何实现消息加密解密 PHP微信开发:如何实现消息加密解密 May 13, 2023 am 11:40 AM

PHP是一种开源的脚本语言,广泛应用于Web开发和服务器端编程,尤其在微信开发中得到了广泛的应用。如今,越来越多的企业和开发者开始使用PHP进行微信开发,因为它成为了一款真正的易学易用的开发语言。在微信开发中,消息的加密和解密是一个非常重要的问题,因为它们涉及到数据的安全性。对于没有加密和解密方式的消息,黑客可以轻松获取到其中的数据,对用户造成威胁

微信小程序PHP SDK的安装及使用 微信小程序PHP SDK的安装及使用 Mar 27, 2024 am 09:33 AM

微信小程序PHPSDK的安装及使用随着移动互联网的快速发展,微信小程序成为了越来越多企业开展业务、推广产品的新方式。微信小程序PHPSDK则为开发者提供了方便快捷的开发工具,可以大大提高开发效率。本文将介绍微信小程序PHPSDK的安装及使用。一、安装SDK1.在GitHub上下载项目文件微信小程序PHPSDK是一个开源项目,开发者可以在GitHub上

linux中的sdk是什么文件夹 linux中的sdk是什么文件夹 Jul 11, 2023 pm 01:38 PM

linux中的sdk是一个包含了编译器、调试器、库文件、头文件等工具和资源的文件夹。sdk是“software development kit”的缩写,是软件开发工具包的意思,是为开发人员提供的一个集成环境,用于开发和构建应用程序,特别是那些运行在Linux操作系统上的应用程序。

PHP实现开源Kafka SDK PHP实现开源Kafka SDK Jun 18, 2023 am 09:18 AM

随着互联网的快速发展,大量的数据需要被传输和处理,因此消息系统作为数据传输和处理的经典应用之一成为了互联网架构中不可或缺的一部分。Kafka作为高性能、分布式、可伸缩、支持实时数据处理的消息系统被广泛地应用于企业数据架构中。在使用Kafka时,一个重要的问题是如何调用Kafka的API。开发团队为此提供了多种语言的开源客户端,而PHP实现的开源KafkaS

See all articles