فصل ششم : بكار گيري global.asax و بحثهاي ا ماري سايت مقدمه : يكي از فايلهايي كه همواره توسط VS.NET به صورت خودكار ايجاد مي شود global.asax است و براي تعريف اشياء عمومي كه برنامه ي وب از ا نها استفاده مي كند بكار مي رود. از اين فايل براي مديريت پردازش هايي در سطوح بالاتر برنامه مانند Application_Start و Application_End وغيره استفاده مي شود. اين فايل در مرورگر وب توسط ساير كاربران قابل اجرا و مشاهده نيست. لازم به ذكر است كه استفاده از اين فايل اختياري بوده و در صورت نياز از ا ن استفاده مي شود. شرح رخدادهاي تعريف شده درون : global.asax : Application_Init اين رويداد هر بار كه يك شيءجديد از HttpApplication ساخته مي شود اجرا مي گردد. كدهاي ا غاز گر را مي توان در اين قسمت تعريف كرد. : Application_Disposed اين رويداد درست قبل از تخريب هر شيء ايجاد شده از HttpApplication فراخواني مي گردد. عموما از ا ن براي پاكسازي منابع تخصيص داده شده استفاده مي گردد. 1 استاد دوره : وحيد نصيري
: Application_Error هنگاميكه خطايي مديريت نشده رخ مي دهد اين رويداد فراخواني مي گردد. : Application_Start اين رخداد تنها يكبار در طول عمر برنامه ي وب اتفاق مي افتد و ا ن هنگامي است كه اولين شيء HttpApplication ساخته مي شود. از اين رخداد براي براي به اشتراك گذاشتن يك شيء در بين تمام سشن ها استفاده مي شود. در اين رخداد متغييرهاي محلي را تعريف نكنيد زيرا متغيرهاي محلي بين اشياء HttpApplication به اشتراك گذاشته نمي شوند. : Application_End اين رخداد تنها يكبار ا نهم هنگاميكه ا خرين شيء HttpApplication تخريب مي شود اتفاق مي افتد. از اين رخداد براي پاكسازي اشياء به اشتراك گذاشته شده مي توان استفاده كرد. : Application_BeginRequest اين رخداد اولين رخدادي است كه ASP.NET هنگاميكه به يك درخواست پاسخ مي دهد اتفاق مي افتد. : Application_EndRequest اين رخداد ا خرين رخدادي است كه ASP.NET هنگاميكه به يك درخواست پاسخ مي دهد اتفاق مي افتد. : Application_PreRequestHandlerExecute اين رخداد درست قبل از اجراي يك اداره كننده (Handler) مانند صفحه يا web service رخ مي دهد. در اين زمان سشن مهيا شده است. : Application_PostRequestHandlerExecute اين رخداد زماني اتفاق مي افتد كه يك اداره كننده اجرايش خاتمه مي يابد. 2 استاد دوره : وحيد نصيري
: Application_PreSendRequestHeader اين رخداد درست قبل از فرستاده شدن HttpHeaders به كلاينت ها رخ مي دهد. : Application_PreSendRequestContext اين رخداد درست قبل از اينكه ASP.NET محتويات صفحه را به كلاينت ها بفرستد رخ مي دهد. : Application_AcquireRequestState اين رخداد هنگامي اتفاق مي افتد كه ASP.NET وضعيت جاري را ذخيره مي كند (مانند وضعيت سشن مربوط به درخواست جاري). : Application_ReleaseRequestState اين رخداد هنگامي اتفاق مي افتد كه ASP.NET اجراي تمامي اداره كننده هاي درخواست ها را تمام كرده است. اين رخداد سبب مي شود كه ماژولهاي حالت داده هاي وضعيت جاري را ذخيره كنند. : Application_ResolveRequestCache اين رخداد هنگامي اتفاق مي افتد كه ASP.NET رخداد تعيين اعتبار را تمام كرده است و اجازه مي دهد به ماژولهاي caching تا اجراي اداره كننده ها را متوقف كرده و خود اراي ه ي سرويس نمايند. اين مورد سبب بالارفتن كارا يي سايت مي گردد و مي توان با استفاده از ا ن قضاوت كرد كه ا يا محتويات از Cache خوانده مي شوند يا خير : Application_UpdateRequestCache اين رخداد هنگامي اتفاق مي افتد ASP.NET اجراي يك اداره كننده را تمام مي كند و به ماژولهاي Caching اجازه مي دهد تا مواردي را كه بايد در درخواست هاي بعدي از Cache خوانده شوند ذخيره كنند. 3 استاد دوره : وحيد نصيري
: Application_AuthenticationRequest است. اين رخداد هنگامي رخ مي دهد كه ماژول امنيتي مشخص مشخص كرده است كه كاربر جاري معتبر : Application_AuthorizeRequest اين رخداد هنگامي رخ مي دهد كه ماژول امنيتي مشخص كرده است كه كاربر تعيين اعتبار شده مجوز دسترسي به منابع را دارد يا خير : Session_Start اين رخداد هر بار كه يك كاربر جديد به وب سايت دسترسي پيدا مي كند فراخواني مي گردد. : SessionEnd اين رخداد هنگاميكه سشن يك كاربر زمانش تمام مي شود و يا خاتمه مي يابد فراخواني مي گردد. ترتيب رويدادن رخدادهاي ذكر شده در سطح : Application - BeginRequest - AuthenticateRequest - AuthorizeRequest - ResolveRequestCache - AcquireRequestState - PreRequestHandlerExecute - PreSendRequestHeaders - PreSendRequestContent - (actual processing) - PostRequestHandlerExecute - ReleaseRequestState - UpdateRequestCache - EndRequest 4 استاد دوره : وحيد نصيري
اين ترتيبي است كه رويدادهاي نامبرده شده يكي پس از ديگري اتفاق مي افتند. منشاء ا نها شيء HttpApplication و يا شيء HttpModule است كه در Web.Config و يا Machine.Config تعيين مي شوند. مثال : ۱ يك پروژه جديد وب اپليكيشن را ا غاز نماييد و سپس كد زير را در فايل global.asax ا ن بنويسيد: using System; using System.Collections; using System.ComponentModel; using System.Web; using System.Web.SessionState; namespace ex01 /// <summary> /// Summary description for Global. /// </summary> public class Global : System.Web.HttpApplication public Global() InitializeComponent(); protected void Application_Start(Object sender, EventArgs e) Application["Hits"] = 0; Application["Sessions"] = 0; Application["TerminatedSessions"] = 0; protected void Session_Start(Object sender, EventArgs e) Application.Lock(); Application["Sessions"] = (int) Application["Sessions"] + 1; Application.UnLock(); //The BeginRequest event is fired for every hit to every page in the site protected void Application_BeginRequest(Object sender, EventArgs e) Application.Lock(); Application["Hits"] = (int) Application["Hits"] + 1; Application.UnLock(); 5 استاد دوره : وحيد نصيري
protected void Application_EndRequest(Object sender, EventArgs e) protected void Application_AuthenticateRequest(Object sender, EventArgs e) protected void Application_Error(Object sender, EventArgs e) protected void Session_End(Object sender, EventArgs e) Application.Lock(); Application["TerminatedSessions"] = (int) Application["TerminatedSessions"] + 1; Application.UnLock(); protected void Application_End(Object sender, EventArgs e) //Write out our statistics to a log file //...code omitted... #region Web Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() #endregion اكنون در رويداد page_load وب فرم كد زير را براي نمايش ا مار سايت بنويسيد: private void Page_Load(object sender, System.EventArgs e) Response.Write("<h2> Statistics for the Test Web Application </h2>"); Response.Write(" Total hits: "); Response.Write(Application["Hits"].ToString()); Response.Write("<br> Total sessions:"); Response.Write(Application["Sessions"].ToString()); Response.Write("<br> Expired sessions:"); 6 استاد دوره : وحيد نصيري
Response.Write(Application["TerminatedSessions"].ToString()); كد فوق رخدادهايي را كه تاكنون بررسي كرده ايم را به شكلي عملي نمايش مي دهد. همانطور كه پيش تر نيز ذكر شد BeginRequest هر بار كه صفحه مشاهده مي شود اتفاق مي افتد و از ا ن براي نوشتن Hit Counter ها مي توان استفاده نمود. هنگاميكه صفحه اجرا شد ا نرا چندبار ريفرش كنيد تا نتيجه را ملاحظه نماييد. براي اينكه چيزي شبيه به قسمت line? Who is on را كه در اكثر فوروم ها مي توان مشاهده كرد ايجاد نماييم مي توان از Session_Start و End استفاده كرد. با استفاده از اين رخدادها مي توان دريافت كه چه نوع كاربران متفاوتي به سايت رجوع كرده اند. با كمي توسعه ي كد فوق مي توان بحث هاي ا ماري جالبي را درسايت پديد ا ورد. شكل ۱ نمايي از اجراي برنامه ي نمايش دهنده ي ا مار سايت. 7 استاد دوره : وحيد نصيري
نكته : اگر فايل global.asax تغيير كند برنامه ي وب Restart خواهد شد و تمام مقادير ذخيره شده ي ا ن صفر خواهند شد. اضافه كردن اشياء به فايل : Global.asax براي اين منظور كلاسي ساده را اضافه مي كنيم كه رشته ها را دريافت و ذخيره كند. از شيء Application براي اينكار مي خواهيم استفاده نماييم بنابراين كلاس بايد Thread-safe باشد. معناي Thread-Safe اين است كه تعداد زيادي از كلاينت ها مي توانند به كلاس بدون تخريب داده هاي ا ن دسترسي داشته باشند. از ا نجاي يكه ASP.NET يك Thread را به ازاي هر صفحه بكار مي برد اطمينان حاصل كردن از Thread-safe بودن كلاس اگر چندين كاربر در يك زمان به سايت مراجعه نمايند بسيار مهم و بحراني است. براي اطمينان حاصل كردن از اين امر از روش Synchrinozation (همزماني) استفاده مي شود كه مربوط است به كلاس. Hashtable مثال ۲: يك پروژه ي وب اپليكيشن جديد را ا غاز نماييد. سپس از منوي پروژه يك كلاس جديد به نام MyClass را به برنامه اضافه نموده و كد زير را در ا ن بنويسيد. using System; using System.Collections; // for Hashtable namespace ex02 /// <summary> /// Summary description for MyClass. /// </summary> public class MyClass private Hashtable m_col; 8 استاد دوره : وحيد نصيري
//m_colsync will be a thread-safe container for m_col private Hashtable m_colsync; public MyClass() m_col = new Hashtable(); m_colsync = Hashtable.Synchronized(m_col); public void AddItem(String Name, String Value) m_colsync[name] = Value; public String GetItem(String Name) return (String) m_colsync[name]; سپس كد زير را به فايل global.asax اضافه نماييد: protected void Application_Start(Object sender, EventArgs e) MyClass m_var = new MyClass(); m_var.additem("firstuser", "Vahid"); Application["myVar"]=m_var; حوضه ي ديد يك شيء در اين فايل مي تواند Session Application و يا AppInstance باشد. در حالتي كه حوضه ي ديد AppInstance باشد فقط به يك نمونه از HttpApplication مربوط شده و به اشتراك گذاشته نمي شود. متغير هاي تعريف شده توسط شيء Session فقط براي يك كاربر در طول سشن او معتبر هستند و متغيرهاي تعريف شده توسط شيء Application در دسترس تمام كاربران سايت مي باشد. صفحه ي وب زير از اين شيء استفاده مي كند: private void Page_Load(object sender, System.EventArgs e) MyClass m_var = new MyClass(); m_var = (MyClass) Application["myVar"]; Response.Write(m_var.GetItem("FirstUser")); 9 استاد دوره : وحيد نصيري
مثال ۳: بهترين مكان براي نوشته شدن يك سري از رخدادهاي برنامه در Event log سيستم (شخصي) است و يا سروري كه دسترسي به يك سري از منابع ا ن براي شما تعريف شده است. براي اين منظور يك پروژه ي وب اپليكيشن جديد را ا غاز كرده و سپس به كد زير دقت فرماييد: using System; using System.Collections; using System.ComponentModel; using System.Web; using System.Web.SessionState; using System.Diagnostics; namespace ex03 /// <summary> /// Summary description for Global. /// </summary> public class Global : System.Web.HttpApplication public Global() InitializeComponent(); protected void Application_Start(Object sender, EventArgs e) EventLog.WriteEntry("Sample Application", "Application Started!", EventLogEntryType.Information); protected void Session_Start(Object sender, EventArgs e) Session.Contents.Add("TimeStart", DateTime.Now); protected void Application_Error(Object sender, EventArgs e) EventLog.WriteEntry("Sample Application", "Application Error Occured!", EventLogEntryType.Error); protected void Application_End(Object sender, EventArgs e) EventLog.WriteEntry("Sample Application", "Application Ended!", EventLogEntryType.Warning); #region Web Form Designer generated code 10 استاد دوره : وحيد نصيري
/// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() #endregion شكل ۲- مواردي را كه تاكنون در برنامه و در Global.asax بكار برديم مي توان در Clipbiard Ring جعبه ابزار استاندارد VS.NET نيز مشاهده نمود. 11 استاد دوره : وحيد نصيري
ممكن است بار اول در هنگام اجراي كد فوق با خطاي زير مواجه شويد كه به تنظيمات امنيتي سيستم مربوط مي گردد: Security Exception Description: The application attempted to perform an operation not allowed by the security policy. To grant this application the required permission please contact your system administrator or change the application's trust level in the configuration file. Exception Details: System.Security.SecurityException: Requested registry access is not allowed. شكل ۳- براي مشاهده ي رخدادهاي ثبت شده مي توان به Server explorer مراجعه نمود و قسمت Event logs را بررسي كرد. اضافه كردن رخدادهاي سفارشي به : global.asax علاوه بر رخدادهاي تعريف شده و استاندارهاي فوق ما نيز مي توانيم رخدادهايي را براي فايل global.asax تعريف كنيم. اينكار از طريق HttpModule به صورت زير انجام مي شود: 12 استاد دوره : وحيد نصيري
مثال : ۴ پروژه ي وب اپليكيشن جديدي را ا غاز نموده و سپس يك كلاس جديد به ا ن به نام SyncModule.cs اضافه نماييد. محتويات اين كلاس به صورت زير است: using System; using System.Web; namespace ex04 public class SyncModule : IHttpModule public delegate void MyEventHandler(Object s, EventArgs e); private MyEventHandler _eventhandler = null; public SyncModule() public void Init(HttpApplication app) app.beginrequest += new EventHandler(OnBeginRequest); public void Dispose() public event MyEventHandler MyEvent add _eventhandler += value; remove _eventhandler -= value; public void OnBeginRequest(Object s, EventArgs e) HttpApplication app = s as HttpApplication; app.context.response.write( "Hello from OnBeginRequest in custom module.<br>"); if(_eventhandler!=null) _eventhandler(this, null); در ادامه كد زير را در رخداد Page_Load مربوط به وب فرم بنويسيد: 13 استاد دوره : وحيد نصيري
private void Page_Load(object sender, System.EventArgs e) Response.Write("Hello from Test.aspx.<br>"); سپس فايل وب كانفيگ را در برنامه گشوده و كد زير را به ا ن اضافه نماييد: <httpmodules> < "add name="mymodule" type="ex04.syncmodule, ex04/> </httpmodules> فايل global.asax را گشوده و كد زير را در ا ن بنويسيد: protected void MyModule_OnMyEvent(Object src, EventArgs e) Context.Response.Write( "Hello from MyModule_OnMyEvent called in Global.asax.<br>"); برنامه را اجرا نماييد. استفاده از Context در : Global.asax به صورت پيش فرض اشياء Request Response و Page تعريف شده در كلاس HttpApplication در فايل global.asax قابل دستيابي نيستند. از Context براي اين منظور استفاده مي شود. مثال ۵: يك پروژه ي وب اپليكيشن جديد را ا غاز نماييد و سپس كد زير را در فايل Global.asax ا ن بنويسيد: protected void Application_Start(Object sender, EventArgs e) Application["SessionCounter"]=0; 14 استاد دوره : وحيد نصيري
protected void Session_Start(Object sender, EventArgs e) /// Fires when the session is started Application.Lock(); Application["SessionCounter"] = (int)application["sessioncounter"]+1; Application.UnLock(); Context.Response.Write("No of session(s): "+Application["SessionCounter"]); 15 استاد دوره : وحيد نصيري
تمرين: ۱- يك Hit Counter را با ديتابيس اكسس طراحي نماييد. ۲- بر مبناي اطلاعات از ۵ دقيقه پيش تا كنون يوزر كنترلي را طراحي كنيد كه كاربران وارد شده به سايت را نمايش دهد. 16 استاد دوره : وحيد نصيري