怎么统计微信自定义菜单的点击量数?
有哪些方法?
我都不知道怎么下手!呜呜呜,哪位大哥做过这方面的功能,可以帮帮我嘛
得到XML 统计一下EventKey呗!
能具体点嘛?
@魔女小溪: 得到XML你会了不? 我写的 项目现在想改成mvc的 这是源码:http://netkf.net/netkfMvc.rar
加百度统计哦也
能够具体点嘛?
我没做过微信。
不过如果微信和普通网站没啥区别的话,
大概思路应该是这样的(当然要先查下是不是微信本身就提供了这个功能。 实在不行才用这个方案):
比如你微信菜单指向的是baidu.com,
那么不要直接指向baidu.com, 而是指向一个页面让他跳转到百度。
比如:http://mysite/redirect.aspx?url=http://www.baidu.com
这样, 在redirect.aspx里面, 你就可以写C#做两件事:
1 跳转到百度
2 记录下, 有跳转到百度。
╮(╯▽╰)╭,搞不懂
不懂,能不能具体点呀!我脑袋很笨!
@魔女小溪: 就是比如说你要调转到百度 这种外面的链接 你就可以建个页面a.aspx 菜单的链接写出a.aspx?url=baidu 在Page_Load 添加以下代码
if(!string.IsNullOrEmpty( Request.QueryString["baidu"]))
{
// +1 进行统计+1 操作
Response.Redirect("http://www.baidu.com/"); // 完成 跳转
}
另一中是自己的页面 比如 b.aspx
菜单的链接写出b.aspx?url=cnblog 在Page_Load 添加以下代码
if(!string.IsNullOrEmpty( Request.QueryString["cnblog"]))
{
// +1 进行统计+1 操作
}
@魔女小溪: 是 if(!string.IsNullOrEmpty( Request.QueryString["url"])) 写错了
@conan_lin: 每个自定义菜单分别统计点击数,你写的这个只是针对外部和自己页面分别统计的点击数,我要的是那种没个菜单都要分别统计的那种,╮(╯▽╰)╭,烦死了!
@魔女小溪: 你说的是那种菜单点击事件的那种,可以再捕获到的事件进行判断统计啊
@conan_lin: 捕获的事件,在哪里?
@conan_lin: 那可以在菜单写相应的链接时再加个参数,然后通过这个参数进行统计判断
这是你说的:就是比如说你要调转到百度 这种外面的链接 你就可以建个页面a.aspx 菜单的链接写出a.aspx?url=baidu 在Page_Load 添加以下代码
@魔女小溪: 就是那种比如点击会发送个图文,这个在菜单定义好事件,用户点击的时候会像你发送个信息 你接收进行处理
@conan_lin: 你弄过mvc吗?我用的是mvc,建了一个controller,然后写了两个action,但是,我对于跳转到外部链接不知道怎么写,~~~~(>_<)~~~~
@魔女小溪: 这种是针对纯菜单的
@魔女小溪: 不是都一样吗
@conan_lin: 痛苦的是,我主要还没弄清楚这个微信,可悲
@conan_lin: 怎么写?O(∩_∩)O~,我不知道
@魔女小溪: 你看下他的api 文档 就那几个接口而已 都类似 挺简单的
@conan_lin: 我笨,看不懂,(⊙o⊙)…我看了很多遍了,就是看不懂,自学能力不行,纠结
@魔女小溪: 你们的服务号可以关注的到吗 叫什么?
@conan_lin: 订阅号,深圳欢乐谷,因为有几个,头像是这种的就是:
@conan_lin: 这是我们的客户,客户要求要这么做,╮(╯▽╰)╭,这么屁大点的公司,开发能力根本就不成熟呀!2个.net开发人员,2个android开发人员,我真是不懂也没得地方问,头大的很!
@魔女小溪: 没找到这个头像的啊
@conan_lin: 是不是有一个没有头像的呀,反正菜单有酷玩攻略等,你加了看看
@魔女小溪: 你要的效果是不是比如点击最新活动的时候除了发送一条有奖活动的图文消息 还进行统计??
@conan_lin: 点击任何一个有内容的菜单都进行分别统计
@魔女小溪:
protected void Page_Load(object sender, EventArgs e)
{
// string s = @"<xml><ToUserName><![CDATA[gh_c51587d175be]]></ToUserName>
//<FromUserName><![CDATA[oehkxt9NoZdCsxAw9fZ2FF4Lfvkc]]></FromUserName>
//<CreateTime>1395365807</CreateTime>
//<MsgType><![CDATA[location]]></MsgType>
//<Location_X>24.486118</Location_X>
//<Location_Y>118.179375</Location_Y>
//<Scale>16</Scale>
//<Label><![CDATA[福建省厦门市思明区观日路22号]]></Label>
//<MsgId>5993050507221723439</MsgId>
//</xml>";
// processRequest(s);
if (Request.HttpMethod.ToUpper() == "GET")
{
// 微信加密签名
string signature = Request.QueryString["signature"];
// 时间戳
string timestamp = Request.QueryString["timestamp"];
// 随机数
string nonce = Request.QueryString["nonce"];
// 随机字符串
string echostr = Request.QueryString["echostr"];
if (WXSignature.CheckSignature(signature, timestamp, nonce))
{
Response.Write(echostr);
}
}
else if (Request.HttpMethod.ToUpper() == "POST")
{
StreamReader stream = new StreamReader(Request.InputStream);
string xml = stream.ReadToEnd();
processRequest(xml);
}
Response.End();
}
private void processRequest(string xml)
{
string log = Server.MapPath("~/") + "log.txt";
AccessConfig.WriteAccess(log, xml);
//xml转datatable
StringReader theReader = new StringReader(xml);
DataSet theDataSet = new DataSet();
theDataSet.ReadXml(theReader);
if (theDataSet.Tables["xml"].Rows.Count > 0)
{
//datatable 转实体类
WXModel model = new ModelTHandler<WXModel>().FillModel(theDataSet.Tables["xml"].Rows[0]);
if (model.MsgType == (MSGType.Event.ToString()).ToLower())//消息事件推送
{
MsgEvent msg = new ModelTHandler<MsgEvent>().FillModel(theDataSet.Tables["xml"].Rows[0]);
if (msg.Event == MSGEvent.subscribe.ToString() || msg.Event == MSGEvent.unsubscribe.ToString())
{
RequestSubScribe(msg);
}
else if (msg.Event == MSGEvent.LOCATION.ToString())//定位推送处理
{
MsgLocation location = new ModelTHandler<MsgLocation>().FillModel(theDataSet.Tables["xml"].Rows[0]);
RequestLocation(location);
string loc = Server.MapPath("~/") + "loc.txt";
AccessConfig.WriteAccess(loc, xml);
}
else if (msg.Event == MSGEvent.CLICK.ToString() || msg.Event == MSGEvent.VIEW.ToString())//菜单事件处理
{
MsgMenuEvent mmsg = new ModelTHandler<MsgMenuEvent>().FillModel(theDataSet.Tables["xml"].Rows[0]);
RequestMenu(mmsg);
}
}//否则为普通消息推送
else //(model.MsgType == MSGType.text.ToString() || model.MsgType == MSGType.image.ToString() || model.MsgType == MSGType.voice.ToString())//文本图片语音
{
MsgTextAccepted msg = new ModelTHandler<MsgTextAccepted>().FillModel(theDataSet.Tables["xml"].Rows[0]);
ProcessMsg(msg);
}
}
}
else if (msg.Event == MSGEvent.CLICK.ToString() || msg.Event == MSGEvent.VIEW.ToString())//菜单事件处理
{
MsgMenuEvent mmsg = new ModelTHandler<MsgMenuEvent>().FillModel(theDataSet.Tables["xml"].Rows[0]);
RequestMenu(mmsg);
}
在这个地方进行操作就行了 你看看
@conan_lin: 好
@conan_lin:
我找了一下,是不是这些个代码呢?
public override IResponseMessageBase OnEvent_ClickRequest(RequestMessageEvent_Click requestMessage) { var Buttons = UserProfile.Buttons; var fileVersionInfo = FileVersionInfo.GetVersionInfo(HttpContext.Current.Server.MapPath("~/bin/EasyWeixin.dll")); foreach (var Button in Buttons) { if (Button.SubButtons.ToList().Count == 0) { if (Button.key == requestMessage.EventKey) { var ResponseMessages = Button.ResponseMessages; return GetEventsResponseMessages(ResponseMessages.ToList(), requestMessage); } } else { foreach (var Subitem in Button.SubButtons) { if (Subitem.key == requestMessage.EventKey) { var ResponseMessages = Subitem.ResponseMessages; return GetEventsResponseMessages(ResponseMessages.ToList(), requestMessage); } } } } var rMessage = UserProfile.ResponseMessages.Where(o => o.ResponseType == 2).ToList(); return GetEventsResponseMessages(rMessage, requestMessage); }
@conan_lin:
上面的:GetEventsResponseMessages()方法
public IResponseMessageBase GetEventsResponseMessages(List<ResponseMessage> ResponseMessages, RequestMessageEventBase requestMessage) { //返回类型Text (ButtonType == 0) if (ResponseMessages.Where(o => o.ButtonType == 0).ToList().Count > 0) { var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(requestMessage); responseMessage.Content = ResponseMessages.Where(o => o.ButtonType == 0).ElementAt(0).Content; return responseMessage; } //返回类型Music (ButtonType == 1) else if (ResponseMessages.Where(o => o.ButtonType == 1).ToList().Count > 0) { var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageMusic>(requestMessage); responseMessage.Music.Title = ResponseMessages.ElementAt(0).ResponseMusic.MusicName; responseMessage.Music.HQMusicUrl = "http://xx" + ResponseMessages.ElementAt(0).ResponseMusic.HQMusicUrl; responseMessage.Music.MusicUrl = "http://xx" + ResponseMessages.ElementAt(0).ResponseMusic.MusicUrl; responseMessage.Music.Description = ""; return responseMessage; } //返回类型Text (ButtonType == 2) else if (ResponseMessages.Where(o => o.ButtonType == 2).ToList().Count > 0) { var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageImage>(requestMessage); responseMessage.PicUrl = "http://xx" + ResponseMessages.ElementAt(0).ResponseImage.ImageUrl; return responseMessage; } //返回类型Text (ButtonType == 3) else if (ResponseMessages.Where(o => o.ButtonType == 3).ToList().Count > 0) { var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageVideo>(requestMessage); responseMessage.VideoUrl = "http://xx" + ResponseMessages.ElementAt(0).ResponseVideo.VideoUrl; return responseMessage; } //返回类型News (ButtonType == 4) else if (ResponseMessages.Where(o => o.ButtonType == 4).ToList().Count > 0) { var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageNews>(requestMessage); foreach (var item in ResponseMessages) { var picurl = String.IsNullOrEmpty(item.ResponseImageText.PicUrl) ? GetImageUrl(item.ResponseImageText.Content) : item.ResponseImageText.PicUrl; var desc = !String.IsNullOrEmpty(item.ResponseImageText.ImageTextDesc) ? HtmlStringHelper.ClearHTMLString(item.ResponseImageText.ImageTextDesc) : ""; responseMessage.Articles.Add(new Article() { Description = desc, Title = item.ResponseImageText.ImageTextName, PicUrl = picurl, Url = item.ResponseImageText.Url + "&User_ID=" + UserProfile.ID + "&UserWexinID=" + requestMessage.FromUserName }); } return responseMessage; } else { return null; } }
@魔女小溪: 看起来应该是 这个不是你写发的?
@conan_lin: 所有的都不是我写的,是以前的人写的,我来的时候,╮(╯▽╰)╭都没怎么跟我讲这个项目,所以,我看的八斤八两的,想死的心都有了
@魔女小溪: 那就试试看有没有效果
@conan_lin: 我还没写呢!我不知道怎么下手,O(∩_∩)O~,怎么弄呀!
@conan_lin: 怎么去区分菜单呀?
@conan_lin: 而且菜单还不是死的,有时候还会改动
@魔女小溪: ButtonType
@魔女小溪: var Buttons = UserProfile.Buttons;这个进去是什么
@conan_lin: 用buttonType只是区分他 可能跳转链接 可能做图文回复 0文字 1语音 2图片 3视频 4 图文消息 5链接,每个主菜单里面有子菜单,而子菜单链接的都可能有,我要做的功能是,统计到单独的一个子菜单点击的次数还有没有子菜单的主菜单的点击次数
@conan_lin: 这是一个UserProfile类里面声明了一个public virtual ICollection<Button> Buttons { get; set; } 这个集合字段
@魔女小溪: 应该是有段代码是专门做菜单处理的 捕获看是不是菜单事件 的看具体代码
@conan_lin: 说实在话,我是真心看不懂以前写这个微信程序的人用意,你说微信就那么几个接口,但是,我每次看这个微信程序我就觉得头好纠结!乱七八糟的,这里一点那里一点的
@魔女小溪: 没有写在单独的工程里面吗 微信推送的消息有个MsgType 来做判断
@conan_lin: 这个UserProfile表跟Buttons表相关联,Buttons表引用userProfile,╮(╯▽╰)╭,越说越来气了,这个程序获取数据库的数据用的还是插件
using Apworks.Specifications;
using AttributeRouting.Web.Mvc;
这样的插件,所以很多东西都封装了,我都毫无头绪!
@conan_lin:
找到这个
public string UpdateWeiXinMenu() { RequestMessageBase rm = new RequestMessageBase(); var count = ButtonRepository.FindAll().Where(o => o.UserId == WebSecurity.GetUserId(User.Identity.Name)).ToList().Count; //主菜单为2~3个 否则报错 if (count > 3 || count < 2) { return "主菜单按钮个数必须是两个或者三个"; } ///获取用户数据 var user = UserProfileRepository.Find(Specification<EasyWeixin.Model.UserProfile>.Eval(o => o.UserId == WebSecurity.CurrentUserId)); ///创建微信菜单实例 EasyWeixin.Entities.Menu.ButtonGroup bg = new EasyWeixin.Entities.Menu.ButtonGroup(); ///提取数据库中菜单数据的前三行数据 var ButtonList = ButtonRepository.FindAll(Specification<Button>.Eval(o => o.UserId == WebSecurity.CurrentUserId)).Take(3); //WeixinController wc = new WeixinController(); ///将数据库中数据添加到微信菜单实例中 foreach (var item in ButtonList) { if (item.SubButtons != null && item.SubButtons.ToList().Count > 0) { EasyWeixin.Entities.Menu.SubButton SubButton = new EasyWeixin.Entities.Menu.SubButton(); SubButton.name = item.name; //SubButton.key = "click"; foreach (var Subitem in item.SubButtons.Take(5)) { if (Subitem.ResponseMessages.ToList().Count > 0 && Subitem.ResponseMessages.ToList()[0].ButtonType == 5) { EasyWeixin.Entities.Menu.SingleViewButton SingleButton = new EasyWeixin.Entities.Menu.SingleViewButton(); SingleButton.name = Subitem.name; SingleButton.url = Subitem.ResponseMessages.ToList()[0].Link; SingleButton.type = "view"; SubButton.sub_button.Add(SingleButton); } else { EasyWeixin.Entities.Menu.SingleClickButton SingleButton = new EasyWeixin.Entities.Menu.SingleClickButton(); SingleButton.name = Subitem.name; SingleButton.key = "SubButton_click_" + Subitem.SubButtonID.ToString(); SingleButton.type = "click"; //2014/6/4 tianxiu //if (Subitem.name=="授权") //{ // string MyAppid = user.AppId; // string RedirectUri = "http://xx/SelfDefiningMenu/AuthRedirectUri"; // string URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + MyAppid + "&redirect_uri=" + RedirectUri + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"; // string Str = "<a href='" + URL + "'>授权页面</a>"; // string res = sendTextMessage(rm, Str); // Response.Write(res); //} SubButton.sub_button.Add(SingleButton); } } bg.button.Add(SubButton); } else { if (item.ResponseMessages.ToList().Count > 0 && item.ResponseMessages.ToList()[0].ButtonType == 5) { EasyWeixin.Entities.Menu.SingleViewButton SingleButton = new EasyWeixin.Entities.Menu.SingleViewButton(); SingleButton.name = item.name; SingleButton.url = item.ResponseMessages.ToList()[0].Link; SingleButton.type = "view"; bg.button.Add(SingleButton); } else { EasyWeixin.Entities.Menu.SingleClickButton SingleButton = new EasyWeixin.Entities.Menu.SingleClickButton(); SingleButton.name = item.name; SingleButton.key = "Button_click_" + item.ButtonID.ToString(); SingleButton.type = "click"; bg.button.Add(SingleButton); } } } AccessTokenResult Result = CommonApi.GetToken(user.AppId, user.AppSecret); string token = Result.access_token; string str = Newtonsoft.Json.JsonConvert.SerializeObject(bg); WxJsonResult wx = CommonApi.CreateMenu(token, bg); return "更新成功"; }
@魔女小溪: 这个是更新菜单的 跟点击事件没关系
@conan_lin: 那我之前发的那两个应该就是处理菜单的,因为找不到别的了
@魔女小溪: 哎。。。 要从在微信配置的接受消息的那个页面 的page_load 那边找下来
@conan_lin: 是这个吗?
public class EventService { public ResponseMessageBase GetResponseMessage(RequestMessageEventBase requestMessage) { ResponseMessageBase responseMessage = null; switch (requestMessage.Event) { case Event.ENTER: { var strongResponseMessage = requestMessage.CreateResponseMessage<ResponseMessageText>(); strongResponseMessage.Content = "您刚才发送了ENTER事件请求。"; responseMessage = strongResponseMessage; break; } case Event.LOCATION: throw new Exception("暂不可用"); //break; case Event.subscribe://订阅 { var strongResponseMessage = requestMessage.CreateResponseMessage<ResponseMessageText>(); //获取Senparc.Weixin.MP.dll版本信息 var fileVersionInfo = FileVersionInfo.GetVersionInfo(HttpContext.Current.Server.MapPath("~/bin/EasyWeixin.dll")); var version = fileVersionInfo.FileVersion; strongResponseMessage.Content = string.Format( "欢迎关注【Senparc.Weixin.MP 微信公众平台SDK】,当前运行版本:v{0}。\r\n您还可以发送【位置】【图片】【语音】信息,查看不同格式的回复。\r\nSDK官方地址:http://weixin.senparc.com", version); responseMessage = strongResponseMessage; break; } case Event.unsubscribe://退订 { //实际上用户无法收到非订阅账号的消息,所以这里可以随便写。 //unsubscribe事件的意义在于及时删除网站应用中已经记录的OpenID绑定,消除冗余数据。 var strongResponseMessage = requestMessage.CreateResponseMessage<ResponseMessageText>(); strongResponseMessage.Content = "有空再来"; responseMessage = strongResponseMessage; break; } case Event.CLICK://菜单点击事件,根据自己需要修改 throw new Exception("Demo中还没有加入CLICK的测试!"); //break; default: throw new ArgumentOutOfRangeException(); } return responseMessage; } }
@conan_lin: O(∩_∩)O~,哥,你是不是很无语呀。。。
@魔女小溪: 最后找到的应该是的了吧,是事件处理程序
@魔女小溪: case Event.CLICK://菜单点击事件,根据自己需要修改 throw new Exception("Demo中还没有加入CLICK的测试!"); //break; 应该就是这个地方了 这边没写 你要自己写
@conan_lin: 怎么写呀?点我一下行不!(*^__^*) 嘻嘻……
@conan_lin: 我加你企鹅行不
@魔女小溪:
@conan_lin: 这个公司还有个不好的地方,连qq都不能上,我那时候怎么会选择这家公司,原因只有一个,就是因为经验不够!呜呜呜,掉进坑里面去了!
1L已经说了,如果你会开发了,自然就知道什么意思了。