ASP.NET MVC5+EF6+EasyUI 后台管理系统(75)-微信公众平台开发-用户管理

最近代码出现分享问题,360云盘宣布混不下去,所有分享的连接都失效了,最近有时间会把代码转移到百度云,再把文章的代码补回去

前言

本节主要是关注者(即用户)和用户组的管理,微信公众号提供了用户和用户组的管理,我们可以在微信公众号官方里面进行操作,添加备注和标签,以及移动用户组别,同时,微信公众号也提供了相应的接口另我们本地可以操作.我们主要是同步到本地,这样我们可以自己为用户定义更多的信息,以及与本地的业务更好的对接起来.

实现

一、关注与订阅事件

看到我们之前的消息处理类 我们需要扩展一个事件类,这个类与之前消息处理类是一样的分部类,同样来自Senpars微信的SDK

/*----------------------------------------------------------------
    Copyright (C) 2016 Senparc

    文件名:CustomMessageHandler_Events.cs
    文件功能描述:自定义MessageHandler

    创建标识:Senparc - 20150312
----------------------------------------------------------------*/

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Senparc.Weixin.MP.Agent;
using Senparc.Weixin.Context;
using Senparc.Weixin.MP.Entities;
using Senparc.Weixin.MP.Helpers;
using Senparc.Weixin.MP.MessageHandlers;
using Senparc.Weixin.MP;
using Apps.WC.DAL;
using Apps.WC.IDAL;
using System.Collections.Generic;
using Apps.Models;
using Apps.WC.IBLL;
using Apps.WC.BLL;
using Apps.Models.WC;
using Apps.Models.Enum;
using Apps.Common;
using Senparc.Weixin.MP.AdvancedAPIs;
using Senparc.Weixin.MP.AdvancedAPIs.User;

namespace Apps.Web.Areas.WC.Core
{
    /// <summary>
    /// 自定义MessageHandler
    /// </summary>
    public partial class CustomMessageHandler
    {
        public override IResponseMessageBase OnTextOrEventRequest(RequestMessageText requestMessage)
        {
            // 预处理文字或事件类型请求。
            // 这个请求是一个比较特殊的请求,通常用于统一处理来自文字或菜单按钮的同一个执行逻辑,
            // 会在执行OnTextRequest或OnEventRequest之前触发,具有以下一些特征:
            // 1、如果返回null,则继续执行OnTextRequest或OnEventRequest
            // 2、如果返回不为null,则终止执行OnTextRequest或OnEventRequest,返回最终ResponseMessage
            // 3、如果是事件,则会将RequestMessageEvent自动转为RequestMessageText类型,其中RequestMessageText.Content就是RequestMessageEvent.EventKey

            if (requestMessage.Content == "OneClick")
            {
                var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
                strongResponseMessage.Content = "您点击了底部按钮。\r\n为了测试微信软件换行bug的应对措施,这里做了一个——\r\n换行";
                return strongResponseMessage;
            }
            return null;//返回null,则继续执行OnTextRequest或OnEventRequest
        }

