博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
微信公众号的开发 Senparc.Weixin.dll使用
阅读量:5136 次
发布时间:2019-06-13

本文共 21342 字,大约阅读时间需要 71 分钟。

   项目需要,做个微信公众号,之前从未做过,前期挺懵的,再次记录一下,一切困难都是纸老虎(哈哈)

服务号是公司申请的微信公共账号,订阅号是个人申请的。建议开发者自己申请一个测试账号,方便使用,但是测试账号不能测试使用支付功能,如果牵扯到支付的功能,建议先用测试账号把其他的做好,然后使用正式的账号,测试支付的功能(个人思路哈)

好了,接下来是项目了(以MVC项目为例):

引用的dll

 

测试账号的申请

地址:

需要填写Url和token:注意这里的Url是有限制的,需要讲默的页面配置为Url!

接下来便是代码了:

首先你需要建立一个CustomMessageHandler类,继承自dll中的类,如下:

 

///    /// 微信消息处理    ///     ///  根据微信原始Id, 判断具体推送给哪一个用户    ///     ///    public partial class CustomMessageHandler : MessageHandler
> { 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     }

注意上面的菜单配置,需要调用一下接口才会有效果的!

转载于:https://www.cnblogs.com/kekelele/p/9989174.html

你可能感兴趣的文章
发布功能完成
查看>>
【原】小程序常见问题整理
查看>>
C# ITextSharp pdf 自动打印
查看>>
【Java】synchronized与lock的区别
查看>>
django高级应用(分页功能)
查看>>
【转】Linux之printf命令
查看>>
关于PHP会话:session和cookie
查看>>
STM32F10x_RTC秒中断
查看>>
display:none和visiblity:hidden区别
查看>>
C#double转化成字符串 保留小数位数, 不以科学计数法的形式出现。
查看>>
牛的障碍Cow Steeplechase
查看>>
Zookeeper选举算法原理
查看>>
3月29日AM
查看>>
利用IP地址查询接口来查询IP归属地
查看>>
HTML元素定义 ID,Class,Style的优先级
查看>>
构造者模式
查看>>
http和https的区别
查看>>
Hbuild在线云ios打包失败,提示BuildConfigure Failed 31013 App Store 图标 未找到 解决方法...
查看>>
找到树中指定id的所有父节点
查看>>
今天新开通了博客
查看>>