微信公眾號的開發 Senparc.Weixin.dll使用


   項目需要,做個微信公眾號,之前從未做過,前期挺懵的,再次記錄一下,一切困難都是紙老虎(哈哈)

服務號是公司申請的微信公共賬號,訂閱號是個人申請的。建議開發者自己申請一個測試賬號,方便使用,但是測試賬號不能測試使用支付功能,如果牽扯到支付的功能,建議先用測試賬號把其他的做好,然后使用正式的賬號,測試支付的功能(個人思路哈)

好了,接下來是項目了(以MVC項目為例):

引用的dll

 

測試賬號的申請

地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

需要填寫Url和token:注意這里的Url是有限制的,需要講默的頁面配置為Url!

接下來便是代碼了:

首先你需要建立一個CustomMessageHandler類,繼承自dll中的類,如下:

 

 
    ///
    /// 微信消息處理
    /// 
    ///  根據微信原始Id, 判斷具體推送給哪一個用戶
    /// 
    ///
    public partial class CustomMessageHandler : MessageHandler<MessageContext<Senparc.Weixin.MP.Entities.IRequestMessageBase, Senparc.Weixin.MP.Entities.IResponseMessageBase>>
    {
      

        private static string AppID = ConfigManager.Config.Wechat.AppID;

        static object _locker = new object();
        public CustomMessageHandler(Stream inputStream, PostModel postModel = null, int maxRecordCount = 0) : base(inputStream, postModel, maxRecordCount)
        {
          
            base.CurrentMessageContext.ExpireMinutes = 10;
        }

        public CustomMessageHandler(XDocument requestDocument, PostModel postModel = null, int maxRecordCount = 0) : base(requestDocument, postModel, maxRecordCount)
        {
        }

        public CustomMessageHandler(RequestMessageBase requestMessageBase, PostModel postModel = null, int maxRecordCount = 0) : base(requestMessageBase, postModel, maxRecordCount)
        {
        }

        #region 用戶關注公眾號
        ///
        /// 用戶關注公眾號
        ///
        ///
        ///
        public async override Task OnEvent_SubscribeRequestAsync(RequestMessageEvent_Subscribe requestMessage)
        {
            try
            {
                if (AppID != null)
                {
                    var userInfo = await UserApi.InfoAsync(AppID, base.WeixinOpenId);
                    if (userInfo == null)
                    {
                        Sprite.Agile.Logger.LoggerManager.Instance.Logger_Info($"獲取用戶信息失敗");
                    }
                    else
                    {
                        Sprite.Agile.Logger.LoggerManager.Instance.Logger_Info($"獲取用戶信息,OpenId:{userInfo.openid}, WeixinOpenId:{WeixinOpenId}");
                    }

                    #region 處理用戶信息
                    if (requestMessage.Event == Event.subscribe)
                    {
                        var user = usersRepository.GetUserByOpenId(userInfo.openid);
                        Sprite.Agile.Logger.LoggerManager.Instance.Logger_Info($"二維碼場景值{userInfo.qr_scene}");
                        if (user == null)
                        {
                            user = new 你的用戶類
                            {
                                OpenId = userInfo.openid,
                                WeChatNickName = userInfo.nickname,
                                HeadImg = userInfo.headimgurl,
                                Status = Sprite.Agile.Domain.Status.Disabled,
                                UserType=Sprite.Agile.Model.Domain.Entities.UserType.User,
                                IsSubscribe = true
                            };
                            //判斷是否通過掃描進入關注
                            if (userInfo.subscribe_scene == "ADD_SCENE_QR_CODE")
                            {
                                //暫時通過場景Id識別上級
                                var parent = usersRepository.GetUserByScanId(userInfo.qr_scene);
                                if(parent!=null)
                                {
                                    user.ParentId = parent.Id;
                                }
                            }

                            usersRepository.AddUser(user);
                        }
                        else
                        {
                            user.OpenId = userInfo.openid;
                            user.HeadImg = userInfo.headimgurl;
                            user.WeChatNickName = userInfo.nickname;
                            user.IsSubscribe = true;
                           
                            usersRepository.SaveUser(user);
                        }
                    }
                    #endregion

                    var responseMessage = requestMessage.CreateResponseMessage();
                    responseMessage.Content = $"  感謝您的關注";
                    return responseMessage;
                }
                else
                {
                    Sprite.Agile.Logger.LoggerManager.Instance.Logger_Info($"用戶關注事件, 微信商戶信息為空:{requestMessage.ToUserName}");
                    return new ResponseMessageNoResponse();
                }
            }
            catch (Exception ex)
            {
                Sprite.Agile.Logger.LoggerManager.Instance.Logger_Error(ex);
                return new ResponseMessageNoResponse();
            }

        }
        #endregion

        #region 用戶取消關注
        ///
        /// 用戶取消關注
        ///
        ///
        ///
        public async override Task OnEvent_UnsubscribeRequestAsync(RequestMessageEvent_Unsubscribe requestMessage)
        {
            try
            {
                var wechat = new UserBaseController();
                if (wechat != null)
                {
                    var userInfo = await UserApi.InfoAsync(wechat.AppId, base.WeixinOpenId);

                    #region 處理用戶信息
                    if (requestMessage.Event == Event.unsubscribe)
                    {
                        var user = usersRepository.GetUserByOpenId(userInfo.openid);
                        if (user != null)
                        {

                            user.IsSubscribe = false;
                            usersRepository.SaveUser(user);
                        }
                    }
                    #endregion
                }
                else
                {
                    Sprite.Agile.Logger.LoggerManager.Instance.Logger_Info($"用戶取消關注事件, 微信商戶信息為空:{requestMessage.ToUserName}");
                }

                return new ResponseMessageNoResponse();
            }
            catch (Exception ex)
            {
                Sprite.Agile.Logger.LoggerManager.Instance.Logger_Error(ex);
                return new ResponseMessageNoResponse();
            }
        }
        #endregion      

        #region 處理文字請求
        ///
        /// 處理文字請求
        ///
        ///
        ///
        public async override Task OnTextRequestAsync(RequestMessageText requestMessage)
        {
            Sprite.Agile.Logger.LoggerManager.Instance.Logger_Info($"處理文字請求,ToUserName:{requestMessage.ToUserName}, WeixinOpenId:{WeixinOpenId}");
            try
            {
                return await Task.Factory.StartNew(() =>
                {
                    var responseMessage = requestMessage.CreateResponseMessage();
                    //responseMessage.Content = $"文本消息,ToUserName:{requestMessage.ToUserName}, WeixinOpenId:{WeixinOpenId}";
                    responseMessage.Content = $"歡迎*****微信公眾號";
                    return responseMessage;
                }
                );
            }
            catch (Exception)
            {

                return new ResponseMessageNoResponse();
            };
        }
        #endregion

        public async override Task OnEvent_ScanRequestAsync(RequestMessageEvent_Scan requestMessage)
        {
            //通過掃描關注
            var responseMessage = CreateResponseMessage();

            responseMessage.Content = $"  您已經是我們的用戶啦!" ; 
            return responseMessage;
        }


        #region 默認觸發事件
        ///
        /// 默認觸發事件
        ///
        ///
        ///
        public async override Task DefaultResponseMessageAsync(IRequestMessageBase requestMessage)
        {
            try
            {
                return await Task.Factory.StartNew(() =>
                {
                    var responseMessage = requestMessage.CreateResponseMessage();
                    responseMessage.Content = $"默認,ToUserName:{requestMessage.ToUserName}, WeixinOpenId:{WeixinOpenId}";
                    return responseMessage;
                }
                );
            }
            catch (Exception)
            {

                return new ResponseMessageNoResponse();
            };
        }

        ///
        /// 默認觸發事件
        ///
        ///
        /// 
        public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage)
        {
            try
            {
                var responseMessage = requestMessage.CreateResponseMessage();
                responseMessage.Content = "你需要推送的內容";
                return responseMessage;

            }
            catch (Exception)
            {

                return new ResponseMessageNoResponse();
            };
        }
        #endregion
    }


