PDA

View Full Version : مدیریت کاربران آنلاین(مقاله)



Saeed_Taghvaee
یک شنبه 06 فروردین 1385, 08:15 صبح
طی تحقیقاتی که اخیرا در سایت های مختلف انجام دادم ، توانستم متد صحیح کد نویسی برای بخش کاربران آنلاین را در Asp.Net تهیه کنم که با اجازه مدیران این بخش آن را به صورت مقاله ای برای این سایت می فرستم :
از ابتدا تا کنون روش های مختلفی برای بدست آوردن لیست کاربران آنلاین در سایت ها استفاده شده که مهم ترین آن ها استفاده از دیتا بیس و یا متغیر های Application بود که همگی نیاز اساسی به فایل Global.asax داشتند. این در حالی است که در بسیاری از هاستینگ های مجانی استفاده از این فایل پشتیبانی نمیشود و باعث ایجاد مشکلات فراوانی میشد.
از طرفی در روش استفاده از دیتا بیس نیز دو اشکال عمده وجود داشت که
1- فشار زیادی رو دیتا بیس وارد میشد که این اصلا به صلاح کیفیت یک سایت نیست .
2- سرعت لود صفحات با افزایش کاربران نیز به طبع پایین تر می آمد .
اما در روش زیر شما به هیچ فایلی حتی Web.config برای تنظیم TimeOut سشن ها و ... نیاز ندارید و میتوانید با بهترین خروجی و کارکرد منظم یک آمار بسیار دقیق از کاربران سایت داشته باشید .
در این روش از Cache به جای DataBase و همچنین از شی DataTable به جای جداول فیزیکی استفاده میشود و باعث میشود تا تغییر سرعت در هر وضعیتی از تعداد کاربران نداشته باشید و هیچ فشاری نیز بر روی دیتا بیس شما نباشد.
در پروژه خود یک فایل Class ایجاد کنید و ان را از System.Web.UI.Page مشتق کنید. و در کلاس خود یک فیلد عمومی به نام minut از نوع Int تعریف کنید و همچنین یک متد برای زیر روال لود صفحه تعریف کرده و آن را در InitializeComponent()ثبت نمایید. در حال حاضر کلاس شما همچین شکلی خواهد داشت.

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.Caching;