        public override IResponseMessageBase OnEvent_ClickRequest(RequestMessageEvent_Click requestMessage)
        {
            IResponseMessageBase reponseMessage = null;
            ////菜单点击,需要跟创建菜单时的Key匹配
            //switch (requestMessage.EventKey)
            //{
            //    case "OneClick":
            //        {
            //            //这个过程实际已经在OnTextOrEventRequest中完成,这里不会执行到。
            //            var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
            //            reponseMessage = strongResponseMessage;
            //            strongResponseMessage.Content = "您点击了底部按钮。\r\n为了测试微信软件换行bug的应对措施,这里做了一个——\r\n换行";
            //        }
            //        break;
            //    case "SubClickRoot_Text":
            //        {
            //            var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
            //            reponseMessage = strongResponseMessage;
            //            strongResponseMessage.Content = "您点击了子菜单按钮。";
            //        }
            //        break;
            //    case "SubClickRoot_News":
            //        {
            //            var strongResponseMessage = CreateResponseMessage<ResponseMessageNews>();
            //            reponseMessage = strongResponseMessage;
            //            strongResponseMessage.Articles.Add(new Article()
            //            {
            //                Title = "您点击了子菜单图文按钮",
            //                Description = "您点击了子菜单图文按钮,这是一条图文信息。",
            //                PicUrl = "http://sdk.weixin.senparc.com/Images/qrcode.jpg",
            //                Url = "http://sdk.weixin.senparc.com"
            //            });
            //        }
            //        break;
            //    case "SubClickRoot_Music":
            //        {
            //            //上传缩略图
            //            var accessToken = Senparc.Weixin.MP.Containers.AccessTokenContainer.TryGetAccessToken(appId, appSecret);
            //            var uploadResult = Senparc.Weixin.MP.AdvancedAPIs.MediaApi.UploadTemporaryMedia(accessToken, UploadMediaFileType.thumb,
            //                                                         Server.GetMapPath("~/Images/Logo.jpg"));
            //            //设置音乐信息
            //            var strongResponseMessage = CreateResponseMessage<ResponseMessageMusic>();
            //            reponseMessage = strongResponseMessage;
            //            strongResponseMessage.Music.Title = "天籁之音";
            //            strongResponseMessage.Music.Description = "真的是天籁之音";
            //            strongResponseMessage.Music.MusicUrl = "http://sdk.weixin.senparc.com/Content/music1.mp3";
            //            strongResponseMessage.Music.HQMusicUrl = "http://sdk.weixin.senparc.com/Content/music1.mp3";
            //            strongResponseMessage.Music.ThumbMediaId = uploadResult.thumb_media_id;
            //        }
            //        break;
            //    case "SubClickRoot_Image":
            //        {
            //            //上传图片
            //            var accessToken = Senparc.Weixin.MP.Containers.AccessTokenContainer.TryGetAccessToken(appId, appSecret);
            //            var uploadResult = Senparc.Weixin.MP.AdvancedAPIs.MediaApi.UploadTemporaryMedia(accessToken, UploadMediaFileType.image,
            //                                                         Server.GetMapPath("~/Images/Logo.jpg"));
            //            //设置图片信息
            //            var strongResponseMessage = CreateResponseMessage<ResponseMessageImage>();
            //            reponseMessage = strongResponseMessage;
            //            strongResponseMessage.Image.MediaId = uploadResult.media_id;
            //        }
            //        break;
            //    case "SubClickRoot_Agent"://代理消息
            //        {
            //            //获取返回的XML
            //            DateTime dt1 = DateTime.Now;
            //            reponseMessage = MessageAgent.RequestResponseMessage(this, agentUrl, agentToken, RequestDocument.ToString());
            //            //上面的方法也可以使用扩展方法:this.RequestResponseMessage(this,agentUrl, agentToken, RequestDocument.ToString());

            //            DateTime dt2 = DateTime.Now;

            //            if (reponseMessage is ResponseMessageNews)
            //            {
            //                (reponseMessage as ResponseMessageNews)
            //                    .Articles[0]
            //                    .Description += string.Format("\r\n\r\n代理过程总耗时:{0}毫秒", (dt2 - dt1).Milliseconds);
            //            }
            //        }
            //        break;
            //    case "Member"://托管代理会员信息
            //        {
            //            //原始方法为:MessageAgent.RequestXml(this,agentUrl, agentToken, RequestDocument.ToString());//获取返回的XML
            //            reponseMessage = this.RequestResponseMessage(agentUrl, agentToken, RequestDocument.ToString());
            //        }
            //        break;
            //    case "OAuth"://OAuth授权测试
            //        {
            //            var strongResponseMessage = CreateResponseMessage<ResponseMessageNews>();
            //            strongResponseMessage.Articles.Add(new Article()
            //            {
            //                Title = "OAuth2.0测试",
            //                Description = "点击【查看全文】进入授权页面。\r\n注意:此页面仅供测试(是专门的一个临时测试账号的授权,并非Senparc.Weixin.MP SDK官方账号,所以如果授权后出现错误页面数正常情况),测试号随时可能过期。请将此DEMO部署到您自己的服务器上,并使用自己的appid和secret。",
            //                Url = "http://sdk.weixin.senparc.com/oauth2",
            //                PicUrl = "http://sdk.weixin.senparc.com/Images/qrcode.jpg"
            //            });
            //            reponseMessage = strongResponseMessage;
            //        }
            //        break;
            //    case "Description":
            //        {
            //            var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
            //            strongResponseMessage.Content = "GetWelcomeInfo";
            //            reponseMessage = strongResponseMessage;
            //        }
            //        break;
            //    case "SubClickRoot_PicPhotoOrAlbum":
            //        {
            //            var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
            //            reponseMessage = strongResponseMessage;
            //            strongResponseMessage.Content = "您点击了【微信拍照】按钮。系统将会弹出拍照或者相册发图。";
            //        }
            //        break;
            //    case "SubClickRoot_ScancodePush":
            //        {
            //            var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
            //            reponseMessage = strongResponseMessage;
            //            strongResponseMessage.Content = "您点击了【微信扫码】按钮。";
            //        }
            //        break;
            //    case "ConditionalMenu_Male":
            //        {
            //            var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
            //            reponseMessage = strongResponseMessage;
            //            strongResponseMessage.Content = "您点击了个性化菜单按钮,您的微信性别设置为:男。";
            //        }
            //        break;
            //    case "ConditionalMenu_Femle":
            //        {
            //            var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
            //            reponseMessage = strongResponseMessage;
            //            strongResponseMessage.Content = "您点击了个性化菜单按钮,您的微信性别设置为:女。";
            //        }
            //        break;
            //    default:
            //        {
            //            var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
            //            strongResponseMessage.Content = "您点击了按钮,EventKey:" + requestMessage.EventKey;
            //            reponseMessage = strongResponseMessage;
            //        }
            //        break;
            //}

            return reponseMessage;
        }

