惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - ~在思考中沉淀~

VS2005中通过code snippet定制类模板 寻找合租的朋友;-) [晴,天气不错]咖啡罐上的灰尘 辛苦的周末~ 结合Web Services和Windows Services定期执行Asp.Net代码 可怕的春运,烦人的火车票! RSS Reader\Workflow Lite\User Manager for Sharepoint以及一点想法 - ~在思考中沉淀~ 创建自定义的Visual Studio项模板 微软推出Microsoft Exchange Server Best Practices Analyzer Tool 有要Gmail的吗?;)[已结束!] 分析更新LastActivity的过程-补Who is online 科技对生活的影响 创建VS.Net外接程序时遇到的问题 开始GMail之旅 .Net和Windows应用程序调试[更新至2004-12-29] 学习SQL Server全文索引 惊喜->监护期 悲哀的晚上 my代码分析器
WhoIsOnline ;) - 解读CNForum源码中在线用户统计
~在思考中沉淀~ · 2005-01-05 · via 博客园 - ~在思考中沉淀~

下载CnForumsBeta1(今天发现CnForum1.2测试版本已经发布,可以至开发实验室下载,或者访问宝玉的blog)已经有段时间,一直想看看其中的代码,但是它的项目结构实在是复杂(也是本人能力有限),实在是觉得无从下手。
最近由于项目的原因对如何统计在线用户信息很感兴趣,正好利用这个机会学习一下CnForum的实现方式。

  BTW:用Google搜了一下“asp.net 用户统计”(如google搜索结果),结果发现前几篇文章的内容几乎相同,只是稍微修改了某些字和出处而已,只是有意思。看样子真是天下文章一大“抄”啊!当然这不是今天讨论的重点,下面切入主题。

首先就是选取切入点。在安装CnForum后的论坛首页左下方有用户在线信息的统计,显示效果如图:

当用户点击“用户在线信息”时,将弹出显示详细的用户在线信息。查看“用户在线信息”链接发现是指向ViewOnline.aspx的。那么就从ViewOnline.aspx页面开始着手吧。
查看ViewOnline.aspx页面的HTML代码,发现主要功能实现是AspNetForums.Controls下的WhoIsOnlineView控件展现的。
进一步查看WhoIsOnlineView控件代码(在子项目Controls下)。
WhoIsOnlineView类是继承SkinnedForumWebControl类的,从名称来看SkinnedForumWebControl类应该不是重点。重点是WhoIsOnlineView类中重写的InitializeSkin(Control skin)方法。从方法中的代码知道是使用repeat控件来显示注册会员和游客信息。
由于获取注册会员和游客信息的方法应该是雷同的,所以这里只需要分析在线注册会员的获得即可。
从代码 repeater.DataSource = Users.GetUsersOnline(15);知道在线注册会员数据的获得是通过Users类的GetUsersOnline(int pastMinutes)方法得到。
定位到Users类(子项目Components下)的GetUsersOnline方法,进而发现实际是调用Users类的GetMembersGuestsOnline(int pastMinutes)方法获得数据。
检查GetMembersGuestsOnline方法的函数体,其中对获取在线注册会员数据的关键代码应该是:
    ForumsDataProvider dp = ForumsDataProvider.Instance();

    users = dp.WhoIsOnline(pastMinutes);

分析ForumsDataProvider dp = ForumsDataProvider.Instance()
定位至ForumsDataProvider类(子项目Components中Provider下)的静态方法Instance()->静态方法Instance (HttpContext context, string providerTypeName, string databaseOwner, string connectionString),目的是返回一个ForumsDataProvider类的实例。
那么ForumsDataProvider的Instance方法到底完成了什么呢?
首先通过ForumConfiguration config = ForumConfiguration.GetConfig();获得ForumConfirguration类的对象。定位至ForumConfirguration的GetConfig方法。

奇怪的事情出现了:GetConfig方法中只有简单的一句(ForumConfiguration) ConfigurationSettings.GetConfig("forums/forums"),但是从ForumConfirguration类定义来看私有成员有很多(如providers、defaultProvider等),而且回头看看
ForumsDataProvider的Instance方法中在调用GetConfig方法后就使用了config的providers。那这些私有成员到底是怎样初始化的呢?看样子玄机就在ConfigurationSettings.GetConfig方法上。查看MSDN知道这个方法是用来“返回用户定义的配置节的配置设置”,查看Web.config的配置,发现forums/forums节是<section name="forums" type="AspNetForums.Configuration.ForumsConfigurationHandler, AspNetForums.Components" />。
在MSDN中搜索section,有这样一段话“声明配置节实质上为配置文件定义了新元素。新元素包含配置节处理程序(即实现

IConfigurationSectionHandler 接口

的类)读取的设置。所定义的节的属性和子元素取决于用来读取设置的节处理程序。”。难道说ForumsConfigurationHandler是指项目中自定义的配置节处理程序。
搜索项目,果然在ForumConfiguration.cs文件(子项目Components/Confirguration下)找到了类ForumsConfigurationHandler,它实现了接口IConfigurationSectionHandler。搜索MSDN知道IConfigurationSectionHandler接口有方法Create,可以返回用户自己的配置对象。
回到代码中,在ForumsConfigurationHandler中用户获得了ForumConfiguration对象,并且通过方法LoadValuesFromConfigurationXml初始化了ForumConfiguration对象的私有成员。
哦,原来如此!看似简单的一句return (ForumConfiguration) ConfigurationSettings.GetConfig("forums/forums")其实已经填充了所需的配置内容。
[是不是很罗嗦啊,不要拿砖头砸我哦!喝口水先~~~]

回到ForumsDataProvider类的Instance方法中,随后的代码就是获得缺省配置内容(详细情况可以查看Web.config),包括数据库连接字符串、数据库Owner等配置信息,以及关键的缺省Provider类型名称providerTypeName,在我的项目配置中是“AspNetForums.Data.SqlDataProvider”,记住这个名字,它随后将起到关键作用!
继续>>根据代码,当Cache["DataProvider"]为null时,获得与前面得到的providerTypeName相应的Type,下面有这样一句代码:cache.Insert( "DataProvider", type.GetConstructor(paramTypes) );。
问题来了,这段代码是做什么的呢?
搜索MSDN知道Type.GetConstructor 方法是“获取当前Type的特定构造函数”(这里说的特定就是指paramTypes,即有两个string参数的构造函数)。根据前面知道type的类型是AspNetForums.Data.SqlDataProvider,那就意味着应该有个类,名字是SqlDataProvider,并且有个样子是SqlDataProvider(string param1,string param2)的构造函数。
搜索项目...果然在子项目SqlDataProvider下的有个名为SqlDataProvider的类,并且构造函数为SqlDataProvider(string databaseOwner, string connectionString)。原来cache.Insert( "DataProvider", type.GetConstructor(paramTypes) )是把与WebConfig中配置的defaultProvider(这里是SqlDataProiver,继承ForumsDataProvider)相应的ConstructorInfo,通过这个ConstructInfo对象我们可以调用SqlDataProvider的构造函数来获得SqlDataProvider对象。
这样做的好处是显而易见的,我们只需要修改Web.config就可以灵活的修改具体访问数据所使用的类。

然后通过ConstructorInfo的Invoke方法获得了SqlDataProvider对象。
    object[] paramArray = new object[2];
    paramArray[0] = databaseOwner;
    paramArray[1] = connectionString;

    return (ForumsDataProvider)(  ((ConstructorInfo)cache["DataProvider"]).Invoke(paramArray) );

至此,通过ForumsDataProvider dp = ForumsDataProvider.Instance()实际获得了SqlDataProvider对象,而在SqlDataProvider类中通过重写实现了ForumsDataProvider中定义的所有abstract方法,即实现了所有需要的数据访问方法。

分析users = dp.WhoIsOnline(pastMinutes)
既然访问数据的对象已经准备完毕了,users = dp.WhoIsOnline(pastMinutes)也就变成了仅仅是调用SqlDataProvider对象的方法而已了。
找到SqlDataProvider类的WhoIsOnline方法,即public override Hashtable WhoIsOnline(int pastMinutes)
这个方法其实就是调用存储过程forums_Users_Online,查看这个存储过程(这个存储过程有输入参数@PastMinutes,此处值为15)。
发现它首先会删除最近一个小时都没有Activity(活动)的在线用户信息,即:
    DELETE
        forums_UsersOnline
    WHERE
    LastActivity < DateAdd(hour, -1, GetDate())
然后根据表forums_UsersOnline中的数据找出最近15分钟有Activity(活动)注册会员信息,以及从表forums_AnonymousUsers中找出所有在线游客信息。

OK,对CnForum中在线用户信息统计的实现方式就分析到这里。
感言:阅读高手的代码的确是收益匪浅,写这个Post也希望能够起到抛砖引玉的效果,共同进步吧~


在分析的过程中难免有错误的地方,请见谅。 当然也欢迎大家扔砖..