系列目录

前言

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

实现

一、关注与订阅事件

看到我们之前的消息处理类 我们需要扩展一个事件类,这个类与之前消息处理类是一样的分部类,同样来自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() > )
{
if (messageList[].Category == (int)WeChatReplyCategory.Text)
{
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
responseMessage.CreateTime = ResultHelper.NowTime;
responseMessage.ToUserName = requestMessage.FromUserName;
responseMessage.FromUserName = account.OfficalId;
responseMessage.Content = messageList[].TextContent;
return responseMessage;
}
//图文方式
else if (messageList[].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[].Category == (int)WeChatReplyCategory.Voice)
{
var responseMessage = base.CreateResponseMessage<ResponseMessageMusic>();
responseMessage.Music.MusicUrl = WebChatPara.SiteUrl + messageList[].MeidaUrl;
responseMessage.Music.Title = messageList[].TextContent;
responseMessage.Music.Description = messageList[].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 = ;
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(, Resource.SaveSucceed));
}
else
{
return Json(JsonHandler.CreateMessage(, Resource.SaveFail));
} }

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

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

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

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

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

    系列目录 前言: 回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手. 继续上一篇的文章,我们接下来演示利用拿到的Token来访 ...

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

    系列目录 前言: WebAPI主要开放数据给手机APP,其他需要得知数据的系统,或者软件应用,所以移动端与系统的数据源往往是相通的. Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能, ...

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

    开发工具:VS2015(2012以上)+SQL2008R2以上数据库  您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB  升级后界面效果如下: 任务调度系统界面 http: ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(转)

    开发工具:VS2015(2012以上)+SQL2008R2以上数据库 您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB 升级后界面效果如下: 日程管理   http://ww ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统-WebApi的用法与调试

    1:ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-WebApi与Unity注入 使用Unity是为了使用我们后台的BLL和DAL层 2:ASP.NET MVC5+EF6+Easy ...

  6. ASP.NET MVC5+EF6+EasyUI 后台管理系统(63)-Excel导入和导出-自定义表模导入

    系列目录 前言 上一节使用了LinqToExcel和CloseXML对Excel表进行导入和导出的简单操作,大家可以跳转到上一节查看: ASP.NET MVC5+EF6+EasyUI 后台管理系统(6 ...

  7. ASP.NET MVC5+EF6+EasyUI 后台管理系统(51)-系统升级

    系统很久没有更新内容了,期待已久的更新在今天发布了,最近花了2个月的时间每天一点点,从原有系统 MVC4+EF5+UNITY2.X+Quartz 2.0+easyui 1.3.4无缝接入 MVC5+E ...

  8. ASP.NET MVC5+EF6+EasyUI 后台管理系统(70)-微信公众平台开发-成为开发者

    系列目录 前言: 一.阅读这段系列之前,你必须花半天时间大致阅读微信公众平台的API文档,我尽量以简短快速的语言与大家分享一个过程 二.借助微信公众平台SDK Senparc.Weixin for C ...

  9. ASP.NET MVC5+EF6+EasyUI 后台管理系统 (源码购买说明)

    系列目录 升级日志 !!!重大版本更新:于2016-12-20日完成了系统的结构重构并合并简化了T4(这是一次重要的更新,不需要修改现有功能的代码),代码总行数比上个版本又少了1/3.更新了代码生成器 ...

随机推荐

  1. java基础集合经典训练题

    第一题:要求产生10个随机的字符串,每一个字符串互相不重复,每一个字符串中组成的字符(a-zA-Z0-9)也不相同,每个字符串长度为10; 分析:*1.看到这个题目,或许你脑海中会想到很多方法,比如判 ...

  2. ASP.NET Aries 入门开发教程9:业务表单的开发

    前言: 经过前面那么多篇的列表的介绍,终于到了大伙期待的表单开发了. 也是本系列的最后一篇文章了! 1:表单页面的权限设置与继承 对于表单页面,权限的设置有两种: 1:你可以选择添加菜单(设置为不显示 ...

  3. 几个比较”有意思“的JS脚本

    1.获取内网和公网真实IP地址(引用地址) <!DOCTYPE html> <html> <head> <meta http-equiv="Cont ...

  4. C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子)

    第一次接触HtmlAgilityPack是在5年前,一些意外,让我从技术部门临时调到销售部门,负责建立一些流程和寻找潜在客户,最后在阿里巴巴找到了很多客户信息,非常全面,刚开始是手动复制到Excel, ...

  5. 分享两种实现Winform程序的多语言支持的解决方案

    因公司业务需要,需要将原有的ERP系统加上支持繁体语言,但不能改变原有的编码方式,即:普通程序员感受不到编码有什么不同.经过我与几个同事的多番沟通,确定了以下两种方案: 方案一:在窗体基类中每次加载并 ...

  6. R abalone data set

    #鲍鱼数据集aburl <- 'http://archive.ics.uci.edu/ml/machine-learning-databases/abalone/abalone.data' ab ...

  7. React Native 之 Text的使用

    前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...

  8. 项目游戏开发日记 No.0x000001

    14软二杨近星(2014551622) 既然已经决定了开发软件, 时不时就要练练手, 还要时不时的去寻找素材, 因为开发的人物设定就是DotA2里面的祈求者, 所以, 就去找了他的相关人物图片和模型, ...

  9. 我的MYSQL学习心得(三) 查看字段长度

    我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  10. Jexus服务器SSL二级证书安装指南

    申请获得服务器证书有三张,一张服务器证书,二张中级CA证书.在Android微信中访问Https,如果服务器只有一张CA证书,就无法访问. 获取服务器证书中级CA证书: 为保障服务器证书在客户端的兼容 ...