HttpModule چیست:
در ASP.NET پردازش هر درخواست دارای مراحل یا فازهای مختلف است و در هر فاز رویدادهای مشخصی وجود دارد که با استفاده از HttpModuleها میتوانیم در این فرآیند تغییراتی ایجاد کنیم. به عنوان مثال می توانیم در اینجا عملیات لاگ کردن درخواستها، اعتبار سنجی درخواستها، بازنویسی Urlها و ... را به یک برنامه ASP.NET اضافه کنیم. برای مشاهده لیست این رویدادها و توضیحات بیشتر در این مورد اینجا را ببینید. در این مقاله برای سادگی بیشتر من فقط به دو تا از مهمترین رویدادها اشاره میکنم. این دو رویداد، BeginRequest (در لحظه دریافت درخواست توسط سرور) و EndRequest (پس از خاتمه پردازش درخواست توسط سرور) هستند و من در چند مثال موجود در این مقاله فقط از همین دو رویداد استفاده کرده ام.
شیوه نوشتن یک HttpModule:
یک HttpModule کلاسی است که از IHttpModule ارثبری میکنید و دو متد Init و Dispose را پیاده سازی میکند. همانطور که از اسم این دو متد مشخص است، در متد Init کارهای اولیه و آماده سازی HttpModule انجام میشود و در متد Disposeهرگونه آزاد سازی منابع که مورد نیاز است انجام میشود.
بسیاری از اوقات در متد Dispose کد خاصی نوشته نمیشود اما در متد Init باید رویدادهایی که میخواهیم از آنها استفاده کنیم را مشخص کنیم. پارامتر ورودی متد Init یک شئ از نوع HttpApplication است که اطلاعات Application جاری را در خود دارد و اتصال رویدادها از طریق آن انجام میشود. به عنوان مثال به کد نمونه زیر توجه کنید:
| class SampleHttpModule : IHttpModule { public void Dispose(){} public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(context_BeginRequest); context.EndRequest += new EventHandler(context_EndRequest); }
void context_BeginRequest(object sender, EventArgs e) { //handle BeginRequest here... } void context_EndRequest(object sender, EventArgs e) { //handle EndRequest here... } } |
همانطور که در کد بالا مشاهده میشود، هر کدام از رویدادهای BeginRequest و EndRequest دارای دو پارامتر ورودی هستند که پارامتر اول (در اینجا sender) همان شئ HttpApplication است که برای دسترسی به اطلاعات درخواست، تغییر پاسخ سرور، دسترسی به Cache، دسترسی به Session و ... از این شئ استفاده میکنیم.
به عنوان مثال فرض کنیم که میخواهیم در انتهای هرکدام از صفحات سایت یک پیغام اضافه کنیم. همانطور که حدس میزنید، برای این کار از رویداد EndRequest میتوانیم استفاده کنیم. البته دقت کنید که یک HttpModule برای تمام درخواستها فراخوانی خواهد شد، پس در کد مورد نظر، باید حتما بررسی کنیم که در صورتی که درخواست صورت گرفته برای یک صفحه (Page) بوده این متن را به انتهای درخواست اضافه کنیم. بنابراین برای این مثال به شئ Response (برای نوشتن اطلاعات در آن) و شئ Context (برای بررسی Handler آن که نشاندهنده Handler استفاده شده برای درخواست جاری است) نیاز داریم.
نکته: در صورتی که با بحث HttpHandler آشنایی ندارید، پیشنهاد میکنم در این مورد نیز مطالعه کنید ولی برای الان فقط این را بدانید که اگر درخواست یک صفحه عادی دریافت شده باشد، Handler از نوع System.Web.UI.Page خواهد بود.
بنابراین کد کامل مورد نظر برای این ماژول به صورت زیر خواهد بود:
| namespace MyApplication { class SampleHttpModule : IHttpModule { public void Dispose() { } public void Init(HttpApplication context) { context.EndRequest += new EventHandler(context_EndRequest); } void context_EndRequest(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; if (application.Context.Handler is System.Web.UI.Page) { application.Response.Write("<hr>This works!"); } } } } |
شیوه استفاده از یک HttpModule:
تا اینجا نحوه نوشتن یک HttpModule را دیدیم. بعد از نوشتن یک HttpModule برای استفاده از آن باید این HttpModule را در فایل web.config معرفی کنیم تا از این به بعد سرور در هنگام اجرای رویدادهای مورد نظر، HttpModule ما را نیز دخالت دهد! تنظیمات مورد نیاز برای این کار بسته به نسخه IIS که استفاده میکنیم متفاوت است.
در IIS 6 و قبل از آن، (ویندوز 2003 و قبل از آن) برای استفاده از یک HttpModule آن را در بخش httpModules (در قسمتsystem.web) قرار میدهیم و در IIS 7 به بعد (ویندوز 2008 به بعد) برای این کار از بخش modules (در قسمتsystem.webServer) استفاده میکنیم. به عنوان مثال برای اضافه کردن ماژول مثال بالا در IIS 6 تنظیمات فایل web.config را به این صورت انجام میدهیم:
| <configuration> <system.web> <httpModules> <add name="SampleHttpModule" type="MyApplication.SampleHttpModule"/> </httpModules> </system.web> </configuration> |
برای IIS 7 تنظیمات به این صورت انجام میشود:
| <configuration> <system.webServer> <modules> <add name="SampleHttpModule" type="MyApplication.SampleHttpModule"/> </modules> </system.webServer> </configuration> |
نکته: اگر هر دو قسمت ذکر شده را در فایل web.config اضافه کنیم (به عنوان مثال در حالتی که بخواهیم یک فایلweb.config در هر دو حالت IIS 6 و IIS 7 کار کند) در IIS 7 با خطا روبرو میشویم که برای رفع این خطا میتوانیم از تگvalidation (در قسمت system.webServer) با ویژگی validateIntegratedModeConfiguration=false استفاده کنیم. به عنوان مثال فایل web.config مورد نیاز برای مثال قبلی در این حالت به این صورت خواهد شد:
| <configuration> <system.web> <httpModules> <add name="SampleHttpModule" type="MyApplication.SampleHttpModule"/> </httpModules> </system.web> <system.webServer> <validation validateIntegratedModeConfiguration="false" /> <modules> <add name="SampleHttpModule" type="MyApplication.SampleHttpModule"/> </modules> </system.webServer> </configuration> |
استفاده از HttpModule در مقابل استفاده از Global.asax
احتمالا برای بسیاری از شما این سوال پیش آمده است که ظاهرا کارهایی که توسط HttpModule قابل انجام است، توسطGlobal.asax نیز میتوان انجام داد، پس استفاده از HttpModule واقعا چه لزومی دارد؟ جواب کوتاه برای این سوال این است که شما میتوانید یک HttpModule را به صورت یک فایل dll جدا تهیه کنید و بدون کد نویسی مجدد، در تمام سایتهای خود مورد استفاده قرار دهید ولی اگر از Global.asax استفاده کنید، مجبور خواهید شد برای اضافه کردن هرکدام از قابلیتهای ذکر شده، کد سایت خود را تغییر دهید و احتمالا دوباره آن را کامپایل کنید. البته تفاوتهای دیگری نیز وجود دارد که برای این مبحث کوتاه در همین حد کافی است.
● نحوه پیاده سازی در پروژه :
مقدمه:
یکی از مشکلات زبان فارسی در صفحات وب، وجود استانداردهای متفاوت برای کدهای حروف و صفحهکلید میباشد که خوشبختانه با جا افتادن استاندارد 2901 و در ادامه آن استانداردهای 6219 و 9147 تا حدودی سر و سامان گرفته است. مشکل اینجاست که هنوز هم کاربران زیادی هستند که صفحه کلید آنها به صورت استاندارد نیست و بیشترین مشکل هم در حروف ی و ک وجود دارد که در بسیاری موارد به اشتباه به صورت عربی آن (ی و ک) وارد میشود.
راه حل متداول این مشکل این است که تمام رشتههای ورودی کاربر، قبل از استفاده بررسی شوند و حروف مشکلدار آنها تصحیح گردد ولی مشکلی که این روش دارد اینست که هم کار زیادی برای برنامهنویس ایجاد میشود و هم ممکن است برخی قسمتها از قلم بیافتد و همیشه این شک وجود دارد که آیا رشتهها به طور کامل بررسی شدهاند یا نه؟
راه حل من برای این مشکل اینست که به طور یکپارچه، تمام ورودی ها قبل از اجرای هر کدی توسط یک HttpModuleتصحیح گردند. به این صورت در هیچ قسمت برنامه نیازی به تغییر نیست و بدون توجه به آرایش صفحه کلید کاربران سایت، ورودیهای دریافت شده توسط برنامه، همیشه با فرمت صحیح خواهند بود. در اینجا HttpModule مورد بحث را ارایه دادهام.
روش استفاده:
برای استفاده کافیست که dll ضمیمه شده را به پروژه اضافه کرده و در فایل web.config در بخش httpModules آن را معرفی کنید.
| <configuration> <system.web> <httpModules> <add name="FixFarsiCharsModule" type="FixFarsiCharsModule.FixFarsiCharsModule" /> </httpModules> </system.web> </configuration> |
پس از اضافه کردن این قسمت، دیگر در برنامه ورودی غیر مجاز دریافت نخواهد شد و این ماژول به طور خودکار ورودیهای کاربران را قبل از رسیدن به دست برنامه تصحیح خواهد کرد.
این تصحیح در قسمتهای مختلف شامل ورودیهای فرمها، کوئری استرینگ، کوکیها و ورودیهای با فرمت JSON انجام میشود. همچنین به طور خودکار این اسکریپ ورودیهای مخصوص ASP.NET مانند ViewState را شناسایی کرده و از تغییر آنها جلوگیری میشود.
تنها نکتهای که در استفاده از این اسکریپت وجود دارد، اینست که در مرحلهای که این اسکریپت کار خود را انجام میدهد، هنوز کنترلها مشخص نیستند و به عنوان مثال معلوم نیست که مقدار ورودی، یک ورودی از یک TextBox است یا مقدار یکDropDownList. بنابراین اگر برای کنترلهایی مثل DropDownList، مقادیر Value به صورت فارسی وارد شوند، آنها نیز تصحیح میگردند. در نتیجه باید دقت کرد که در صورت استفاده از این ماژول یا Valueها در کنترلهایی مثل این به صورت صحیح وارد شود. البته در حالت کلی توصیه من اینست که تا حد امکان از متن فارسی در Valueها استفاده نکنید و متن فارسی را فقط برای ویژگی Text استفاده کنید و برای Value از مقادیری مثل عددها استفاده کنید.
تنظیمات ماژول:
در این ماژول امکان تنظیم تمام رفتارها در فایل web.config وجود دارد و میتوانید بسته به نیازهای خاص خود، آن را تنظیم کنید. برای استفاده از تنظیمات، ابتدا بخش مورد نظر این ماژول را در بخش configSections در فایل web.config معرفی کنید. این تعریف باید حتما اولین قسمت از فایل web.config باشد.
| <configuration> <configSections> <section name="fixFarsiChars" type="FixFarsiCharsModule.FixFarsiCharsConfigurationSection" allowLocation="true" allowDefinition="Everywhere" /> </configSections> <configuration> |
بعد از آن قسمت fixFarsiChars را در فایل web.config اضافه کنید و تنظمات مورد نظر خود را در آن قرار دهید. در اینجا به عنوان نمونه، یک حالت تنظیم ماژول را آوردهام. بجز فیلد استثنا (someControlID) بقیه قسمتها تنظیمات پیشفرض ماژول هستند و در صورت نیاز به استفاده در همین حالت، اصلا نیازی به وجود این بخش نخواهد بود.
| <fixFarsiChars applyToForm="true" applyToCookie="true" applyToJson="true" applyToQueryString="true"> <replacements> <add original="ی" replacement="ی"/> <add original="ک" replacement="ک"/> </replacements> <exceptions> <add prefix="__" /> <add id="someControlID" /> </exceptions> </fixFarsiChars> |
تنظیمات ماژول تقریبا مشخص است ولی باز هم به طور خلاصه آنها را توضیح میدهم. در قسمت اول قابلیت تنظیم این مساله وجود دارد که این ماژول عمل تصحیح را در کدام قسمتهای ورودی انجام دهد. در صورت نیاز، میتوانید هر قسمت که مورد نیاز نبود غیرفعال کنید.
در بخش replacements عمیات تصحیحی که مورد نیاز است معرفی میشود. در این قسمت میتوانید تنظیمات خاص خود را وارد کنید. به عنوان مثال ممکن است در پروژهای نیاز باشد که برعکس کار ماژول، حروف به صورت عربی باشند و یا به عنوان مثال اعداد نیز فارسی شوند که به راحتی این موراد در این قسمت قابل انجام است. در هر مورد original به معنی کارکتری که باید تصحیح شود و replacement به معنی کارکتر جایگزین آن است.
در بخش exceptions نیز میتوانید کنترلها و فیلدهایی که تصحیح بر روی آنها نباید انجام شود را معرفی کنید. به طور پیش فرض تمام کنترلهایی که با دو حرف خط زیر (__) شروع میشوند استثنا شدهاند که این امر به منظور جلوگیری از تداخل کار ماژول با مقادیر مورد استفاده در خود ASP.NET (مانند VIEWSTATE__ و EVENTTARGET__ و ...) است. در صورت لزوم میتوانید کنترلهای خاص خود را در این قسمت برای وارد کنید. از حالت prefix برای استثنا کردن کنترلها به صورت گروهی با وارد کردن بخش ابتدایی نام آنها و از id برای استثنا کردن کنترل با id خاص استفاده میشود.