        public override IResponseMessageBase OnEvent_EnterRequest(RequestMessageEvent_Enter requestMessage)
        {
            var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(requestMessage);
            responseMessage.Content = "您刚才发送了ENTER事件请求。";
            return responseMessage;
        }

        public override IResponseMessageBase OnEvent_LocationRequest(RequestMessageEvent_Location requestMessage)
        {
            //这里是微信客户端(通过微信服务器)自动发送过来的位置信息
            var responseMessage = CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "这里写什么都无所谓,比如:上帝爱你!";
            return responseMessage;//这里也可以返回null(需要注意写日志时候null的问题)
        }

        public override IResponseMessageBase OnEvent_ScanRequest(RequestMessageEvent_Scan requestMessage)
        {
            //通过扫描关注
            var responseMessage = CreateResponseMessage<ResponseMessageText>();

            responseMessage.Content = responseMessage.Content ?? string.Format("通过扫描二维码进入,场景值:{0}", requestMessage.EventKey);

            return responseMessage;
        }

        public override IResponseMessageBase OnEvent_ViewRequest(RequestMessageEvent_View requestMessage)
        {
            //说明:这条消息只作为接收,下面的responseMessage到达不了客户端,类似OnEvent_UnsubscribeRequest
            var responseMessage = CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "您点击了view按钮,将打开网页:" + requestMessage.EventKey;
            return responseMessage;
        }

        public override IResponseMessageBase OnEvent_MassSendJobFinishRequest(RequestMessageEvent_MassSendJobFinish requestMessage)
        {
            var responseMessage = CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "接收到了群发完成的信息。";
            return responseMessage;
        }

        /// <summary>
        /// 订阅(关注)事件
        /// </summary>
        /// <returns></returns>
        public override IResponseMessageBase OnEvent_SubscribeRequest(RequestMessageEvent_Subscribe requestMessage)
        {
            var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "欢迎关注";
            return responseMessage;
        }

        /// <summary>
        /// 退订
        /// 实际上用户无法收到非订阅账号的消息,所以这里可以随便写。
        /// unsubscribe事件的意义在于及时删除网站应用中已经记录的OpenID绑定,消除冗余数据。并且关注用户流失的情况。
        /// </summary>
        /// <returns></returns>
        public override IResponseMessageBase OnEvent_UnsubscribeRequest(RequestMessageEvent_Unsubscribe requestMessage)
        {
            var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "有空再来";
            return responseMessage;
        }