然后,你需要建立一個基礎的Controller,來進行攔截判斷權限

    ///
    /// 微信認證模塊
    ///
    [AllowAnonymous]
    public class BaseController : Controller
    { 
        //這些文件一般配置zai webconfig中
        private static string Token = ConfigManager.Config.Wechat.Token;
        private static string AppID = ConfigManager.Config.Wechat.AppID;
        private static string AppSecret = ConfigManager.Config.Wechat.AppSecret;
        private static string EncodingAESKey = ConfigManager.Config.Wechat.EncodingAESKey;

        IYueSaoUserService userServices;

        public BaseController()
        {
            userServices = Sprite.Agile.Plugins.PluginManager.Resolve();
        }

        #region  

        // 生成隨機文件名
        readonly Func _getRandomFileName = () => DateTime.Now.ToString("yyyyMmdd-HHmmss") + Guid.NewGuid().ToString("n").Substring(0, 6);


        [HttpGet]
        [ActionName("Index")]
        public Task Get(string signature, string timestamp, string nonce, string echostr)
        {
            return Task.Factory.StartNew(() =>
            {
                if (CheckSignature.Check(signature, timestamp, nonce, Token))
                {
                    return echostr; //返回隨機字符串則表示驗證通過
                }
                else
                {
                    return "failed:" + signature + "," + CheckSignature.GetSignature(timestamp, nonce, Token) + "。" +
                        "如果你在瀏覽器中看到這句話,說明此地址可以被作為微信公眾賬號后台的Url,請注意保持Token一致。";
                }
            }).ContinueWith(task => Content(task.Result));
        }

        ///
        /// 用戶發送消息后,微信平台自動Post一個請求到這里,並等待響應XML
        ///
        [HttpPost]
        [ActionName("Index")]
        public async Task Post(PostModel postModel)
        {
            if (!CheckSignature.Check(postModel.Signature, postModel.Timestamp, postModel.Nonce, Token))
            {
                return new WeixinResult("參數錯誤!");
            }



            #region 打包 PostModel 信息

            postModel.Token = Token;
            postModel.EncodingAESKey = EncodingAESKey; //根據自己后台的設置保持一致
            postModel.AppId = AppID; //根據自己后台的設置保持一致

            #endregion
            var messageHandler = new CustomMessageHandler(Request.InputStream, postModel, 10);

            #region 設置消息去重

            /* 如果需要添加消息去重功能,只需打開OmitRepeatedMessage功能,SDK會自動處理。
             * 收到重復消息通常是因為微信服務器沒有及時收到響應,會持續發送2-5條不等的相同內容的RequestMessage*/
            messageHandler.OmitRepeatedMessage = true;//默認已經開啟,此處僅作為演示,也可以設置為false在本次請求中停用此功能

            #endregion

            try
            {
                #region 記錄 Request 日志

                var logPath = Server.MapPath(string.Format("~/App_Data/MP/{0}/", DateTime.Now.ToString("yyyy-MM-dd")));
                if (!Directory.Exists(logPath))
                {
                    Directory.CreateDirectory(logPath);
                }

                //測試時可開啟此記錄,幫助跟蹤數據,使用前請確保App_Data文件夾存在,且有讀寫權限。
                messageHandler.RequestDocument.Save(Path.Combine(logPath, string.Format("{0}_Request_{1}_{2}.txt", _getRandomFileName(),
                    messageHandler.RequestMessage.FromUserName,
                    messageHandler.RequestMessage.MsgType)));
                if (messageHandler.UsingEcryptMessage)
                {
                    messageHandler.EcryptRequestDocument.Save(Path.Combine(logPath, string.Format("{0}_Request_Ecrypt_{1}_{2}.txt", _getRandomFileName(),
                        messageHandler.RequestMessage.FromUserName,
                        messageHandler.RequestMessage.MsgType)));
                }

                #endregion
                await messageHandler.ExecuteAsync(); //執行微信處理過程
                //messageHandler.Execute(); //執行微信處理過程

                #region 記錄 Response 日志

                //測試時可開啟,幫助跟蹤數據

                //if (messageHandler.ResponseDocument == null)
                //{
                //    throw new Exception(messageHandler.RequestDocument.ToString());
                //}
                if (messageHandler.ResponseDocument != null)
                {
                    messageHandler.ResponseDocument.Save(Path.Combine(logPath, string.Format("{0}_Response_{1}_{2}.txt", _getRandomFileName(),
                        messageHandler.ResponseMessage.ToUserName,
                        messageHandler.ResponseMessage.MsgType)));
                }

                if (messageHandler.UsingEcryptMessage && messageHandler.FinalResponseDocument != null)
                {
                    //記錄加密后的響應信息
                    messageHandler.FinalResponseDocument.Save(Path.Combine(logPath, string.Format("{0}_Response_Final_{1}_{2}.txt", _getRandomFileName(),
                        messageHandler.ResponseMessage.ToUserName,
                        messageHandler.ResponseMessage.MsgType)));
                }

                #endregion

                //return Content(messageHandler.ResponseDocument.ToString());//v0.7-
                return new WeixinResult(messageHandler);//v0.8+
                                                        //return new FixWeixinBugWeixinResult(messageHandler);//為了解決官方微信5.0軟件換行bug暫時添加的方法,平時用下面一個方法即可

            }
            catch (Exception ex)
            {
                #region 異常處理
                //WeixinTrace.Log("MessageHandler錯誤:{0}", ex.Message);

                using (TextWriter tw = new StreamWriter(Server.MapPath("~/App_Data/Error_" + _getRandomFileName() + ".txt")))
                {
                    tw.WriteLine("ExecptionMessage:" + ex.Message);
                    tw.WriteLine(ex.Source);
                    tw.WriteLine(ex.StackTrace);
                    //tw.WriteLine("InnerExecptionMessage:" + ex.InnerException.Message);

                    if (messageHandler.ResponseDocument != null)
                    {
                        tw.WriteLine(messageHandler.ResponseDocument.ToString());
                    }

                    if (ex.InnerException != null)
                    {
                        tw.WriteLine("========= InnerException =========");
                        tw.WriteLine(ex.InnerException.Message);
                        tw.WriteLine(ex.InnerException.Source);
                        tw.WriteLine(ex.InnerException.StackTrace);
                    }

                    tw.Flush();
                    tw.Close();
                }
                return Content("");
                #endregion
            }


        }

        #endregion 

        #region 微信授權
        ///
        /// 微信授權登錄頁面
        ///
        ///跳轉地址
        ///
        public async Task Login(string returnUrl)
        {
            var appId = AppID;

            return await Task.Factory.StartNew(() =>
            {
                var doMain = Request.Url.Scheme + "://" + Request.Url.Host;
                var redirect_uri = $"{doMain}{Url.Action("Callback", new { returnUrl = returnUrl })}";
                var state = "FenXiao-" + DateTime.Now.Millisecond;
                Session["State"] = state;

                #region 通過參數信息,拿到用戶訪問的appid

                #endregion

                var oauthUrl = OAuthApi.GetAuthorizeUrl(appId, redirect_uri, state, OAuthScope.snsapi_userinfo);

                return oauthUrl;
            }).ContinueWith(task =>
            {
                var url = task.Result;
                return Redirect(task.Result);
            });
        }

        ///
        /// 微信回調
        ///
        ///
        ///
        ///
        ///
        public ActionResult Callback(string code, string state, string returnUrl)
        {
            Sprite.Agile.Logger.LoggerManager.Instance.Logger_Info($"微信回調{returnUrl}");
            var url = string.Empty;
            var doMain = Request.Url.Scheme + "://" + Request.Url.Host;

            if (string.IsNullOrEmpty(code))
            {
                url = Url.Action("Msg", "Msg", new { msg = "您拒絕了授權!" });
                return Redirect($"{doMain}/{url}");
            }

            if (state != Session["State"] as string)
            {
                Session["State"] = null;
                url = Url.Action("Msg", "Msg", new { msg = "驗證失敗!請從正規途徑進入!" });
                return Redirect($"{doMain}/{url}");
            }

            OAuthAccessTokenResult result = null;
            try
            {
                result = OAuthApi.GetAccessToken(AppID, AppSecret, code);
            }
            catch (Exception ex)
            {
                url = Url.Action("Msg", "Msg", new { msg = ex.Message });
                return Redirect($"{doMain}/{url}");
            }

            if (result.errcode != Senparc.Weixin.ReturnCode.請求成功)
            {
                url = Url.Action("Msg", "Msg", new { msg = result.errmsg });
                return Redirect($"{doMain}/{url}");
            }

            Session["State"] = null;

            //下面2個數據也可以自己封裝成一個類,儲存在數據庫中(建議結合緩存)
            //如果可以確保安全,可以將access_token存入用戶的cookie中,每一個人的access_token是不一樣的
            Session["OAuthAccessTokenStartTime"] = DateTime.Now;
            Session["OAuthAccessToken"] = result;

            var oauthAccessToken = result.access_token;
            var openId = result.openid;
            var userInfo = OAuthApi.GetUserInfo(oauthAccessToken, openId);

            Session["OpenId"] = openId;
            //Session["AppId"] = appId;

            #region 查找數據庫看用戶信息是不是存在, 根據用戶信息存在與否執行不同操作
            try
            {

                var user = userServices.GetUserByOpenId(openId);

                if (user == null)
                {
                    user = new Sprite.Agile.Model.Domain.Entities.YueSaoUserManage.YueSaoUser
                    {
                        OpenId = openId,
                        WeChatNickName = userInfo.nickname,
                        HeadImg = userInfo.headimgurl,
                        UserType = Sprite.Agile.Model.Domain.Entities.UserType.User,
                        Status = Sprite.Agile.Domain.Status.Disabled,
                    };
                    userServices.AddUser(user);
                }
                else
                {

                    #region 跟新用戶頭像 & 昵稱

                    user.WeChatNickName = userInfo.nickname;
                    user.HeadImg = userInfo.headimgurl;
                    userServices.SaveUser(user);

                    #endregion
                }

                Session["UserId"] = user.Id;
                if (user.ParentId != null)
                    Session["ParentId"] = user.ParentId;
                Sprite.Agile.Logger.LoggerManager.Instance.Logger_Info($"old:{user.Id}   new:{ Session["UserId"]}");
                Session["HeadImg"] = user.HeadImg;
                Session["WeChatNickName"] = user.WeChatNickName;
            }
            catch (Exception ex)
            {
                Sprite.Agile.Logger.LoggerManager.Instance.Logger_Info($"回調錯誤信息{ex.Message}");
                url = Url.Action("Msg", "Msg", new { msg = "從DB中獲取用戶信息失敗" });
                return Redirect($"{doMain}/{url}");
            }
            #endregion

            if (returnUrl.IndexOf('?') != -1)
            {
                returnUrl += "&appId=" + AppID;
            }
            else
            {
                returnUrl += "?appId=" + AppID;
            }
            return Redirect(returnUrl);

        }

        #endregion

        #region  菜單配置

        ///
        /// 微信創建菜單
        ///
        ///
        /// 
        [HttpGet]
        public async Task CreateMenu(string keyValue)
        {
            var data = "成功";
            try
            {
                if (keyValue.IsEmputy())
                {
                    data = "參數錯誤";
                }
                else if (AppID != null)
                {
                    var accessToken = await AccessTokenContainer.GetAccessTokenAsync(AppID);
                    var wechatWeb = 你的Url;// $"{Request.Url.Scheme}://{Request.Url.Host}";
                    Sprite.Agile.Logger.LoggerManager.Instance.Logger_Debug($"菜單地址:{wechatWeb}");
                    ButtonGroup bg = new ButtonGroup();

                    bg.button.Add(new SingleViewButton()
                    {
                        url = $"{wechatWeb}/Home/Index?appId={AppID}",
                        name = "首頁"
                    });


                    bg.button.Add(new SingleViewButton()
                    {
                        url = $"{wechatWeb}/TrainingRegistration/NannyTrain?appId={AppID}",
                        name = "*****"
                    });

                    bg.button.Add(new SingleViewButton()
                    {
                        url = $"{wechatWeb}/YueSaoUser/PersonalCenters?appId={AppID}",
                        name = "個人中心"
                    });

                    var result = CommonApi.CreateMenu(accessToken, bg);
                    if (result.errcode == ReturnCode.請求成功)
                    {
                        data = "菜單同步成功";
                    }
                    else
                    {
                        data = "菜單同步失敗";
                    }
                }
            }
            catch (Exception e)
            {
                data = e.Message;
            }
            ViewBag.Message = data;
            return View();
        }

        #endregion 



    }




注意上面的菜單配置,需要調用一下接口才會有效果的!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM