PDA

View Full Version : ناگفته های HttpModules و HttpHandlers



manager
چهارشنبه 15 فروردین 1386, 11:23 صبح
مطالب مندرج در تاپیک قبلی که من باب همین موضوع توسط یکی از عزیزان مطرح شده بود به صورت کامل به این تاپیک منتقل شد.


HttpModules و HttpHandlers

با استفاده از HttpModule و HttpHandler شما می توانید عملیات سطح پائین تری را با درخواست ها و پاسخ های Client انجام دهید. در حقیقت HttpModule و HttpHandler دو ابزار برای Componentizing کردن Web App هستند. وظیفه ی یک HttpHandler رندر کردن منبع خاص و یا نوع خاصی از یک منبع خاص می باشد. در حقیقت هر وقت که شما یک صفحه ی aspx را به پروژه خود اضافه می کنید در واقع یک HttpHandler ایجاد کرده اید. به این خاطر که هنگامی که بخشی از HTML صفحه ی aspx شما در هنگام زمان اجرا کامپایل می شود و به صورت مستقیم یا غیر مستقیم از System.Web.UI.Page به ارث می برد که این باعث پیاده سازی یک HttpHandler می شود. در حقیقت کلاس System.Web.UI.Page یک HttpHandler هستش که باعث رندر شدن صفحه ی aspx می شود. البته احتمالا شما از این موضوع تا به حال کاملا بی اطلاع بودید و نیازی هم نیست که بدانید در پشت صحنه چه می گذرد.
بعضی وقت ها شما نیاز دارید که در ازای شروع هر درخواست یک کد خاص اجرا شود . مثلا فرض کنید شما نیاز دارید که بدانید کاربر به چه صفحه هایی در وب سایتتان می رود. یک راه اینکه کد Logging که این عمل را برایتان انجام می دهد را در Pgae_Load هر صفحه بگذارید که آشکارا دارای هزینه ی بالائی برای Maintenance و Reusability هست. مثلا باید برای تمام صفحات این کار را انجام دهیم و یا تصور کنید سایتتان 300 صفحه دارد، حال می خواهید در کنار Logging یک عمل دیگرنیز انجام دهید، حتی تصورش هم عذاب آور است. اما راه خوب و آسان این کار که امتیاز خوبی نیز در Maintenance و Reusability دارد، استفاده از HttpModule هاست. شما یک Dll ایجاد می کنید که از IHttpModule پیروی کند و بعد تمام. اگر خواستید به راحتی می تونید از این Module در سایر وب سایت ها نیز استفاده کنید با کمترین هزینه تغییرات.

اما بیاید نگاهی دقیق تر و عمیق تر به HttpHandler ها و HttpModule ها بیاندازیم. هنگامی که یک Request به IIS از ظرف Client می رسد IIS پسوند فایل درخواست شده رو بررسی می کند تا در مورد اینکه چگونه Request رو پردازش کند تصمیم گیری کند. برای محتویات static و محتویاتی که نیاز به پردازش ندارند مثل فایل های HTML، js، images و غیره IIS خود Request ها را پردازش می کند. برای فایل هایی با محتویات داینامیک IIS با توجه به ISAPI Extensionهای ثبت شده تصمیم می گیرد که Request را به کدام ISAPI dll تحویل دهد. یک ISAPI یک قطعه کوچک unmanaged code است که می داند چگونه باید یک نوع خاص را Render کند. برای مثال asp.dll یک ISAPI است که فایل های asp را پردازش می کند و یا aspnet_isapi.dll یک ISAPI است که هنگام درخواست برای فایل های aspx طلبیده (invoke) می شود.



http://mfarahy.persiangig.com/image/123.jpg



علاوه بر ISAPI، IIS اجازه تعریف و مشخص کردن ISAPI Filterها نیز را می دهد. یک ISAPI Filter یک کد unmanaged هست که می تواند به event هایی که از سمت IIS بر می آید (Raising) پاسخ دهد.در دوره ی زندگی یک Request، IIS مراحل مختلفی رو طی می کند که هر مرحله Event مخصوص به خود را تولید می کند. برای مثال هنگام شروع دریافت درخواست، هنگامی که درخواست در مورد Authentication است، هنگامی بازگرداندن محتویات Render شده به سمت Client و همانند آن. ISAPI Filterها معمولا برای فشرده سازی، دوباره نوشتن URL، عملیات Authentication و .. مورد استفاده قرار می گیرند.



http://mfarahy.persiangig.com/image/124.jpg



هنگامی که درخواست asp.net از سمت Client به IIS ارسال می شود،IIS آن را به موتور asp.net راهنمائی می کند تا محتویات آن توسط Asp.net مورد پردازش قرار گیرد. موتور Asp.net بسیار شبیه به IIS عمل می کند و در حین پردازش درخواست Event های مختلفی را ایجاد می کند. علاوه بر این موتور Asp.net عملیات Rendering یک Resource درخواست شده را در غالب یک کلاس ویژه نمایندگی می کند.


نقاط پنهان پردازش درخواست

یکی از اشیاء بسیار مهم که در حقیقت حاوی درخواست IIS می باشد در Asp.net، شیئ ISAPIWorkerRequest هست بعد از آن سطح پائین ترین شیئ که حامل درخواست IIS می باشد، شیئ HttpWorkerRequest می باشد، این شیئ یکی از اعضاء خصوصی شیئ HttpContext می باشد و شما در حالت عادی به هیچ طریقی نمی توانید به آن دستیابی داشته باشید. برای دسترسی به آن می توانید از طریق کد زیر اقدام فرمائید :


BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
HttpWorkerRequest wr= (HttpWorkerRequest)pobjContext.GetType().GetProper ty("WorkerRequest", bindingFlags).GetValue(pobjContext, null);
ویا


HttpWorkerRequest wr= (HttpWorkerRequest)((IServiceProvider)context).Get Service(typeof(HttpWorkerRequest));
خوب برگردیم به سراغ HttpHandlerها و HttpModule ها.
یک HttpHandler کلاسی ست که موظف به Render کردن نوع خاصی از منابع است. به عنوان مثال همان کلاس Page یک HttpHandler است که موظف به Render کردن محتویات صفحات aspx می باشد.
یک HttpModule کلاسی ست که می تواند از وقایع (Events) مختلفی که در طی مراحل مختلف پردازش منبع در Server ایجاد می شود بهره برداری کند. به عنوان مثال یکی از HttpModule هایی رو که می توانید تصور کنید یک ErrorLogger می تواند باشد که هنگامی فعال می شود که یک Exception ناخواسته در Web App ایجاد شود.
تصویر زیر نمای گرافیکی از مراحل مختلف پردازش منابع Asp.net را نشان می دهد. توجه داشته باشید که پردازش هنگامی شروع می شود که درخواست به IIS برسد. فرض کنید درخواستی برای منابع Asp.net به IIS ارسال می شود. ابتدا IIS پسوند فایل را بررسی نموده وسپس درخواست را به aspnet_isapi.dll ارائه می کند. سپس aspnet_isapi.dll درخواست را به موتور Asp.net ارائه می کند. در حین چرخه ی زندگی درخواست ممکن است چندین HttpModule اجرا شوند که این بستگی به ثبت شدن و یا نشدن آنها دارد. در پایان درخواست به یک HttpHandler ویژه ارائه می شود.( این HttpHandler ویژه توسط یک HttpHandlerFactory شناسائی می شود.) سپس بعد از پردازش درخواست توسط HttpHandler درخواست چرخه برگشت خود به IIS را طی می کند.


http://mfarahy.persiangig.com/image/121.jpg

HttpHandler ها امکاناتی دارند که می توانید با استفاده از آنها منابع و یا مسیرهای خاصی را به آنها نسبت دهید و هنگام درخواست آن منابع یا مسیرها از سمت Client، موتور asp.net این درخواست را به HttpHandler شما تسلیم می کند و حالا HttpHandler شما وظیفه ی Render کردن آن درخواست را بر عهده دارد. مثلا در مثال زیر شما تعیین می کنید که در صورتی که کاربر صفحاتی با پسوند ashx را درخواست کرده بود، آنگاه کنترل درخواست به HttpHandler ای که شما مشخص کرده اید هدایت شود.( این کد را باید در web.config در میان تگ های <system.web> و </system.web> قرار دهید.)



<httpHandlers>
<add path="*.ashx" verb="*" type="Farahy.MyHttpHandler, MyHttpHandler"/>
</httpHandlers>


هر HttpHandler باید اینترفیس IHttpHandler را پیاده سازی کند. این اینترفیس دو عضو دارد. یکی خصوصیت IsReusable است که مشخص می کند آیا یک درخواست دیگر می تواند از نمونه ی آن استفاده کند یا خیر. هنگامی که یک درخواست از طریق Client به سرور ارسال می شود، موتور Asp.net به ازای پردازش هر درخواست یک Thread ایجاد می کند. IHttpHandler.IsReusable مشخص می کند که آیا یک نمونه از کلاس HttpHandler شما می تواند برای پردازش چندین درخواست همزمان مورد استفاده قرار گیرد یا خیر. در صورتی که HttpHandler شما مقدار true را برای این خصوصیت باز گرداند، کد موجود در متد ProcessRequest باید ThreadSafe بوده و همچنین مراقب باشید که هیچ گونه حالتی را نمی توانید در این مد در اختیار داشته باشید. همچنین در این حالت باید مراقب منابع مشترک که مورد استفاده ی درخواست های همزمان دیگر می باشد باشید. این حالت نسبت به حالتی دیگر (حالتی که IHttpHandler.IsReusable شما مقدار false را بر می گرداند) هزینه کمتری من باب استفاده از منابع سیستمی دارد. مثلا در مثال تولید تصاویر امنیتی با استفاده از HttpHandler، چون از منابع مشترک استفاده نمی کند و به حالت وابسته نیست می توان برای پائین آوردن هزینه اشغالی منابع در وضعیتی که چندین Request به صورت Concurrent پردازش می شود، از حالت Reusable استفاده نمود. البته کارائی این خصوصیت در سایت های بزرگ که یکباره با طیف وسیعی از درخواست ها مواجه می شوند، محسوس تر است.
پیشنهاد می کنم اگر تمایل به ایجاد یک HttpHandler داشتید مقدار بازگشتی IsReusable را با دقت انتخاب کنید. عضو دیگر IHttpHandler متد ProcessRequest است که وظیفه ی پردازش یک Request را بر عهده دارد.


public bool IsReusable
{
get
{
return true;
}
}

public void ProcessRequest(HttpContext context)
{
context.Response.Write("<BR/>HttpHandler :::: ProcessRequest<BR/>");
}
اما elementهای مهم تگ add میان <httpHandlers> و </httpHandlers> عبارت است از :
path : مشخص می کند این HttpHandler باید نسبت به چه مسیری و یا چه نوع منابعی گوش به زنگ باشد. به عنوان مثال path=” *.simg”
verb : مشخص می کند این HttpHandler نسبت به چه نوع Request باید فعال شود. مقادیر مجاز برای این element عبارت است از GET, POST, HEAD.

با استفاده از تنظیمات زیر در فایل web.config شما می توانید نسبت به معرفی و ثبت یک HttpModule اقدام کنید.

<add name="ModuleName"
type=".NET Class, Assembly [,Version=version number]
[,Culture=culture] [,PublicKeyToken=token]"/>هر کلاس HttpModule باید اینترفیس IHttpModule را پیاده سازی کند. این اینترفیس دو عضو دارد. یکی متد مهم Init است که در آن شما به شیئ HttpApplication دسترسی دارید و با استفاده از آن می تونید وقایعی را که نیاز به Handle کردن دارند را مشخص کنید. مثلا در کد زیر من دو واقعه ی BeginRequest و EndRequest را Handle می کنم.


public void Init(HttpApplication context)
{
HttpContext.Current.Response.Write("<BR/>HttpModule :::: Init<BR/>");
context.BeginRequest += new EventHandler(context_BeginRequest);
context.EndRequest += new EventHandler(context_EndRequest);
}
void context_EndRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
app.Response.Write("<BR/>HttpModule :::: context_EndRequest<BR/>");
}

void context_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.Write("<BR/>HttpModule :::: context_BeginRequest<BR/>");
}
شیئ sender در هر Event همان شیئ HttpApplication است.

با استفاده از مثال حاظر می توانید مراحل مراحل اجرای یک HttpModule و HttpHandler را مشاهده کنید.

http://mfarahy.persiangig.com/image/122.jpg

دانلود مثال (http://mfarahy.persiangig.com/Training/examples/HttpHandlersModules.rar)

دانلود نسخه PDF (http://mfarahy.persiangig.com/Articles/HttpHandlers_HttpModules.pdf)



سید محمد رضا فراحی(manager)

babi_wd
شنبه 15 اردیبهشت 1386, 12:44 عصر
ایا از httpHandlers برای دستیابی به فایلها توسط یوزر ها میشه استفاده کرد؟
اگه بله
پس اگه آدرس مستقیم فایل مشخص بشه بازم httpHandlers میتوته کنترلش کنه

manager
سه شنبه 18 اردیبهشت 1386, 22:26 عصر
سورس کامل این برنامه در این آدرس (http://www.dotnetsource.com/fa/forum/default.aspx?g=posts&m=3868#3868) قرار گرفته. با استفاده از این روش که توسط HttpModule و HttpHandler تواما پیاده سازی شده شما می تونید حتی برای آپلود فایل از ProgressBarهای جداگانه نیز استفاده کنید.

ghabil
چهارشنبه 09 خرداد 1386, 20:15 عصر
آقا ممنون استفاده کردم،

ضمنا در حالت معمولی برای یک HttpHandler به تنهایی Session ساخته نمیشه ، در حالیکه خیلی وقتها نیاز به Session هست ، راه حلش هم خیلی ساده هست ؛ کافیه کلاس Handlerی که میسازید اینترفیس IRequiresSessionState رو هم Implement کنه که عملا هم متد خاصی نداره .

habedijoo
شنبه 19 خرداد 1386, 11:31 صبح
سلام
این HttpModule خیلی گیر داره مثل اینکه . من دارم توی پروژه برای سطح دسترسی کاربران از HttpModule استفاده میکنم . به این شکل آدرس صفحه در حال ارسال برای IIS ا میگیرم . اگر کاربر به این صفحه دسترسی داشته باشد . ( اطلاعات مربوطه درون Session وجود دارند ) کار به شکل عادی ادامه میابد وگرنه بوسیه دستور Server.Transfer کاربر را به صفحه Login می برم . توی پروژه از مستر پیج استقاده کردم . همش گیر میده که SessionState رو True کنید .
کسی تا حالا این کار رو انجام داده ؟
البته این نکته رو بگم که با Response.write این مشکل پیش نمیاد ولی مشکلات دیگه ای دارم باهاش .

ghabil
یک شنبه 20 خرداد 1386, 01:13 صبح
چیزی که من نوشتم دقیقا برای حل مشکل شما بود ، اگر IRequiresSessionState رو هم Implement بکنید مشکلتون حل میشه.

habedijoo
یک شنبه 20 خرداد 1386, 12:54 عصر
دوست عزیز این کار رو هم کردم . نشد . اگر این مشکل رو سرچ کنید میبینیدکه خیلی ها باهاش سرو کله میزنن .
مثل این که یه باگی داره ؟

Sayehzendeh
سه شنبه 05 تیر 1386, 11:51 صبح
سلام . ممنون از نوشته شما.
آیا میشود توضیح دهید که چگونه با HttpHandler می شود Extension را عوض کنم.
به عنوان مثال aspx به Html

manager
سه شنبه 05 تیر 1386, 15:28 عصر
سلام . ممنون از نوشته شما.
آیا میشود توضیح دهید که چگونه با HttpHandler می شود Extension را عوض کنم.
به عنوان مثال aspx به Html
این کار رو باید تو IIS انجام بدید، طریقه مراجعه به اون بخش هم در بالا گفتم.

Sayehzendeh
سه شنبه 19 تیر 1386, 09:57 صبح
من تمام مراحل شما در بالا توضیح دادید را مطالعه کردم . دست شما درد نکنه .
ولی من یک مشکل دارم؟
من یک content page به نام news.aspx دارم و یک masterpage دارم.
میخواهم news.aspx را در هنگام نمایش extension را عوض کنم و به صورت news.html
نمایش دهم.
حال یک httphandler ایجاد کردم و در web.config انتساب handler را انجام دادم و کلاس myhandler را
ایجاد کردم و حالا نمی دانم چه کدی بنویسم تا extension را از aspx به html تغییر دهم.

rtech
دوشنبه 08 مرداد 1386, 20:43 عصر
این مقاله هم میتونه بهتون کمک کنه :



http://aspnet.4guysfromrolla.com/articles/011404-1.aspx

javad3151
دوشنبه 19 شهریور 1386, 10:12 صبح
سلام
من یه IHttpModule درست کردم و در روال Application_EndRequest نام فایل درخواستی و اطلاعات کاربر login شده رو چک می کنم ، که در صورتی که کاربر مجاز نباشه نباید بتونه فایل رو ببینه ؛ تا اینجا همه چیز درست کار میکنه ولی نمی دونم چرا دستور redirect درست کار نمیکنه


HttpContext.Current.Response.Redirect("../usermsg.aspx?msgid=11")

از Server.Transfer هم استفاده کردم ولی کار نمیکنه (مشکل اینجاست که error هم نمیده )

javad3151
یک شنبه 01 مهر 1386, 09:33 صبح
اساتید بزرگ کممممممممممممک

cactuskhan
دوشنبه 02 مهر 1386, 08:25 صبح
سلام

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

من یه کلاسی نوشتم واسه اینکه theme رو توی صفحات مدیریت کنه واسه همین کلاسم رو از IHttpModule مشتق کردم ولی یه جای کار ایراد داره و کار نمیکنه یعنی اصلا زمان اجرا وارد کلاس من نمیشه اگه میشه راهنمایی کنید کجای کار گیر داره !؟؟ :متفکر:

این کلاس رو من داخل App_Code گذاشتم !


using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;

namespace HandleTheme
{
public class HandleTheme : IHttpModule
{
public HandleTheme()
{

}
public void Init(HttpApplication application)
{
application.BeginRequest += new EventHandler(application_BeginRequest);
}
public void Dispose()
{ }

private void application_BeginRequest(object sender, EventArgs e)
{
Page page = HttpContext.Current.CurrentHandler as Page;
if (page != null)
{
page.EnableTheming = true;
page.PreInit += new EventHandler(Page_PreInit);
}
}
public void Page_PreInit(object sender, EventArgs e)
{
Page page = (Page)sender;

if (page != null)
{
page.Theme = "Default";
}
}


}
}

manager
سه شنبه 03 مهر 1386, 20:14 عصر
دوست عزیز در زمان اجرای رویداد Application.BeginRequest شیئ Page هنوز ساخته نشده است. شما می توانید از یک رویداد دیگر مثل PreRequestHandlerExecute استفاده کنید و بدین وسیله مشکل خود را حل کنید.

bahareh1368
سه شنبه 20 دی 1390, 13:46 عصر
سلام به همگی.
چوری میشه در صفحه Codebehind بطور مستقیم از کلاس httphandler استفاده کرد.من یه handler ساختم تا تمام عکسایی که از کنترل fileUpload در پروژه م استفاده میشه به اندازه 100 پیکسل Resize بشه.تمام تنظیمات للازم رو هم در web.config انجام دادم.اما چطوری میتونم زمانی که عکسی رو انتخاب کردم , این کلاس را روی آن map کنم تا عمل تغییر سایز انجام بشه.چه کدی باید بنوسیم؟

bahmanbit
دوشنبه 01 مهر 1392, 16:05 عصر
سلام
ایا این امکان وجود داره که برای MultiLanguage به جایه اینکه در page_load هر page ما کدی را اضافه کنیم ، فقط در httpModule کدی را برای فهمیدن CurrentLanguage کاربر بنویسیم؟؟؟

saramigmigmig
یک شنبه 29 تیر 1393, 23:27 عصر
دوست عزیز سایتی که پروژه داخلش هست باز نمیشه میشه لطفا پروژه رو اینجا بذارید؟