        /// <summary>
        /// 事件之扫码推事件(scancode_push)
        /// </summary>
        /// <param name="requestMessage"></param>
        /// <returns></returns>
        public override IResponseMessageBase OnEvent_ScancodePushRequest(RequestMessageEvent_Scancode_Push requestMessage)
        {
            var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "事件之扫码推事件";
            return responseMessage;
        }

        /// <summary>
        /// 事件之扫码推事件且弹出“消息接收中”提示框(scancode_waitmsg)
        /// </summary>
        /// <param name="requestMessage"></param>
        /// <returns></returns>
        public override IResponseMessageBase OnEvent_ScancodeWaitmsgRequest(RequestMessageEvent_Scancode_Waitmsg requestMessage)
        {
            var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "事件之扫码推事件且弹出“消息接收中”提示框";
            return responseMessage;
        }

        /// <summary>
        /// 事件之弹出拍照或者相册发图(pic_photo_or_album)
        /// </summary>
        /// <param name="requestMessage"></param>
        /// <returns></returns>
        public override IResponseMessageBase OnEvent_PicPhotoOrAlbumRequest(RequestMessageEvent_Pic_Photo_Or_Album requestMessage)
        {
            var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "事件之弹出拍照或者相册发图";
            return responseMessage;
        }

        /// <summary>
        /// 事件之弹出系统拍照发图(pic_sysphoto)
        /// 实际测试时发现微信并没有推送RequestMessageEvent_Pic_Sysphoto消息,只能接收到用户在微信中发送的图片消息。
        /// </summary>
        /// <param name="requestMessage"></param>
        /// <returns></returns>
        public override IResponseMessageBase OnEvent_PicSysphotoRequest(RequestMessageEvent_Pic_Sysphoto requestMessage)
        {
            var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "事件之弹出系统拍照发图";
            return responseMessage;
        }

        /// <summary>
        /// 事件之弹出微信相册发图器(pic_weixin)
        /// </summary>
        /// <param name="requestMessage"></param>
        /// <returns></returns>
        public override IResponseMessageBase OnEvent_PicWeixinRequest(RequestMessageEvent_Pic_Weixin requestMessage)
        {
            var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "事件之弹出微信相册发图器";
            return responseMessage;
        }

        /// <summary>
        /// 事件之弹出地理位置选择器(location_select)
        /// </summary>
        /// <param name="requestMessage"></param>
        /// <returns></returns>
        public override IResponseMessageBase OnEvent_LocationSelectRequest(RequestMessageEvent_Location_Select requestMessage)
        {
            var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "事件之弹出地理位置选择器";
            return responseMessage;
        }
    }
}

CustomMessageHandler.cs

        /// <summary>
        /// 订阅(关注)事件
        /// </summary>
        /// <returns></returns>
        public override IResponseMessageBase OnEvent_SubscribeRequest(RequestMessageEvent_Subscribe requestMessage)
        {
            var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "欢迎关注";
            return responseMessage;
        }

        /// <summary>
        /// 退订
        /// 实际上用户无法收到非订阅账号的消息,所以这里可以随便写。
        /// unsubscribe事件的意义在于及时删除网站应用中已经记录的OpenID绑定,消除冗余数据。并且关注用户流失的情况。
        /// </summary>
        /// <returns></returns>
        public override IResponseMessageBase OnEvent_UnsubscribeRequest(RequestMessageEvent_Unsubscribe requestMessage)
        {
            var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
            responseMessage.Content = "有空再来";
            return responseMessage;
        }

里面有2个事件,一个用户关注时触发,一个退订时候触发,所以基本我们无需要进行什么配置,只要加入这个类就可以了

二、本地数据库表

CREATE TABLE [dbo].[WC_Group](
    [Id] [varchar](50) NOT NULL,
    [Name] [varchar](200) NOT NULL,
    [Count] [int] NOT NULL,
    [OfficalAccountId] [varchar](50) NOT NULL,
 CONSTRAINT [PK_WC_Group] PRIMARY KEY CLUSTERED
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[WC_Group]  WITH CHECK ADD  CONSTRAINT [FK_WC_Group_WC_OfficalAccounts] FOREIGN KEY([OfficalAccountId])
REFERENCES [dbo].[WC_OfficalAccounts] ([Id])
GO

ALTER TABLE [dbo].[WC_Group] CHECK CONSTRAINT [FK_WC_Group_WC_OfficalAccounts]
GO

分组表

CREATE TABLE [dbo].[WC_User](
    [Id] [varchar](50) NOT NULL,
    [OpenId] [varchar](50) NOT NULL,
    [NickName] [varchar](200) NULL,
    [Sex] [int] NOT NULL,
    [Language] [varchar](50) NULL,
    [City] [varchar](50) NULL,
    [Province] [varchar](50) NULL,
    [Country] [varchar](50) NULL,
    [HeadImgUrl] [varchar](1000) NULL,
    [SubscribeTime] [datetime] NOT NULL,
    [UnionId] [varchar](200) NULL,
    [Remark] [varchar](1000) NULL,
    [GroupId] [varchar](50) NULL,
    [TagidList] [varchar](1000) NULL,
    [Subscribe] [int] NOT NULL,
    [OfficalAccountId] [varchar](50) NOT NULL,
 CONSTRAINT [PK_WC_User] PRIMARY KEY CLUSTERED
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[WC_User]  WITH NOCHECK ADD  CONSTRAINT [FK_WC_User_WC_Group] FOREIGN KEY([GroupId])
REFERENCES [dbo].[WC_Group] ([Id])
GO

ALTER TABLE [dbo].[WC_User] NOCHECK CONSTRAINT [FK_WC_User_WC_Group]
GO

ALTER TABLE [dbo].[WC_User]  WITH CHECK ADD  CONSTRAINT [FK_WC_User_WC_OfficalAccounts] FOREIGN KEY([OfficalAccountId])
REFERENCES [dbo].[WC_OfficalAccounts] ([Id])
GO

ALTER TABLE [dbo].[WC_User] CHECK CONSTRAINT [FK_WC_User_WC_OfficalAccounts]
GO

用户表

表字段是根据官网,用户管理对应字段而建立,基本与官方提供的用户信息是一样的,无非是存点用户的姓名,籍贯,头像,关注事件等

三、同步数据

这时我们就可以实现OnEvent_SubscribeRequest (关注时)的代码,基本没有实现难度,步骤如下:

  1. 获得OpenID(requestMessage.FromUserName)
  2. 调用信息接口( UserInfoJson userJson = UserApi.Info(account.AccessToken, requestMessage.FromUserName);)
  3. 把信息添加到本地
  4. 启用订阅时回复的内容(回复在前面已经放出)
    /// <summary>
        /// 订阅(关注)事件
        /// </summary>
        /// <returns></returns>
        public override IResponseMessageBase OnEvent_SubscribeRequest(RequestMessageEvent_Subscribe requestMessage)
        {
            ValidationErrors errors = new ValidationErrors();

            using (DBContainer db = new DBContainer())
            {

                IWC_OfficalAccountsBLL account_BLL = new WC_OfficalAccountsBLL()
                {
                    m_Rep = new WC_OfficalAccountsRepository(db)
                };

                //获得当前公众号
                WC_OfficalAccountsModel account = account_BLL.GetById(Id);

                //将用户提取到本地数据库
                WC_UserModel userModel = new WC_UserModel();
                IWC_UserBLL user_BLL = new WC_UserBLL()
                {
                    m_Rep = new WC_UserRepository(db)
                };
                user_BLL.Create(ref errors, userModel);
                UserInfoJson userJson = UserApi.Info(account.AccessToken, requestMessage.FromUserName);
                userModel.Id = ResultHelper.NewId;
                userModel.OpenId = userJson.openid;
                userModel.NickName = userJson.nickname;
                userModel.Sex = userJson.sex;
                userModel.Language = userJson.language;
                userModel.City = userJson.city;
                userModel.Province = userJson.province;
                userModel.Country = userJson.country;
                userModel.HeadImgUrl = userJson.headimgurl;
                userModel.SubscribeTime = ResultHelper.GetTimeByLong(userJson.subscribe_time);
                userModel.UnionId = userJson.unionid;
                userModel.Remark = userJson.remark;
                userModel.GroupId = userJson.groupid.ToString();
                userModel.TagidList = string.Join(",", userJson.tagid_list.ToArray());
                userModel.Subscribe = userJson.subscribe;
                userModel.OfficalAccountId = account.Id;
                IWC_MessageResponseRepository m_Rep = new WC_MessageResponseRepository(db);
                //订阅回复
                List<WC_MessageResponse> messageList = m_Rep.GetSubscribeResponseContent(account.Id);
                if (messageList.Count() > 0)
                {
                    if (messageList[0].Category == (int)WeChatReplyCategory.Text)
                    {
                        var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
                        responseMessage.CreateTime = ResultHelper.NowTime;
                        responseMessage.ToUserName = requestMessage.FromUserName;
                        responseMessage.FromUserName = account.OfficalId;
                        responseMessage.Content = messageList[0].TextContent;
                        return responseMessage;
                    }
                    //图文方式
                    else if (messageList[0].Category == (int)WeChatReplyCategory.Image)
                    {
                        var responseMessage = CreateResponseMessage<ResponseMessageNews>();
                        foreach (var model in messageList)
                        {
                            responseMessage.Articles.Add(new Article()
                            {
                                Title = model.TextContent,
                                Description = model.ImgTextContext,
                                PicUrl = WebChatPara.SiteUrl + model.ImgTextUrl,
                                Url = model.ImgTextLink
                            });
                        }
                        return responseMessage;
                    }//一般很少用到
                    else if (messageList[0].Category == (int)WeChatReplyCategory.Voice)
                    {
                        var responseMessage = base.CreateResponseMessage<ResponseMessageMusic>();
                        responseMessage.Music.MusicUrl = WebChatPara.SiteUrl + messageList[0].MeidaUrl;
                        responseMessage.Music.Title = messageList[0].TextContent;
                        responseMessage.Music.Description = messageList[0].Remark;
                        return responseMessage;
                    }
                }
                var errorResponseMessage = requestMessage.CreateResponseMessage<ResponseMessageText>();
                return errorResponseMessage;
            }
        }

退订事件:OnEvent_UnsubscribeRequest(退订没有什么代码,只是标记这个openID已经取消关注)

 /// <summary>
        /// 订阅(关注)事件
        /// </summary>
        /// <returns></returns>
        public override IResponseMessageBase OnEvent_SubscribeRequest(RequestMessageEvent_Subscribe requestMessage)
        {
            ValidationErrors errors = new ValidationErrors();

            using (DBContainer db = new DBContainer())
            {

                IWC_OfficalAccountsBLL account_BLL = new WC_OfficalAccountsBLL()
                {
                    m_Rep = new WC_OfficalAccountsRepository(db)
                };
                //获得当前公众号
                WC_OfficalAccountsModel account = account_BLL.GetById(Id);
                //将用户提取到本地数据库
                IWC_UserBLL user_BLL = new WC_UserBLL()
                {
                    m_Rep = new WC_UserRepository(db)
                };
                WC_UserModel userModel = user_BLL.GetById(Id);
                //标记为取消关注
                userModel.Subscribe = 0;
                user_BLL.Edit(ref errors, userModel);
                var errorResponseMessage = requestMessage.CreateResponseMessage<ResponseMessageText>();
                return errorResponseMessage;
            }
        }

后台管理

后台管理最直接的效益是分析统计用户的数据状况,这里只演示从服务器同步用户信息,其他都是以前写得发愁的,增删改查了

 前端JS

 $("#btnSync").click(function () {
            var rows = $(‘#List‘).datagrid(‘getSelections‘);
            if (rows.length > 0) {
                var ids = rows.join(",");
                $.each(rows, function (index, row) {
                    ids = ids + row.value + ",";
                });
                $.post("@Url.Action("SyncUser")?ids=" + ids, function (data) {
                    if (data.type == 1)
                        $("#List").datagrid(‘load‘);
                        $.messageBox5s(‘@Resource.Tip‘, data.message);
                }, "json");
            } else { $.messageBox5s(‘@Resource.Tip‘, ‘@Resource.PlaseChooseToOperatingRecords‘); }
        });

后端控制器代码

 public JsonResult SyncUser(string ids,string officeId)
        {
            if (!string.IsNullOrWhiteSpace(ids))
            {
                //填充数据
                string[] arrs = ids.Split(‘,‘);
                List<BatchGetUserInfoData> list = new List<BatchGetUserInfoData>();
                foreach (var m in arrs)
                {
                    list.Add(new BatchGetUserInfoData() {
                        openid = m
                    });
                }

                //批量同步数据
                WC_OfficalAccountsModel accountModel =  account_BLL.GetById(officeId);
                var batchList =  Senparc.Weixin.MP.AdvancedAPIs.UserApi.BatchGetUserInfo(accountModel.AccessToken, list);
                foreach (var info in batchList.user_info_list)
                {
                    WC_UserModel userModel = m_BLL.GetById(info.openid);
                    if (userModel != null)
                    {
                        userModel.City = info.city;
                        userModel.OpenId = info.openid;
                        userModel.Id = info.openid;
                        userModel.HeadImgUrl = info.headimgurl;
                        userModel.Language = info.language;
                        userModel.NickName = info.nickname;
                        userModel.Province = info.province;
                        userModel.Sex = info.sex;
                        m_BLL.Edit(ref errors, userModel);
                    }
                }

                LogHandler.WriteServiceLog(GetUserId(), "Ids:" + ids, "成功", "删除", "WC_User");
                return Json(JsonHandler.CreateMessage(1, Resource.SaveSucceed));
            }
            else
            {
                return Json(JsonHandler.CreateMessage(0, Resource.SaveFail));
            }

        }

代码简单易懂:通过OpenID到公众号同步到数据,再将本地数据修改

同步接口在Senparc WX SDK下的Senparc.Weixin.MP.AdvancedAPIs  UserApi

同时这个类也提供了:获取用户信息,获取关注者OpenId信息,修改关注者备注信息,批量获取用户基本信息

示例代码下载:https://yunpan.cn/cM9ffkutawueD  访问密码 2f0d

时间: 2024-10-28 15:17:50

ASP.NET MVC5+EF6+EasyUI 后台管理系统(75)-微信公众平台开发-用户管理的相关文章

ASP.NET MVC5+EF6+EasyUI 后台管理系统(65)-MVC WebApi 用户验证 (1)

系列目录 前言: WebAPI主要开放数据给手机APP,其他需要得知数据的系统,或者软件应用,所以移动端与系统的数据源往往是相通的. Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能,一个功能复杂的业务应用系统,通过角色授权来控制用户访问 本文通过Basic 方式进行基础认证Mvc的Controller基类及Action的权限验证来实现Web系统登录,Mvc前端权限校验以及WebApi服务端的访问校验功能,本文主要作为本人备忘使用,如能给予人帮助,深感荣幸,欢迎讨论和指正,下面梳

ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(持续更新中...)

开发工具:VS2015(2012以上)+SQL2008R2以上数据库  您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB  升级后界面效果如下: 日程管理   http://www.cnblogs.com/ymnets/p/7094914.html 任务调度系统界面 http://www.cnblogs.com/ymnets/p/5065154.html 系统权限全套完整图  http://www.cnblogs.com/ymnets/p/5065201.html 系统

ASP.NET MVC5+EF6+EasyUI 后台管理系统-关于WebApi的用法

1:ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-WebApi与Unity注入 使用Unity是为了使用我们后台的BLL和DAL层 2:ASP.NET MVC5+EF6+EasyUI 后台管理系统(2)-WebApi与Unity注入-配置文件 3:ASP.NET MVC5+EF6+EasyUI 后台管理系统(3)-MVC WebApi 用户验证 (1) 4:ASP.NET MVC5+EF6+EasyUI 后台管理系统(4)-MVC WebApi 用户验证 (2) 以往我们讲

ASP.NET MVC5+EF6+EasyUI 后台管理系统(84)-Quartz 作业调度用法详解一

前言 我从Quartz2.0开始使用,并对其进行了封装了界面,可以参考 http://www.cnblogs.com/ymnets/p/5065154.html 最近拿出来进行了优化,并升级到最新版,温故而知新嘛 当初教程较少,并且是英文,现在很多地方都有中文的教程也是学习起来事半功倍 Quartz能实现什么? 他类似于SQL Server的代理与Timer定时器: 1.指定时间执行一条SQL语句或存储过程 2.指定时间发送邮件(执行一个C#方法) 3.有规律的定时执行想要做的事情(通过配置Cr

ASP.NET MVC5+EF6+EasyUI 后台管理系统(73)-微信公众平台开发-消息管理

前言 回顾上一节,我们熟悉的了解了消息的请求和响应,这一节我们来建立数据库的表,表的设计蛮复杂 你也可以按自己所分析的情形结构来建表 必须非常熟悉表的结果才能运用这张表,这表表的情形涵盖比较多 思维导图 我这个人比较喜欢用思维导图来分析和表达一些模型: 表结构 根据思维导图,我们可以建立的表可以是3张表:消息表,规则表,类型表 消息表:实际的消息 规则表:文本.图文.语音等 类型表:文本.图文.语音(默认回复,订阅回复) 也可以是两张表:规制表,消息表(+一个类型字段) 我这里只设计一张表:消息

ASP.NET MVC5+EF6+EasyUI 后台管理系统(999)-如何使用

前言 这篇文本讲述了这个框架的使用方式,及一些疑问的答疑,更加精准的使用这个框架来建立功能 经过几个版本的迭代,系统使用更加方便,代码更加简洁也更加的智能,所以之前61节的文章也需要重新编排 对项目的了解 项目没有特别难以理解的类库, 就当成一个普通的MVC,三层项目看待即可 目录 我们只需要分为几步就能快速的建立一个具有权限的功能 表设计及约定 生成代码(代码生成器及TT模板) 配置(URL的配置及权限设置) 1.表设计及约定 框架表的设计必须遵循约定来设计,否则生成的代码需要再重载,而约定只

ASP.NET MVC5+EF6+EasyUI 后台管理系统(92)-打印EasyUI 的datagrid表格

前言 应用系统有时候需要打印Datagrid的表格内容,我们本节就来学习打印datagrid内容 打印主要使用:web打印(我们之前有讲过web打印插件jqprint) + 将datagrid重新编制成可以打印的html格式 一.建立一个普通的例子 我们使用官方下载的demo下的datagrid basic.html代码就好 引入Jqgrid打印插件,并增加一个按钮来触发打印事件 <!DOCTYPE html> <html> <head> <meta charse

ASP.NET MVC5+EF6+EasyUI 后台管理系统(76)-微信公众平台开发-网页授权

前言 网页授权是:应用或者网站请求你用你的微信帐号登录,同意之后第三方应用可以获取你的个人信息 网上说了一大堆参数,实际很难理解和猜透,我们以实际的代码来演示比较通俗易懂 配置 实现之前我们必须配置用户授权获取用户信息的域名或者IP.正式公众号只能配置(域名) 第一步:登录公众号平台 跟我们之前配置公众号平台信息一样 第二步: 打开开发者工具 拉到下半部分位置的网页账号 第三步:配置你的授权回调域名 实现 我们模拟一个需要授权的页面(代码提供来自Senparc) 第一步:新建一个Controll

ASP.NET MVC5+EF6+EasyUI 后台管理系统(4)-创建项目解决方案

系列目录 前言 为了符合后面更新后的重构系统,文章于2016-11-1日重写 设计中术语,概念这种东西过于模糊,我们必须学习累积才能认识这些概念模型. 我无法用文章来下详细解析此系统的深层概念,需要大家在日常工作中实践和意会, 推荐一本.net的设计书籍<Microsoft .NET企业级应用架构设计>这本书详细的讲述了接口编程,面向方面编程 构建解决方案 现在我们开始构建我们的解决方案吧,分别建立类库 Apps.BLL (业务层) Apps.IBLL (业务层接口) Apps.DAL (数据