English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
In the previous article, we mentioned several pitfalls of WeChat public accounts, the first five, and already talked about menus. Baby continues to elaborate. Unfortunately, I don't know if Baby's baby really cares about Baby. Oh, I'm confused...
Back to the main topic, we won't complain about other things. As mentioned in the previous article, we talked about WeChat menus. So, let's talk about menu replies and so on now.
Menu reply requires handling XML files., we can get the unique identifier of each WeChat user relative to the WeChat official account from the XML file returned by WeChat. The mechanism of the WeChat public platform is simply that we output a fixed format xml file, and the WeChat APP is responsible for parsing, getting the information we want, and then processing the information uniformly.
The sixth pit,If you look at the WeChat document, you will definitely be confused, as shown in the figure. The ToUserName and FromUserName must be distinguished, remember not to write them backwards. For WeChat, the user is A→B, then for the user, it is reversed, it seems that it should be clear now.
/// <summary> /// Receive the XML message sent by WeChat and parse it /// </summary> private void ReceiveXml() { try { Stream requestStream = System.Web.HttpContext.Current.Request.InputStream; byte[] requestByte = new byte[requestStream.Length]; requestStream.Read(requestByte, 0, (int)requestStream.Length); string requestStr = Encoding.UTF8.GetString(requestByte); if (!string.IsNullOrEmpty(requestStr)) { //Encapsulate request class XmlDocument requestDocXml = new XmlDocument(); requestDocXml.LoadXml(requestStr); XmlElement rootElement = requestDocXml.DocumentElement; WxXmlModel WxXmlModel = new WxXmlModel(); if (rootElement != null) { WxXmlModel.ToUserName = rootElement.SelectSingleNode("ToUserName") == null ? "" : rootElement.SelectSingleNode("ToUserName").InnerText;63; "" : rootElement.SelectSingleNode("ToUserName").InnerText; WxXmlModel.FromUserName = rootElement.SelectSingleNode("FromUserName") == null ? "" : rootElement.SelectSingleNode("ToUserName").InnerText;63; "" : rootElement.SelectSingleNode("FromUserName").InnerText; WxXmlModel.CreateTime = rootElement.SelectSingleNode("CreateTime") == null63; "" : rootElement.SelectSingleNode("CreateTime").InnerText; WxXmlModel.MsgType = rootElement.SelectSingleNode("MsgType") == null63; "" : rootElement.SelectSingleNode("MsgType").InnerText; switch (WxXmlModel.MsgType) { case "text"://Text WxXmlModel.Content = rootElement.SelectSingleNode("Content") == null63; "" : rootElement.SelectSingleNode("Content").InnerText; break; case "image"://Image WxXmlModel.PicUrl = rootElement.SelectSingleNode("PicUrl") == null63; "" : rootElement.SelectSingleNode("PicUrl").InnerText; break; case "event"://Event WxXmlModel.Event = rootElement.SelectSingleNode("Event") == null63; "" : rootElement.SelectSingleNode("Event").InnerText; if (WxXmlModel.Event != "TEMPLATESENDJOBFINISH")//Type of attention { WxXmlModel.EventKey = rootElement.SelectSingleNode("EventKey") == null63; "" : rootElement.SelectSingleNode("EventKey").InnerText; } break; default: break; } } ResponseXML(WxXmlModel);//Response message } } catch (Exception ee) { //Record error log } } /// <summary> /// Response message /// </summary> /// <param name="WxXmlModel"></param> private void ResponseXML(WxXmlModel WxXmlModel) { string XML = \ switch (WxXmlModel.MsgType) { case "text"://Text reply var info = oauth.GetUserInfo(Tools.WA_GetAccess_Token.IsExistAccess_Token(), WxXmlModel.FromUserName); Tools.WAEntity.OAuthUser user = Tools.JsonHelper.ParseFromJson<Tools.WAEntity.OAuthUser>(info); var content = WxXmlModel.Content.ToUpper(); string NcbActUrl = ConfigurationManager.AppSettings["NcbActUrl"]; string appid = ConfigurationManager.AppSettings["AppID"]; if (content.Contains("T"))//The received text if it contains "T" { //Business processing } else { XML = ResponseMessage.ReText(WxXmlModel.FromUserName, WxXmlModel.ToUserName, "/:rose farm big data welcomes you!/:rose"); } break; case "event": switch (WxXmlModel.Event.ToLower()) { case "subscribe": if (string.IsNullOrEmpty(WxXmlModel.EventKey)) { XML = ResponseMessage.ReText(WxXmlModel.FromUserName, WxXmlModel.ToUserName, "Subscribe successfully!",/:rose"); } else { XML = ResponseMessage.SubScanQrcode(WxXmlModel.FromUserName, WxXmlModel.ToUserName, WxXmlModel.EventKey);//Scan QR code with parameters, first follow and then push the event } break; case "scan": XML = ResponseMessage.ScanQrcode(WxXmlModel.FromUserName, WxXmlModel.ToUserName, WxXmlModel.EventKey);//Scanning a parameter QR code already followed directly push the event break; case "click"://Handle single-click event if (WxXmlModel.EventKey == "p1") { //Your business logic } else { //Your business logic } break; case "unsubscribe"://Unsubscribe break; } break; default://Default reply break; } Response.Write(XML);//Output organized XML information }
This is the information processing of the menu, and the general public who do not know the truth may ask what the so-called ResponseMessage means. OK, I am at a loss for words about the things I have studied for the WeChat public platform these three days.
public class ResponseMessage { #region Received type /// <summary> /// Receive text /// </summary> /// <param name="FromUserName"></param> /// <param name="ToUserName"></param> /// <param name="Content"></param> /// <returns></returns> public static string GetTextTest(string FromUserName, string ToUserName, string Content, string key) { CommonMethod.WriteTxt(Content);//Received text message string XML = \ switch (Content) { case "Keyword": XML = ReText(FromUserName, ToUserName, "Keyword reply test——Xingnongfenghua:" + key); break; case "Single Image Message": XML = ReArticle(FromUserName, ToUserName, "Test Title", "Test Details——Xingnongfenghua:" + key, "http://www.xnfhtech.com/templets/boze/images/20120130083143544.gif", "http://www.xnfhtech.com/"); break; default: XML = ReText(FromUserName, ToUserName, "No corresponding keyword——Xingnongfenghua:" + key); break; } return XML; } /// <summary> /// Scanning a parameter QR code without following /// </summary> /// <param name="FromUserName"></param> /// <param name="ToUserName"></param> /// <param name="EventKey"></param> /// <returns></returns> public static string SubScanQrcode(string FromUserName, string ToUserName, string EventKey) { return ""; } /// <summary> /// Scanned a parameter QR code after subscribing /// </summary> /// <param name="FromUserName"></param> /// <param name="ToUserName"></param> /// <param name="EventKey"></param> /// <returns></returns> public static string ScanQrcode(string FromUserName, string ToUserName, string EventKey) { return ""; } #endregion #region Reply method /// <summary> /// Text reply /// </summary> /// <param name="FromUserName">To whom (openid)</param> /// <param name="ToUserName">From whom (Public Account ID)</param> /// <param name="Content">Text reply type</param> /// <returns>Merged XML</returns> public static string ReText(string FromUserName, string ToUserName, string Content) { string XML = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>";//Send to whom (openid), from whom (public account ID) XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//Reply timestamp XML += "<MsgType><![CDATA[text]]></MsgType>";//Text reply type XML += "<Content><![CDATA[" + Content + "]]></Content><FuncFlag>0</FuncFlag></xml>";//When replying content, set FuncFlag to1When replying, automatically mark the received message as a star, suitable for activity statistics return XML; } /// <summary> /// Single image reply /// </summary> /// <param name="FromUserName">To whom (openid)</param> /// <param name="ToUserName">From whom (Public Account ID)</param> /// <param name="Title">Title</param> /// <param name="Description">Details</param> /// <param name="PicUrl">Image address</param> /// <param name="Url">Address</param> /// <returns>Merged XML</returns> public static string ReArticle(string FromUserName, string ToUserName, string Title, string Description, string PicUrl, string Url) { string XML = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>";//Send to whom (openid), from whom (public account ID) XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//Reply timestamp XML += "<MsgType><![CDATA[news]]></MsgType><Content><![CDATA[]]></Content><ArticleCount>1</ArticleCount><Articles>"; XML += "<item><Title><![CDATA[" + Title + "]]></Title><Description><![CDATA[" + Description + "]]></Description><PicUrl><![CDATA[" + PicUrl + "]]></PicUrl><Url><![CDATA[" + Url + "]]></Url></item>"; XML += "</Articles><FuncFlag>0</FuncFlag></xml>"; return XML; } /// <summary> /// Multi-image reply /// </summary> /// <param name="FromUserName">To whom (openid)</param> /// <param name="ToUserName">From whom (Public Account ID)</param> /// <param name="ArticleCount">Number of articles and images</param> /// <param name="dtArticle"><}}/param> /// <returns></returns> public static string ReArticle(string FromUserName, string ToUserName, int ArticleCount, System.Data.DataTable dtArticle) { string XML = "<xml><ToUserName><![CDATA[" + FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + ToUserName + "]]></FromUserName>";//Send to whom (openid), from whom (public account ID) XML += "<CreateTime>" + CommonMethod.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";//Reply timestamp XML += "<MsgType><![CDATA[news]]></MsgType><Content><![CDATA[]]></Content><ArticleCount>" + ArticleCount + "</ArticleCount><Articles>"; foreach (System.Data.DataRow Item in dtArticle.Rows) { XML += "<item><Title><![CDATA[" + Item["Title"] + "]]></Title><Description><![CDATA[" + Item["Description"] + "]]></Description><PicUrl><![CDATA[" + Item["PicUrl"] + "]]></PicUrl><Url><![CDATA[" + Item["Url"] + "]]></Url></item>"; } XML += "</Articles><FuncFlag>0</FuncFlag></xml>"; return XML; } #endregion }
OK, add your own logic code, is the reply perfectly implemented?
The seventh pit,I really don't want to count anymore, are you sure this reply is okay? To be honest, the baby is not sure because you know where to call it after you write it, my dear, ni ma, it is the safest to add the reply after the server verification passes. I have no scruples anymore.
What are we going to talk about next? Let's talk about getting user information, because all these things are usually based on H5of the page. So, we need to use the configuration we made earlier
This thing, actually it's much less problematic than the previous one, sincerely, baby won't say it's problematic for the time being. Let's show the code.
//WeChat Webpage Authorization2.0 public class Oauth2 { JavaScriptSerializer Jss = new JavaScriptSerializer(); public Oauth2() { } /// <summary> /// Whether the page needs authorization /// </summary> /// <param name="Appid">WeChat application ID</param>/param> /// <param name="redirect_uri">Callback page</param>/param> /// <param name="scope">Application authorization scope snsapi_userinfo (no pop-up authorization page, direct jump, can only get user openid), snsapi_userinfo (pop-up authorization page, can obtain nickname, gender, location through openid. And, even if not subscribed, as long as the user authorizes, their information can also be obtained)</param>/param> /// <returns>Authorization address</returns>/returns> public string GetCodeUrl(string Appid, string redirect_uri, string scope) { return string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1&response_type=code&scope={2&state=STATE#wechat_redirect", Appid, redirect_uri, scope); } /// <summary> /// Whether the page needs authorization /// </summary> /// <param name="Appid">WeChat application ID</param>/param> /// <param name="redirect_uri">Callback page</param>/param> /// <param name="scope">Application authorization scope snsapi_userinfo (no pop-up authorization page, direct jump, can only get user openid), snsapi_userinfo (pop-up authorization page, can obtain nickname, gender, location through openid. And, even if not subscribed, as long as the user authorizes, their information can also be obtained)</param>/param> /// <returns>Authorization address</returns>/returns> public string GetCodeUrl(string Appid, string redirect_uri, string scope,string state) { return string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1&response_type=code&scope={2&state={3#wechat_redirect", Appid, redirect_uri, scope, state); } /// <summary> /// Exchange openid with code, this method is generally used when not fetching the user's nickname /// </summary> /// <param name="Appid"></param> /// <param name="Appsecret"></param> /// <param name="Code">The code parameter carried by the callback page</param> /// <returns>Unique identifier of WeChat user openid</returns>/returns> public string CodeGetOpenid(string Appid, string Appsecret, string Code) { string url = string.Format("https:",//api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1&code={2&grant_type=authorization_code", Appid, Appsecret, Code); string ReText = CommonMethod.WebRequestPostOrGet(url, "");//post/get method to get information Dictionary<string, object> DicText = (Dictionary<string, object>)Jss.DeserializeObject(ReText); if (!DicText.ContainsKey("openid")) return ""; return DicText["openid"].ToString(); } /// <summary> ///Use code to obtain user information (including non-following users) /// </summary> /// <param name="Appid"></param> /// <param name="Appsecret"></param> /// <param name="Code">The code parameter carried by the callback page</param> /// <returns>Get user information (json format)</returns> public string GetUserInfo(string Appid, string Appsecret, string Code) { string url = string.Format("https:",//api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1&code={2&grant_type=authorization_code", Appid, Appsecret, Code); string ReText = CommonMethod.WebRequestPostOrGet(url, "");//post/get method to get information Dictionary<string, object> DicText = (Dictionary<string, object>)Jss.DeserializeObject(ReText); if (!DicText.ContainsKey("openid")) { log.Error("Failed to obtain openid, error code: " + DicText["errcode"].ToString()); return ""; } else { return CommonMethod.WebRequestPostOrGet("https:",//api.weixin.qq.com/sns/userinfo?access_token=" + DicText["access_token"] + "&openid=" + DicText["openid"] + "&lang=zh_CN", ""); } } /// <summary> /// Through openId to obtain user information /// </summary> /// <param name="accesstoken"></param> /// <param name="openid"></param> /// <returns></returns> public string GetUserInfo(string accesstoken, string openid) { string url = string.Format("https:",//api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1&lang=zh_CN", accesstoken, openid); return CommonMethod.WebRequestPostOrGet(url, "");//post/get method to get information } }
We can use the methods inside directly when we need to call them to get WeChat web page authorization, for example, for the B view under the A controller to get authorization and obtain the relevant user information, we can call it directly, such as GetCodeUrl(appid, "http://" + Url + "/A/"B", "snsapi_userinfo")
I still want to complain here.
The eighth pit,The URL concatenation of WeChat menu JSON, the front is not added js verification, so, the hell, add http: as usual.//.
However, after authorization here, because we need to use a lot of user information, this is H5There is a problem with the page value passing. I use Session in my project and write a common method directly. If there is a value in Session, take the value directly. For some things inside, I want to explain that not all code needs to be posted, the code here is just what I personally think needs to be posted. So there may be methods that you can't see, if needed, you can leave a message for this baby, thank you.
public string getSession() { log.Error("GetSession"); string oauthStr = ""; try { if (Session != null && (Session["oauthStr"] == null || string.IsNullOrEmpty(Session["oauthStr"].ToString()))) { if (!string.IsNullOrEmpty(Request.QueryString["code"])) { Oauth2 oauth = new Oauth2(); string code = Convert.ToString(Request["code"]); oauthStr = oauth.GetUserInfo(ConfigurationManager.AppSettings["AppID"], ConfigurationManager.AppSettings["AppSecret"], code); Session["oauthStr"] = oauthStr; Tools.WAEntity.OAuthUser oAuthUser = new Tools.WAEntity.OAuthUser(); oAuthUser = Tools.JsonHelper.ParseFromJson<Tools.WAEntity.OAuthUser>(oauthStr); } return oauthStr; } else { Tools.WAEntity.OAuthUser oAuthUser = new Tools.WAEntity.OAuthUser(); oAuthUser = Tools.JsonHelper.ParseFromJson<Tools.WAEntity.OAuthUser>(Session["oauthStr"].ToString()); return Session["oauthStr"].ToString(); } } catch (Exception e) { log.Error(e.ToString()); return oauthStr; }; }
Then every time I encounter a page that needs to get information, I usually just call this.
基本上剩下的都是我们自己要处理的业务逻辑了,继续说坑吧。
The ninth pit,WeChat uploading pictures, the pit is not just for yourself. This baby really believed it, whether you believe it or not. The pictures can't be uploaded in a for loop. Of course, this is limited to Apple models, big Android is still fine.
As mentioned earlier, this is about the issue of JS security verification, here is to call these verifications, request some necessary permissions, and then get image information, etc.
Don't worry, the baby is all about the picture now, no picture, say a little brother, ... ... ...
Let's continue to look at the code.
Let's start with processing JSON.
public class JsApi { JavaScriptSerializer Jss = new JavaScriptSerializer(); public JsApi() { } const string URL_FORMAT_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi"; #region Verify JsApi permission configuration /// <summary> /// array to get JsApi permission configuration/four parameters /// </summary> /// <param name="Appid">application id</param> /// <param name="Appsecret">key</param> /// <returns>json format of four parameters</returns> public string GetJsApiInfo(string Appid, string Appsecret) { string jsapi_ticket = ""; //ticket cache7200 seconds if (System.Web.HttpContext.Current.Session["jsapi_ticket"] == null) { string ticketurl = string.Format(URL_FORMAT_TICKET, BasicApi.GetAccessToken(Appid, Appsecret));//"https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + GetAccessToken(Appid, Appsecret) + "&type=jsapi" jsapi_ticket = CommonMethod.WebRequestPostOrGet(ticketurl, "");//BasicApi.GetTokenSession System.Web.HttpContext.Current.Session["jsapi_ticket"] = jsapi_ticket; System.Web.HttpContext.Current.Session.Timeout = 7200; BasicApi.WriteTxt("jsapi_ticket1:" + jsapi_ticket); } else { jsapi_ticket = System.Web.HttpContext.Current.Session["jsapi_ticket"].ToString(); BasicApi.WriteTxt("jsapi_ticket2:" + jsapi_ticket); } Dictionary<string, object> respDic = (Dictionary<string, object>)Jss.DeserializeObject(jsapi_ticket); jsapi_ticket = respDic["ticket"].ToString();//Obtain ticket string timestamp = CommonMethod.ConvertDateTimeInt(DateTime.Now).ToString();//Generate the timestamp for the signature generation time string nonceStr = CommonMethod.GetRandCode(16);//Generate the random string for the signature string url = System.Web.HttpContext.Current.Request.Url.AbsoluteUri.ToString();//The current address BasicApi.WriteTxt("url:", + url); string[] ArrayList = { "jsapi_ticket=" + jsapi_ticket, "timestamp=" + timestamp, "noncestr=" + nonceStr, "url=" + url }; Array.Sort(ArrayList); string signature = string.Join("&", ArrayList); string signature = FormsAuthentication.HashPasswordForStoringInConfigFile(signature, "SHA1").ToLower(); string r = "{\"appId\":\"" + Appid + "\",\"timestamp\":" + timestamp + ",\"nonceStr\":\"" + nonceStr + "\",\"signature\":\"" + signature + "\",\"jsApiList\":[\"chooseImage\",\"previewImage\",\"uploadImage\",\"downloadImage\",\"scanQRCode\",\"onMenuShareQQ\"]}"; BasicApi.WriteTxt("r:", + r.Replace(" ", "")); return r.Replace(" ", ""); } }
Then let's see the specific call.
The background code is actually very simple, just output the configuration file, and then the front-end JavaScript can call it directly.
JsApi jsApi = new JsApi(); string config = jsApi.GetJsApiInfo(appId, appSecret); ViewBag.config = config;
Front-end code, it's not difficult, there is an official example.
<script type="text"/javascript"> wx.config(@Html.Raw(ViewBag.config));//Background transmitted WeChat configuration file wx.ready(function () { $("#avatar").click(function () { wx.chooseImage({ count: 1, // Number of images Default9 sizeType: ['compressed'], // You can specify whether it is original image or compressed image, default is both 'original', sourceType: ['album', 'camera'], // You can specify whether the source is album or camera, default is both success: function (res) { var localIds = res.localIds; // Return the local ID list of selected photos, localId can be used as the src attribute of img tags to display images wx.uploadImage({ localId: '' + localIds, isShowProgressTips: 1, success: function (res) { serverId = res.serverId; getWxPhoto(serverId); } }); } }); }); }); wx.error(function (res) { alert("Interface verification failed, detailed information:\n" + JSON.stringify(res)); }); var types = 1; function getWxPhoto(mediaId) { $.ajax({ async: false, type: "post", url: "/ActivityRegistration/DownloadWxPhoto",//Self-processing method data: { mediaId: mediaId, types: types }, success: function (data) { $("#imageico").val(data.result); $("#hed_pic").attr('src', ".." + data.result); $("#hed_pic").attr('alt', "avatarImg"); } }); } </script>
OK, the background method is actually very simple, it is just a binary file processing, no, simple egg, f**k, because of the path problem, I fell into a pit for an hour, f**k. And here is a suggestion, wait for the WeChat image to be downloaded before loading the image on the front end, make sure each image is loaded, make sure the upload of the background image is completed.
/// <summary> /// Download multimedia files /// </summary> /// <param name="userName">Public account</param> /// <param name="mediaId">Media ID</param> /// <param name="data">Return whether the download is successful</param> /// <param name="types">Added image type</param> /// <returns>Return multimedia file data; if the download fails, return null.</returns> public JsonResult DownloadWxPhoto(string mediaId, int types) { ErrorMessage errorMessage; string access_token = BasicApi.GetAccessToken(ConfigurationManager.AppSettings["AppID"], ConfigurationManager.AppSettings["AppSecret"]); byte[] data = MediaHelper.Download(access_token, mediaId, out errorMessage); string files = String.Empty, fileName = String.Empty; files = Server.MapPath("~"}/Wxinphoto/"); if (!Directory.Exists(files)) { Directory.CreateDirectory(files); } fileName = files + DateTime.Now.Ticks + ".jpg"; if (data != null) { bool flag = writeFile(data, fileName); if (flag) { errorMessage = new ErrorMessage(ErrorMessage.SuccessCode, "Download multimedia file successfully."); } else { errorMessage = new ErrorMessage(ErrorMessage.ExceptionCode, "Failed to download multimedia file from WeChat server."); } } else errorMessage = new ErrorMessage(ErrorMessage.ExceptionCode, "Failed to download multimedia file from WeChat server."); return Json(new { result = "/" + urlconvertor(fileName), errorMessage = errorMessage }); } //Read filename to byte[] private byte[] ReadFile(string fileName) { FileStream pFileStream = null; byte[] pReadByte = new byte[0]; try { pFileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read); BinaryReader r = new BinaryReader(pFileStream); r.BaseStream.Seek(0, SeekOrigin.Begin); //Set the file pointer to the beginning of the file pReadByte = r.ReadBytes((int)r.BaseStream.Length); return pReadByte; } catch { return pReadByte; } finally { if (pFileStream != null) pFileStream.Close(); } } //Write byte[] to fileName private bool writeFile(byte[] pReadByte, string fileName) { FileStream pFileStream = null; try { pFileStream = new FileStream(fileName, FileMode.OpenOrCreate); pFileStream.Write(pReadByte, 0, pReadByte.Length); } catch { return false; } finally { if (pFileStream != null) pFileStream.Close(); } return true; } /// <summary> /// Determine whether the target byte array is located at the beginning of the source byte array /// </summary> /// <param name="source">Source byte array</param> /// <param name="target">Target byte array</param> /// <returns>Whether the target byte array is located at the beginning of the source byte array</returns> private bool StartsWithBytes(byte[] source, byte[] target) { if (source == null && target == null) return true; if (source == null && target != null || source != null && target == null) return false; if (source.Length < target.Length) return false; bool startsWith = true; for (int i = 0; i < target.Length; i++) { if (source[i] != target[i]) { startsWith = false; break; } } return startsWith; }
Did you think that's all there is to it? My dear, the avatar has been uploaded, and WeChat's camera has been called as needed. I feel so happy, I'm also a real pro. Remember what I said earlier, I haven't mentioned the pitfalls yet.
Let's repeat our ninth pitfall, f*ck, if you can use a for loop to upload pictures to the background, I'll be impressed, really, I'm impressed.
Alright, let's get straight to it. After some thought and discussion with my teammates, it might be due to some verification on WeChat, which causes us to be able to upload one picture at a time after a successful upload. But our iPhone is a special case, as it's not a problem with Android. It's just that the iPhone has a problem, and it's not a small one. When uploading four pictures, it's always the last one that causes trouble. In the end, I found the all-powerful netizens, thank you. But I've already forgotten where I found you, what an embarrassment......
<script type="text"/javascript"> var types = 2; var urlList=""; var i = 0; function up(resurl) { if (i < resurl.localIds.length) { // Upload photo resu.localIds[i] wx.uploadImage({ localId: '' + resurl.localIds[i], isShowProgressTips: 1, success: function (res) { // alert("res.serverId:") + res.serverId); mediaId = res.serverId; $.ajax({ async: false, type: "post", url: "/ActivityRegistration/DownloadWxPhoto", data: { mediaId: mediaId, types: types }, success: function (data) { $("#picPath").append('<li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" + i + " alt="" /></div></li '> $("#picture" + i).attr('src', data.result); $("#picPath").append('<input value=' + data.result + ' type="hidden" id="picurl" + i + " class="picclass" /"> i++; if (i == resurl.localIds.length - 1) { $("#picPath").append('<li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" alt="" /></div></li '> } up(resurl); } }); } }); } i = 0; } } //Upload image wx.config(@Html.Raw(ViewBag.config)); wx.ready(function () { $("#picPath").click(function () { wx.chooseImage({ count: 3, // Default9 sizeType: ['compressed'], // You can specify whether it is original image or compressed image, default is both 'original', sourceType: ['album', 'camera'], // You can specify whether the source is album or camera, default is both success: function (resu) { var localIds = resu.localIds; // Return the local ID list of selected photos, localId can be used as the src attribute of img tags to display images if (localIds.indexOf("wxlocalresource") != -1) { localIds = localIds.replace("wxlocalresource", "wxLocalResource"); } @(index += 1) if (localIds != '') { $("#picPath").html(""); var sear = new RegExp(','); if (sear.test(localIds)) { up(resu); } else { $("#picPath").append(' <li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" + "@index" + " alt="" " /></div></li '> $("#picture" + "@index").attr('src', localIds); // Upload photo wx.uploadImage({ localId: '' + localIds, isShowProgressTips: 1, success: function (res) { mediaId = res.serverId; $.ajax({ async: false, type: "post", url: "/ActivityRegistration/DownloadWxPhoto", data: { mediaId: mediaId, types: types }, success: function (data) { $("#picPath").append('<input value=' + data.result + ' type="hidden" id="picurl" + @index + " class="picclass" /"> $("#picPath").append('<li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" alt="" /></div></li '> } }); } }); } // $("#picPath").append('<li><div class="imgbox"><img src="/img/cechanadd.png" id="picture" alt="" /></div></li '> } } }); }); }); wx.error(function (res) { alert("Interface verification failed, detailed information:\n" + JSON.stringify(res)); }); </script>
Remember, recursion is enough.
To be honest, the baby doesn't want to say more. You can't be so pretentious, can't you see that WeChat can reply to a message and jump to a web page directly? Why don't you go to hell? Thinking of the mooncake incident of big Alibaba a few days ago, suddenly I feel that programmers are quite tragic. The successful ones are all products, and the problems are all the responsibility of the programmers. Ask, is this really the responsibility of the programmers?
Forget it, I won't complain anymore, I am tired of it...... Baby92year has arrived, it is indeed82year's skin, oh, the baby is tired, really.
By the way, give some H5This is a suggestion for the page. For example, when you click the back button and need to refresh the page, it is about whether the page needs to be refreshed. There are many methods, but in WeChat, the baby still thinks this method is reliable.
<script type="text"/javascript"> if (window.name != "hasLoad") { location.reload(); window.name = "hasLoad"; } window.name = ""; } </script>
Also, if you want to exit the current interface directly into the WeChat public account interface after the WeChat execution is completed, you can directly call a built-in method of WeChat. Remember to write <script></inside the script>.
WeixinJSBridge.call('closeWindow'); //This is to close the current web page of WeChat
So confident in thinking you've handled everything, run away, you have to run, um哼,don't be不服气。
WeChat Public Account refers toThe Tenth PitThis is something I added myself, hahaha, it's about how to deal with these things when the JS verification is done without the header file. Is the baby winning? Oh, perfect, I like it.
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
You must not forget this thing.
That's all for this article. Hope it helps everyone's learning and also hope everyone will support the Yelling Tutorial more.
Declaration: The content of this article is from the Internet, the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been manually edited, and does not assume any relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#w3Please report via email to codebox.com (replace # with @ when sending an email) with relevant evidence. Once verified, this site will immediately delete the content suspected of infringement.