namespace WebSite5
{

public class Pages : System.Web.UI.Page
{
public int minut=5;
private void Page_Load(object sender, System.EventArgs e)
{

}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}

private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
همانطور که حتما فهمیدی قراره از این کلاس به جای System.Web.UI.Page در ارث بری صفحات استفاده شود و همگی صفحات از آن مشتق شوند به عبارت دیگر هر روتینی که در روال لود صفحه نوشته شود در هنگام لود همه صفحاتی که از آن مشتق میشوند نیز استفاده میشود.
در نتیجه این مکان قسمت مناسبی برای جایگزنی ساب روتین های مورد نیاز در فایل های Global.asax میباشد.
در حال حاضر ما میخواهیم در صورتی که کش (Cache) مورد نظر در سرور وجود نداشت یک کش ساده و خالی ایجاد کنیم و در آن اطلاعات کاربران را ثبت کنیم. همچنین در این قسمت میبایستی DataTable مورد نظر را نیز در Cache خود Add کنیم تا در صفحات دیگر از آن استفاده کنیم. بدین منظور یک متد بدون بازگشتی با نام loadCaching() در فایل خود با محتویات زیر وارد میکنیم :

public void loadCaching()
{
DataTable dt=new DataTable("UsersOnline");
DataColumn dcA=new DataColumn("UserIp",typeof(String));
DataColumn dcB=new DataColumn("UserId",typeof(String));
DataColumn dcC=new DataColumn("UserLastVisit",typeof(System.DateTime);
dt.Columns.Add(dcA);
dt.Columns.Add(dcB);
dt.Columns.Add(dcC);
System.Web.Caching.CacheItemRemovedCallback CloseUser;
CloseUser=new CacheItemRemovedCallback(Pages_CloseUser);
Cache.Add("UserOnlineList",dt,null,DateTime.Now.AddMinutes(2)
,System.Web.Caching.Cache.NoSlidingExpiration,Cach eItemPriority.Default,CloseUser);
}
همانطور که میبینید در متد بالا ابتدا پس از ایجاد یک DataTable سه Column به آن اضافه میکنیم که در یکی از این ها IP کاربر ذخیره میشود، در یکی از آن های نام کاربری کاربر ذخیره میشود و در آخرین فیلد نیز اخرین دسترسی کاربر به یکی از صفحات تعریف میشود .
سپس یک delegate از نوع System.Web.Caching.CacheItemRemovedCallback تعریف میکنیم و آن را با متد Pages_CloseUser (که بعدا متن آن را میگویم) ثبت میکنیم. اما مهم ترین قسمت این سیستم اخرین دستور آن می باشد. پارامتر های Cache.Add به ترتیب از قرار زیر خواهند بود :
اولین پارامتر :
نام مقداری که در دیتا کش سرور ذخیره میشود .
دومین پارامتر :
مقداری که باید در آن قسمت از دیتا کش سرور ذخیر شود(همان جدول خالی)ک
سومین پارامتر:
یک CacheDependency بار DataCache مورد نظر که چون اینجا لازم نیست میتوان مقدار null به آن پاس داد.
چهارمین پارامتر:
یک AbsoluteExpiration برای تعیین مدت زمان عمر این متغیر که می توان آن را با نوع DateTime تنظیم نمود ، این عمل در صورتی که دقیقا به تاریخ مورد نظر رسید دیتا کش را پاک میکند.
پنجمین پارامتر :
یک SlidingExpiration میباشد که کار پارامتر با لا با نوع TimeSpan انجام میدهد و پس از گذشت زمانی که توسط این مقدار تنظیم میشود دیتا کش را پاک میکند.
توجه : ماکرو سافت در MSDN خود اشاره داشته که همیشه از یک نوع از پارامتر اول یا دوم استفاده کنید و پارامتر بعدی را با یکی از انواع System.Web.Caching.Cache.NoSlidingExpiration (در صورت استفاده از پارامتر چهارم ) و یا
System.Web.Caching.Cache.NoAbsoluteExpiration (در صورت استفاده از پارامتر پنجم توصیه میکند) که همانطور که میبینید در بالا استفاده از DateTime ترجیح داده شده.
پارامتر ششم :
یک نوع از انوم(enum) System.Web.Caching.CacheItemPriority میباشد که تریجحا آن را با مقدار System.Web.Caching.CacheItemPriority.Default تنظیم کنید.
آخرین پارامتر :
اصلی ترین پارامتر این متد یک دلگیت میباشد که آن را هنگام از بین بردن DataCache و فرا رسیدن Expiration مورد نظر که در پارامتر های قبلی تنظیم کردم ، ارجا میکند. به عبارتی تمامی متد هایی که در این دلگیت ذخیر و پاس میشوند زمانی که عمر دیتا کش مورد نظر پایان میرسد اجرا میشود .
اما بخش بعد و مهم این سیستم متدی است که به آن دلگیت پاس داده بودیم (Pages_CloseUser) که متن آن در زیر آمده :

private void Pages_CloseUser(string key, object Value, CacheItemRemovedReason reason)
{
if(Value.GetType() is System.Data.DataTable && key=="UserOnlineList")
{
DataTable dt=(DataTable)Value;
for(int i=0;i!=dt.Rows.Count;i++)
{
if(((DateTime)dt.Rows[i]["UserLastVisit"]).Minute-minut < DateTime.Now.Minute-minut)
{
dt.Rows.RemoveAt(i);
}
}
System.Web.Caching.CacheItemRemovedCallback CloseUser;
CloseUser=new CacheItemRemovedCallback(Pages_CloseUser);
Cache.Add("UserOnlineList",dt,null,DateTime.Now.AddMinutes(2), System.Web.Caching.Cache.NoSlidingExpiration,Cache ItemPriority.Default,CloseUser);
}
همانطور که میبینید ابتدا چک میشود که واقعا آیتم در حال نابود شدن همان جدول مورد نظر بوده یا خیر و حال در صروتی که آن جدول بود ابتدا آن را با استفاد از TypeCasting بازیابی میکنیم. سپس تمامی سطرها ی جدول که توسط قسمتی دیگر از این کد پاس میشود رو چک میکنیم.
در صورتکی که سطر مورد نظر (که همون کاربر مورد نظر میباشد) چیزی بیشتر از زمانی که ما تعیین کردیم در سایت حاضر نبود آن را از لیست خود حذف میکنیم.
در انتها دوباره جدول را در دیتا کش به همان روش بالا ذخیره می کنیم.
عمدتا این الگوریتم تا بی نهایت تکرار میشود و هر وقت که زمان آخرین بازدید کاربر مورد نظر از زمان تعیین شده بیشتر شد آن کاربر را از لیست اعضا حذف میکنیم. و دوباره لیست را ذخیره کرده و 2 دقیقه بعد آن را چک میکنیم . (به همین سادگی !)
اما بریم سراغ روال لود صفحه :
آنجا ابتدا چک میکنیم که اگر دیتا کش مورد نظر ست نشده بود ، آن متدی که در بالا نوشتیم را اجرا میکنیم تا یک جدول خالی در دیتا کش ذخیره شود.

private void Page_Load(object sender, System.EventArgs e)
{
if(Cache["UserOnlineList"]==null)
{
this.loadCaching();
}

{
اما اصلی ترین قسمت این کد زمانی است که میخواهیم کاربران را به لیست اضافه کنیم.
روال دیگری در کد خود به نام Check_Session() ایجاد کنید و متن زیر را در آن وارد کنید :

public void Check_Session()
{
String dd=Session["User"].ToString();
DataTable dt=(DataTable)Cache["UserOnlineList"];
string filter="UserIp='"+Request.UserHostAddress+"'";
int cc=dt.Select(filter).Length;
filter="UserId='"+dd+"'";
int vv=dt.Select(filter).Length;
if(vv==0 && cc==0)
{
DataRow dr=dt.NewRow();
dr["UserIp"]=Request.UserHostAddress;
dr["UserId"]=dd;
dr["UserLastVisit"]=DateTime.Now;
dt.Rows.Add(dr);
}
else
{
for(int i=0;i!=dt.Rows.Count;i++)
{
if(dt.Rows[i]["UserId"].ToString()==dd && dt.Rows[i]["UserIp"].ToString()==Request.UserHostAddress)
{
dt.Rows[i]["UserLastVisit"]=DateTime.Now;
}
}

}
}
(در این روال فرض شده شما نام کاربر اعضای سایت خود را در سشن User ذخیر می کنید.)
ابتدا نام کاربری را از سشن میگیریم. سپس جدول را از دیتا کش بازیابی میکنیم. در جدول موجود در دیتا کش با استفاده از متد Select جست و جو میکنیم که آیا کاربری با نام و Ip در لیست وجود دارد یا خیر.
اگر کاربر موجود نبود در جدول یک سطر جدید باز کرده و در آن نام و زمان و ای پی کاربر را مینویسیم. اما اگر همچین کاربری در لیست موجود بود زمان آخرین بازدیدش را به زمان حال تغییر میدهیم تا در دیتا کش نام کاربریش اش از بین نرود.
در نهایت روال لود صفحه بدین شکل خواهد بود :

private void Page_Load(object sender, System.EventArgs e)
{
if(Cache["UserOnlineList"]==null)
{
this.loadCaching();
}else
{
if(Session["User"]!=null)
{
Check_Session();
}
}
}
خب فایل مورد نظر که تمامی صفحات در آن نوشته میشوند به شکل زیر میشود :

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.Caching;

namespace WebSite5
{
public class Pages : System.Web.UI.Page
{
public int minut=5;
private void Page_Load(object sender, System.EventArgs e)
{
if(Cache["UserOnlineList"]==null)
{
this.loadCaching();
}else
{
if(Session["User"]!=null)
{
Check_Session();
}
}
}
public void Check_Session()
{
String dd=Session["User"].ToString();
DataTable dt=(DataTable)Cache["UserOnlineList"];
string filter="UserIp='"+Request.UserHostAddress+"'";
int cc=dt.Select(filter).Length;
filter="UserId='"+dd+"'";
int vv=dt.Select(filter).Length;
if(vv==0)
{
DataRow dr=dt.NewRow();
dr["UserIp"]=Request.UserHostAddress;
dr["UserId"]=dd;
dr["UserLastVisit"]=DateTime.Now;
dt.Rows.Add(dr);
}
else
{
for(int i=0;i!=dt.Rows.Count;i++)
{
if(dt.Rows[i]["UserId"].ToString()==dd && dt.Rows[i]["UserIp"].ToString()==Request.UserHostAddress)
{
dt.Rows[i]["UserLastVisit"]=DateTime.Now;
}
}

}
}
public void loadCaching()
{
DataTable dt=new DataTable("UsersOnline");
DataColumn dcA=new DataColumn("UserIp",typeof(String));
DataColumn dcB=new DataColumn("UserId",typeof(String));
DataColumn dcC=new DataColumn("UserLastVisit",typeof(System.DateTime));
dt.Columns.Add(dcA);
dt.Columns.Add(dcB);
dt.Columns.Add(dcC);
System.Web.Caching.CacheItemRemovedCallback CloseUser;
CloseUser=new CacheItemRemovedCallback(Pages_CloseUser);
Cache.Add("UserOnlineList",dt,null,DateTime.Now.AddMinutes(2) ,System.Web.Caching.Cache.NoSlidingExpiration,Cach eItemPriority.Default,CloseUser);
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{ InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion

private void Pages_CloseUser(string key, object Value, CacheItemRemovedReason reason)
{
if(Value.GetType() is System.Data.DataTable && key=="UserOnlineList")
{
DataTable dt=(DataTable)Value;
for(int i=0;i!=dt.Rows.Count;i++)
{
if(((DateTime)dt.Rows[i]["UserLastVisit"]).Minute-minut < DateTime.Now.Minute-minut)
{
dt.Rows.RemoveAt(i);
}
}
System.Web.Caching.CacheItemRemovedCallback CloseUser;
CloseUser=new CacheItemRemovedCallback(Pages_CloseUser);
Cache.Add("UserOnlineList",dt,null,DateTime.Now.AddMinutes(2)
,System.Web.Caching.Cache.NoSlidingExpiration,Cach eItemPriority.Default,CloseUser);
}
}
}
}خب، حالا هر صفحه ای رو که میخواهید میتوانید براحتی دیتا کش را با TypeCasting به دیتا تیبل تبدیل کرده و داده های خود را نمایش دهید.
فقط یادتون باشه که وقتی میخواهید سشن یوزرتون رو ست کنید بعد از ست کردن روال Check_Session() را بعدش اجرا نمایید که لیست همیشه آپ دیت بمونه.
اگه نکته یا سوال دیگه ای بود در همین تایپیک مطرح کنید ، من در خدمتم.

mahdi_negahi
یک شنبه 06 فروردین 1385, 09:20 صبح
جالب و کامل بود مرسسسسسسسسسسسی

manager
یک شنبه 06 فروردین 1385, 10:01 صبح
ageh mishe in maghale ro be soorate PDF ya CHM dar biarid ta mellat download konan !!

Saeed_Taghvaee
یک شنبه 06 فروردین 1385, 10:19 صبح
درود !
والا متاسفانه من pdf_Convertor یا pdf_Writer ندارم وگرنه حتما این کارو میکردم !!
راستی یک نکته راجع به این سیستم بگم که میشه به سادگی با این سیستم چک کرد که مثلا چند کار بر دارند فلان موضع یا فلان صفحه رو میخونند و همچنین اگه کسی بخواد بفهمه کسی که از سیستم سایت بیرون رفته لاگ اوت کرده یا دی سی شده با این راه هم میتونه به سادگی (با نوشتن کد در روال Page_CloseUser) متوجه بشه.
در ضمن سورس کلی و نهایی رو که آخرش براتون گذاشتم کاملا تست شده (کلاینت) و تونسته در آنی که کاربر خارج شد دست کم بعد از 2 دقیقه سطر مربوط به اونو از دیتا بیس خارج کنه.

mahdi_negahi
یک شنبه 06 فروردین 1385, 10:55 صبح
من این مقاله را تبدیل به PDF کردم البته کد را هم خوشگل کردم
:چشمک:

kasra515
یک شنبه 06 فروردین 1385, 11:43 صبح
آفرین سعید جان ! بازم مارو خوشحال کردی ! :بوس:
از mahdi_negahi هم به خاطر pdf کردن تشکر می کنم !:چشمک:

amirjan
یک شنبه 06 فروردین 1385, 14:08 عصر
خیلی ممنون سعید ! :بوس:

nazaninam
یک شنبه 06 فروردین 1385, 17:22 عصر
اگه کسی این پرژه رو به vb.net تبدیل کرده لطف کنه بگذاره...بقیه هم استفاده کنن من نتونستم convert کنم

ar_monti@
چهارشنبه 27 تیر 1386, 11:58 صبح
سلام دوستان
ممنون از این همه اطلاعات خوب شما . چون من تازه کارم میخواستم بدونم چگونه اطلاعات UserIP , UserID را روی صفحه نمایش دهم.
ممنون

mehrdad_t
چهارشنبه 27 تیر 1386, 14:27 عصر
مقاله جالبی بود

اگر ممکنه مطلبی هم در مورد گرفتن تعداد کاربران آنلاین و کاربران لاگین نکرده بنویسید

مثل همین سایت :

کاربران فعال حاضر: 157 (51 کاربر و 106 مهمان)

کمی بیشتر در مورد گرفتن تعداد کاربران مهمان توضیح بدبد

قثط هم برای هاست هایی که از فایل Global.aspx.cs پشتیبانی نمی کنند توضیح ندید .

mehrdad201
پنج شنبه 12 مهر 1386, 14:52 عصر
دوست عزیز

من از کلاس فایل شما استفاده کردم اما موقع کمپایل ارور زیر رو دریافت می کنم

روی this.loadCaching();

Error 1 'login' does not contain a definition for 'loadCaching' C:\SignalsDemo\login.aspx.cs 21 18 C:\SignalsDemo\

و روی Check_Session();
Error 2 The name 'Check_Session' does not exist in the current context C:\SignalsDemo\login.aspx.cs 27 17 C:\SignalsDemo\


لطفا یکی به من بگه واسه حل این مشکلات باید چه کار کنم ؟!؟!؟!

irdelta
پنج شنبه 19 مهر 1386, 16:18 عصر
من از این کلاس استفاده کردم ولی توی ایجاد کش ارور میده چیکار کنم


Server Error in '/amirheydari' Application.

Cache is not available

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Web.HttpException: Cache is not available

Source Error:

Line 69: System.Web.Caching.CacheItemRemovedCallback CloseUser;Line 70: CloseUser = new CacheItemRemovedCallback(Pages_CloseUser);Line 71: Cache.Add("UserOnlineList",dt,null,DateTime.Now.AddMinutes(2),System.Web.Cac hing.Cache.NoSlidingExpiration,CacheItemPriority.N ormal,CloseUser ); Line 72: }Line 73: #region Web Form Designer generated code
Source File: c:\Inetpub\wwwroot\amirheydari\App_Code\Class1.cs Line: 71

Stack Trace:

[HttpException (0x80004005): Cache is not available] System.Web.UI.Page.get_Cache() +2025393 WebSite5.Pages.loadCaching() in c:\Inetpub\wwwroot\amirheydari\App_Code\Class1.cs: 71 Default_aspx.Page_Load(Object sender, EventArgs e) in c:\Inetpub\wwwroot\amirheydari\Default.aspx.cs:18 System.Web.Util.CalliHelper.EventArgFunctionCaller (IntPtr fp, Object o, Object t, EventArgs e) +15 System.Web.Util.CalliEventHandlerDelegateProxy.Cal lback(Object sender, EventArgs e) +34 System.Web.UI.Control.OnLoad(EventArgs e) +99 System.Web.UI.Control.LoadRecursive() +47 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1061

Version Information: Microsoft .NET Framework Version:2.0.50727.42; ASP.NET Version:2.0.50727.42

ebrahimhoze
پنج شنبه 19 مهر 1386, 19:03 عصر
ما که vb بلدیم تکلیف چیه

ali_reza_nazari
دوشنبه 30 مهر 1386, 23:47 عصر
مشکل من هم همینه
وی بی

Neo Persian
سه شنبه 01 آبان 1386, 19:03 عصر
از converter ها استفاده کنید

http://www.developerfusion.co.uk/utilities/convertvbtocsharp.aspx

nkhozooii
پنج شنبه 22 آذر 1386, 16:56 عصر
مقاله بسیار در خور توجه ای بود. از دوست گرامی که محبت کردند و تجربیات خود را در اختیارمان قرار دادند تشکر می کنم. فقط اگر ممکن است نحوه کامل فراخوانی آن را در صفحه اصلی توضیح دهند تا بتوانیم از آن استفاده نماییم.