微信平台自带的统计功能太简单,有时我们需要统计有哪些微信个人用户阅读、分享了微信公众号的手机网页,以及微信个人用户访问手机网页的来源:朋友圈分享访问、好友分享消息访问等。本系统实现了手机网页阅读、分享与来源统计及手机网页在朋友圈的传播路径分析。

本系统使用最传统的三层架构。本文是微统计的第二篇,主要介绍如下内容:

1. 各实体具体业务实现

2. 获取分享记录

3. 获取访问来源

4. 识别访问者

5. 识别分享者

 

1. 各个实体具体业务实现

PageNavBll:

public class PageNavBll

    {

        public List<PageNavEntity> GetPageNavList()

        {

            var pageNavList = new PageNavDal().GetAll().OrderByDescending(p=>p.VisitTime).ToList();

            PageNavEntity pageNavEntity = new PageNavEntity();

            return pageNavList.Select(p => pageNavEntity.GetViewModel(p)).ToList();

        }

 

        public bool InsertPageNav(PageNavEntity entity)

        {

            return new PageNavDal().Insert(entity.GetDataEntity(entity));

        }

    }

 

PageShareBll:

public class PageShareBll

    {

        public List<PageShareEntity> GetPageShareList()

        {

            var psList = new PageShareDal().GetAll().OrderByDescending(p=>p.ShareTime).ToList();

            PageShareEntity psEnt = new PageShareEntity();

            return psList.Select(p => psEnt.GetViewModel(p)).ToList();

        }

 

        public bool InsertPageShare(PageShareEntity entity)

        {

            return new PageShareDal().Insert(entity.GetDataEntity(entity));

        }

    }

很简单就是查询和插入。

 

2. 获取分享记录

当用户点击了发送到朋友或发送到朋友圈时,可以利用微信JS接口来获取分享记录。详细的实现方法可参考《用c#开发微信 (10) JS-SDK 基本用法- 分享接口“发送到朋友”》。

然后调用上面的PageShareBll插入数据库。

 

3. 获取访问来源

1. 在微信内打开网页

2. 单击微信好友通过“发送给朋友”按钮分享的链接,这里会在链接后面加上 &from=SinbleMessage

3. 如果是朋友圈过来的链接,会在后面带上 &from=timeline

/// <summary>

        /// 判断页面访问来源类型

        /// </summary>

        /// <returns></returns>

        private static NavFrom GetNavFromType()

        {

            //网址中的参数集合

            NameValueCollection parameters = System.Web.HttpContext.Current.Request.Params;

            string fromStr = parameters["from"]; //发送给朋友、分享到朋友圈的链接会含有from参数

 

            m_Log.Info("from: " + fromStr);

 

            NavFrom fromType;

            if (!Enum.TryParse<NavFrom>(fromStr, true, out fromType)) //通过判断from参数,识别页面访问是来自于发送给朋友的链接还是分享到朋友圈的链接

            {

                //获取HTTP访问头中的User-Agent参数的值

                string agent = System.Web.HttpContext.Current.Request.Headers["User-Agent"];

                if (agent.Contains(NavFrom.MicroMessenger.ToString())) //判断页面是否是在微信内置浏览器中打开

                    fromType = NavFrom.MicroMessenger;

                else

                    fromType = NavFrom.Other;

            }

            return fromType;

        }

 

4. 识别访问者

通过网页授权接口,可以方便地获取访问网页的微信个人用户的OpenId。要获取用户的OpenId,每次页面请求都需要执行微信公众平台“网页授权接口”的前二步,如果每次都请求访问这个接口,会影响性能,降低用户体验。因些这里用到了Cookie,第一次获取到OpenId后,把它保存到Cookie里。

首先,建立一个读写Cookie的类:

/// <summary>

   /// 操作站内cookie的助手

   /// </summary>

   public class CookieHelper

   {

       /// <summary>

       /// 写客户端cookie的名字

       /// </summary>

       public const string COOKIE_NAME = "awenhu";

 

       #region 写COOKIE到客户端

 

       /// <summary>

       /// 登录后写COOKIE到客户端,代替session

       /// </summary>

       /// <param name="expires">过期时间,如果永不过期,设为DateTime.MaxValue,<para>如果不想写入客户端,浏览器关闭时即失效则设为DateTime.MinValue</para></param>

       /// <param name="values">保存cookie信息</param>

       public static void WriteLoginCookies(Dictionary<string, string> values, DateTime expires)

       {

           HttpCookie cookie = HttpContext.Current.Request.Cookies[COOKIE_NAME] ?? new HttpCookie(COOKIE_NAME);

           if (expires != DateTime.MinValue)

               cookie.Expires = expires;

           foreach (var value in values)

           {

               cookie.Values[value.Key] = System.Web.HttpUtility.UrlEncode(value.Value);

           }

           HttpContext.Current.Response.Cookies.Add(cookie);

       }

       #endregion

 

       #region cookie中获取信息

 

       /// <summary>

       /// cookie中获取信息;

       /// </summary>

       /// <returns></returns>

       public static Dictionary<string, string> GetLoginCookies(string[] cookieKeys)

       {

           Dictionary<string, string> values = new Dictionary<string, string>();

           HttpCookie cookie = HttpContext.Current.Request.Cookies[COOKIE_NAME];

           if (cookie != null)

           {

               foreach (var cookieKey in cookieKeys)

               {

                   string value = cookie.Values[cookieKey];

                   values.Add(cookieKey,

                              value == null ? null : System.Web.HttpUtility.UrlDecode(cookie.Values[cookieKey].Trim()).Replace("%5F", "_"));

               }

           }

           else

           {

               foreach (var cookieKey in cookieKeys)

               {

                   values.Add(cookieKey, null);

               }

           }

           return values;

       }

       #endregion

 

       #region 清除cookie

 

       /// <summary>

       /// 清除cookie

       /// </summary>

       public static void CleanLoginCookie(string[] keys)

       {

           HttpCookie ck = HttpContext.Current.Request.Cookies[COOKIE_NAME];

 

           if (ck == null || ck.Values.Count == 0)

               return;

           foreach (var key in keys)

           {

               ck.Values[key] = "";

           }

           ck.Expires = DateTime.Now.AddDays(-1.0);

           HttpContext.Current.Response.Cookies.Add(ck);

       }

 

       #endregion

 

   }

 

以前《用c#开发微信(2)扫描二维码,用户授权后获取用户基本信息 (源码下载)》有过介绍怎么取OpenId,这里直接上代码:

/// <summary>

        /// 获取访问者openId

        /// </summary>

        private string GetNavOpenId()

        {

            NameValueCollection parameters = System.Web.HttpContext.Current.Request.Params;

            //获取链接中的openId

            string navOpenId = parameters["u"];

            #region 如果是从微信浏览器浏览,获取真实的微信OpenId

            if (!string.IsNullOrEmpty(appID) && !string.IsNullOrEmpty(appSecret))

            {

                string accessSource = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_USER_AGENT"];

 

                if (accessSource.Contains("MicroMessenger")) //如果是从微信打开页面

                {

                    string[] cookieKeys = new[] { CookieHelper.COOKIE_NAME };

                    Dictionary<string, string> realIdCookie = CookieHelper.GetLoginCookies(cookieKeys); //获取保存在Cookie中的OpenId

                    //如果Cookie中不存在OpenId,或者链接中的openId与Cookie中的OpenId不一致,链接中的openId为分享者的OpenId,需要获取当前用户的真实OpenId

                    if (NeedGetReadOpenId(parameters, realIdCookie))

                    {

                        if (parameters["code"] == null)

                        {

                            // 先去获取code,并记录分享者

                            string snsapi_baseUrl = GoCodeUrl(navOpenId);

                            if (!string.IsNullOrEmpty(snsapi_baseUrl))

                            {

                                CookieHelper.CleanLoginCookie(cookieKeys);

                                //跳转到微信网页授权页面

                                System.Web.HttpContext.Current.Response.Redirect(snsapi_baseUrl, true);

                                System.Web.HttpContext.Current.Response.End();

                                return null;

                            }

                        }

                        else

                        {

                            m_Log.Info("code: " + parameters["code"].ToString());

 

                            OAuthAccessTokenResult tokenResult = GetRealOpenId(parameters["code"].ToString());

                            if (null != tokenResult && !string.IsNullOrEmpty(tokenResult.openid))

                            {

                                m_Log.Info("tokenResult.openid: " + tokenResult.openid);

 

                                navOpenId = tokenResult.openid;

                                // 获取到的当前访问者的OpenId保存到cookie里

                                CookieHelper.CleanLoginCookie(cookieKeys);

                                realIdCookie[CookieHelper.COOKIE_NAME] = tokenResult.openid;

                                CookieHelper.WriteLoginCookies(realIdCookie, DateTime.MinValue);

                            }

                        }

                    }

                }

            }

            #endregion

            return navOpenId;

        }

 

        /// <summary>

        /// 如果Cookie中存在OpenId且链接中的openId与Cookie中的OpenId一致

        /// 则不需要调用网页授权接口,链接中的openId即为当前访问者的真实OpenId

        /// </summary>

        /// <param name="parameters"></param>

        /// <param name="realIdCookie"></param>

        /// <returns></returns>

        private bool NeedGetReadOpenId(NameValueCollection parameters, Dictionary<string, string> realIdCookie)

        {

            string referer = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_REFERER"];

            string openId = null;

            if (realIdCookie != null)

            {

                if (realIdCookie.ContainsKey(CookieHelper.COOKIE_NAME))

                {

                    openId = realIdCookie[CookieHelper.COOKIE_NAME];

                }

            }

 

            m_Log.Info("NeedGetReadOpenId openid: " + openId + " referer: " + referer + " u: " + parameters["u"].ToString());

 

            if (!string.IsNullOrEmpty(referer) && openId == parameters["u"].ToString())

                return false;

            else

                return true;

        }

 

获取OpenId的二个步骤:

/// <summary>

        /// 网页授权接口第一步

        /// 跳转到获取code的url

        /// </summary>

        /// <param name="shareOpenId">当访问来源为朋友圈时的分享者微信openid</param>

        private string GoCodeUrl(string shareOpenId)

        {

            string url = System.Web.HttpContext.Current.Request.Url.AbsoluteUri + "&s=" + shareOpenId; //添加分享者OpenId

            return OAuthApi.GetAuthorizeUrl(appID, url, "STATE", OAuthScope.snsapi_base);

        }

 

        /// <summary>

        /// 网页授权接口第二步

        /// 解析code并获取当前访问者真正的openId

        /// </summary>

        /// <param name="parameters">url参数</param>

        /// <returns>真正的openId</returns>

        private OAuthAccessTokenResult GetRealOpenId(string code)

        {

            OAuthAccessTokenResult result = new OAuthAccessTokenResult();

            try

            {

                result = OAuthApi.GetAccessToken(appID, appSecret, code);

            }

            catch (Exception ex)

            {

                m_Log.Error(ex.Message, ex);

            }

            return result;

        }

 

5. 识别分享者

可以在页面网址中加上当前用户的OpenId,如果分享了页面,通过上面第4步获取到的当前访问者的OpenId跟网址中的不一样,那么网址中的OpenId即为分享者,记录完分享者后,再把网址中的OpenId替换为当前访问者的OpenId,以确保再次被分享后,同样能识别分享者。

 

 

未完待续!!!

 

 

用c#开发微信 系列汇总

用c#开发微信 (12) 微统计 - 阅读分享统计系统 2 业务逻辑实现的更多相关文章

  1. 用c#开发微信 (11) 微统计 - 阅读分享统计系统 1 基础架构搭建

    微信平台自带的统计功能太简单,有时我们需要统计有哪些微信个人用户阅读.分享了微信公众号的手机网页,以及微信个人用户访问手机网页的来源:朋友圈分享访问.好友分享消息访问等.本系统实现了手机网页阅读.分享 ...

  2. 用c#开发微信 (13) 微统计 - 阅读分享统计系统 3 UI设计及后台处理

      微信平台自带的统计功能太简单,有时我们需要统计有哪些微信个人用户阅读.分享了微信公众号的手机网页,以及微信个人用户访问手机网页的来源:朋友圈分享访问.好友分享消息访问等.本系统实现了手机网页阅读. ...

  3. 用c#开发微信 (14) 微统计 - 阅读分享统计系统 4 部署测试 (最终效果图)

    微信平台自带的统计功能太简单,有时我们需要统计有哪些微信个人用户阅读.分享了微信公众号的手机网页,以及微信个人用户访问手机网页的来源:朋友圈分享访问.好友分享消息访问等.本系统实现了手机网页阅读.分享 ...

  4. 用c#开发微信 (7) 微渠道 - 推广渠道管理系统 2 业务逻辑实现

    我们可以使用微信的“生成带参数二维码接口”和 “用户管理接口”,来实现生成能标识不同推广渠道的二维码,记录分配给不同推广渠道二维码被扫描的信息.这样就可以统计和分析不同推广渠道的推广效果. 上次介绍了 ...

  5. 用c#开发微信 (8) 微渠道 - 推广渠道管理系统 3 UI设计及后台处理

    我们可以使用微信的“生成带参数二维码接口”和 “用户管理接口”,来实现生成能标识不同推广渠道的二维码,记录分配给不同推广渠道二维码被扫描的信息.这样就可以统计和分析不同推广渠道的推广效果. 前面二篇& ...

  6. 用c#开发微信 (16) 微活动 2 刮刮卡

    微信营销是一种新型的营销模式,由于微信更重视用户之间的互动,故而这种营销推广不不能盲目地套用微博营销的单纯大量广告推送方式.这种方式在微信营销中的效果非常差,会令用户反感,继而取消去企业或商家的微信公 ...

  7. 用c#开发微信 (9) 微渠道 - 推广渠道管理系统 4 部署测试 (最终效果图)

    我们可以使用微信的“生成带参数二维码接口”和 “用户管理接口”,来实现生成能标识不同推广渠道的二维码,记录分配给不同推广渠道二维码被扫描的信息.这样就可以统计和分析不同推广渠道的推广效果. 本文是微渠 ...

  8. 用c#开发微信 (6) 微渠道 - 推广渠道管理系统 1 基础架构搭建

    我们可以使用微信的“生成带参数二维码接口”和 “用户管理接口”,来实现生成能标识不同推广渠道的二维码,记录分配给不同推广渠道二维码被扫描的信息.这样就可以统计和分析不同推广渠道的推广效果. 本系统使用 ...

  9. 用c#开发微信 (15) 微活动 1 大转盘

    微信营销是一种新型的营销模式,由于微信更重视用户之间的互动,故而这种营销推广不不能盲目地套用微博营销的单纯大量广告推送方式.这种方式在微信营销中的效果非常差,会令用户反感,继而取消去企业或商家的微信公 ...

随机推荐

  1. 9.S5PV210的时钟系统

    1.时钟域:MSYS.DSYS.PSYS(1)因为S5PV210的时钟体系比较复杂,内部外设模块太多,因此把整个内部的时钟划分为3大块,叫做3个域.(2)MSYS: CPU(Cortex-A8内核). ...

  2. ubuntu 14.04 更新 gcc/g++ 4.9.2

    ubuntu 14.04 更新 gcc/g++ 4.9.2 最近看到c++11非常的好用,尤其是自带了regex,于是稍微学了一下c++11的新特性.可是我在编译一个regex程序是却发现稍微复杂一点 ...

  3. ABAP-SQL基础知识

    SQL语法 我们在编写ABAP4程序的时候,经常需要从TABLE中根据某些条件读取数据,读取数据最常用的方法就是通过SQL语法实现的.ABAP/4中可以利用SQL语法创建或读取TABLE,SQL语法分 ...

  4. LoadRunner ---思考时间设置

    用户访问某个网站或软件,一般不会不停地做个各种操作,例如一次查询,用户需要时间查看查询的结果是否是自己想要的.例如一次订单提交,用户需要时间核对自己填写的信息是否正确等. 也就是说用户在做某些操作时, ...

  5. oc中的枚举定义

    typedef NS_ENUM(类型,枚举名){        枚举名+值名,       枚举名+值名,}; 该方法定义的枚举,OC会自动把其转换成合适当前版本的枚举.如果枚举值可合并的话 NS_E ...

  6. SSH基本框架搭建后的简化

    对于SSh框架的简化,我们可以从下面几个方面来剖析: 1.实体类entity:在这里我们需要将数据库和实体类进行关联,在简化之前,我们需要在entity包里面加入一份.xml配置文件 例如原码---- ...

  7. 循序渐进Python3(六) -- 初识内置变量、反射、递归

    #python用下划线作为变量前缀和后缀指定特殊变量.稍后我们会发现,   #对于程序来说,其中的有些变量是非常有用的,而其他的则是未知或者无用的.   #我们总结一下Python中下划线的特殊用法  ...

  8. 搭建本地MAVEN NEXUS 服务

    下载 http://120.192.76.70/cache/www.sonatype.org/downloads/nexus-latest-bundle.zip?ich_args=232fba36ed ...

  9. firefox广告拦截插件

    firefox广告拦截插件: Adblock Plus  Adblock Edge Adblock Plus Pop-up Addon 如果不能更新,则需要修改HOST: 117.18.232.191 ...

  10. C++队列中应该注意的一些问题

    第一次在C++中写类,新手,见笑 #include<iostream.h>#include<iostream>template<typename T> class ...