上一篇了解到 請(qǐng)求到達(dá)服務(wù)器后是怎么被IIS處理的饶辙,本篇來(lái)看一下在ISAPI內(nèi)部是怎么處理請(qǐng)求的;
首先ISAPI 有三個(gè)重量級(jí)入口:
一斑粱, ISAPIRuntimeRequest.ProcessRequest() 最外層入口
- 根據(jù)句柄ecb創(chuàng)建HttpWorkerRequest 對(duì)象封裝原始請(qǐng)求報(bào)文 wr 弃揽;
public int ProcessRequest(IntPtr ecb, int iWRType)
{
......
ISAPIWorkerRequest wr = null;
try
{
bool useOOP = iWRType == 1;
wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
wr.Initialize();
string appPathTranslated = wr.GetAppPathTranslated();
string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal;
if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))
{
HttpRuntime.ProcessRequestNoDemand(wr);
return 0;
}
......
1.1. 根據(jù)IIS版本來(lái)創(chuàng)建請(qǐng)求報(bào)文 ISAPIWorkerRequest
internal static ISAPIWorkerRequest CreateWorkerRequest(IntPtr ecb, bool useOOP)
{
......
if (num >= 7)
{
EtwTrace.TraceEnableCheck(EtwTraceConfigType.IIS7_ISAPI, ecb);
}
else
{
EtwTrace.TraceEnableCheck(EtwTraceConfigType.DOWNLEVEL, IntPtr.Zero);
}
if (EtwTrace.IsTraceEnabled(5, 1))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_APPDOMAIN_ENTER, ecb, Thread.GetDomain().FriendlyName, null, true);
}
if (num >= 7)
{
return new ISAPIWorkerRequestInProcForIIS7(ecb);
}
if (num == 6)
{
return new ISAPIWorkerRequestInProcForIIS6(ecb);
}
return new ISAPIWorkerRequestInProc(ecb);
}
二, HttpRuntime.ProcessRequestInternal()
1.根據(jù)HttpRuntime.ProcessRequestNoDemand(wr);方法內(nèi)部創(chuàng)建HttpContext则北,HttpApplication對(duì)象矿微;
internal static void ProcessRequestNoDemand(HttpWorkerRequest wr)
{
RequestQueue queue = _theRuntime(HttpRuntime實(shí)例)._requestQueue(請(qǐng)求隊(duì)列);
wr.UpdateInitialCounters();
if (queue != null)
{
wr = queue.GetRequestToExecute(wr);
}
if (wr != null)
{
CalculateWaitTimeAndUpdatePerfCounter(wr);
wr.ResetStartTime();
ProcessRequestNow(wr);
}
}
2.我們接著進(jìn)入ProcessRequestNow(wr) 方法,方法根據(jù)請(qǐng)求報(bào)文開(kāi)始創(chuàng)建HttpContext對(duì)象尚揣;
private void ProcessRequestInternal(HttpWorkerRequest wr)
{
......
HttpContext context;
try
{
context = new HttpContext(wr, false);
2.1. 這是實(shí)例HttpContext的方法涌矢,我們看到內(nèi)部實(shí)例了常用對(duì)象 HttpRequest和HttpResponse
internal HttpContext(HttpWorkerRequest wr, bool initResponseWriter)
{
this._timeoutStartTimeUtcTicks = -1L;
this._timeoutTicks = -1L;
this._threadAbortOnTimeout = true;
this.ThreadContextId = new object();
this._wr = wr;
this.Init(new HttpRequest(wr, this), new HttpResponse(wr, this));
if (initResponseWriter)
{
this._response.InitResponseWriter();
}
PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_EXECUTING);
}
- 我們接下來(lái)看 HttpApplicationFactory.GetApplicationInstance(context) 方法內(nèi)部通過(guò)維護(hù)一個(gè)應(yīng)用程序池,當(dāng)不存在時(shí) 實(shí)例化了HttpApplication(通過(guò)反射 Global.asax 文件)快骗;我們?cè)谶@里發(fā)現(xiàn)原來(lái)IHttpHandler 是HttpApplication 的基類娜庇;
private void ProcessRequestInternal(HttpWorkerRequest wr)
......
context.Response.InitResponseWriter();
IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);
......
}
}
三. HttpApplication.Init() 管道事件
以上說(shuō)了那么多廢話,因?yàn)槲覀兪裁匆哺牟涣朔嚼海皇菍?duì)請(qǐng)求流程有個(gè)大致的了解名秀;
下面我們就可以 跟微軟達(dá)達(dá)互動(dòng)了 (* ̄︶ ̄)
1.我們還是從 HttpApplication創(chuàng)建過(guò)程來(lái)看,我們注意到有一個(gè)InitInternal初始實(shí)例方法藕溅,在此方法中有兩個(gè) InitModules(),BuildSteps()方法匕得;
private HttpApplication GetNormalApplicationInstance(HttpContext context)
{
HttpApplication state = null;
......
if (state == null)
{
state = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
using (new ApplicationImpersonationContext())
{
state.InitInternal(context, this._state, this._eventHandlerMethods);
}
}
......
2.在 InitModules方法中,通過(guò)讀取Web.Config配置文件關(guān)于HttpModule信息巾表,并加入集合汁掠;最后通過(guò)方法InitModulesCommon()遍歷執(zhí)行每個(gè)模塊的初始化方法 Init();
private void InitModules()
{
HttpModuleCollection modules = RuntimeConfig.GetAppConfig().HttpModules.CreateModules();
HttpModuleCollection other = this.CreateDynamicModules();
modules.AppendCollection(other);
this._moduleCollection = modules;
this.InitModulesCommon();
}
3.在BuildSteps()方法中注冊(cè)了管道事件略吨,F(xiàn)12發(fā)現(xiàn)此方法是抽象方法,全局搜索找到考阱; 方法結(jié)束時(shí)有一個(gè)CopyTo 方法晋南,這個(gè)是把所有事件按順序儲(chǔ)存;
internal override void BuildSteps(WaitCallback stepCallback)
{
ArrayList steps = new ArrayList();
HttpApplication app = base._application;
bool flag = false;
UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings;
flag = urlMappings.IsEnabled && (urlMappings.UrlMappings.Count > 0);
steps.Add(new HttpApplication.ValidateRequestExecutionStep(app));
steps.Add(new HttpApplication.ValidatePathExecutionStep(app));
if (flag)
{
steps.Add(new HttpApplication.UrlMappingsExecutionStep(app));
}
// 管道事件
app.CreateEventExecutionSteps(HttpApplication.EventBeginRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventAuthenticateRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventDefaultAuthentication, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostAuthenticateRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventAuthorizeRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostAuthorizeRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventResolveRequestCache, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostResolveRequestCache, steps);
steps.Add(new HttpApplication.MapHandlerExecutionStep(app));
app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);
app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);
steps.Add(app.CreateImplicitAsyncPreloadExecutionStep());
steps.Add(new HttpApplication.CallHandlerExecutionStep(app));
app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);
app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);
steps.Add(new HttpApplication.CallFilterExecutionStep(app));
app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);
this._endRequestStepIndex = steps.Count;
app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);
steps.Add(new HttpApplication.NoopExecutionStep());
this._execSteps = new HttpApplication.IExecutionStep[steps.Count];
steps.CopyTo(this._execSteps);
this._resumeStepsWaitCallback = stepCallback;
}
4.我們依然回到ProcessRequestInternal方法中,執(zhí)行BeginProcessRequest方法觸發(fā)每個(gè)事件執(zhí)行羔砾;
if (applicationInstance is IHttpAsyncHandler)
{
IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;
context.AsyncAppHandler = handler2;
handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context);
}
四,模塊和事件 ——管道
管道事件[http://www.cnblogs.com/edisonchou/p/4201855.html]
模塊 IHttpmodule ,事件 IHttpHandler. 兩種同屬于請(qǐng)求處理注入邏輯偶妖,不同點(diǎn)在于 模塊 針對(duì)于全部請(qǐng)求 邏輯注入姜凄,事件針對(duì)于指定文件 邏輯注入;
1.通過(guò)在<modules>節(jié)點(diǎn)下 配置模塊趾访,通過(guò)在 <handlers>節(jié)點(diǎn)下 配置事件,我們從它們配置項(xiàng)也可以看出來(lái)區(qū)別态秧;
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<!--<modules runAllManagedModulesForAllRequests="true" />-->
<modules>
<add name="CustomeModule" type="MVC3.CustomeModule, MVC3" />
</modules>
<handlers>
<add name="CustomeHandler" verb="*" path="*.txt" type="MVC3.CustomeHandler, MVC3"/>
</handlers>
</system.webServer>
- 實(shí)現(xiàn)相應(yīng)的接口; 注意實(shí)現(xiàn)IHttpModule接口時(shí)Dispose方法的實(shí)現(xiàn)和IHttpHandler接口屬性IsReusable 改為return true扼鞋;
public class CustomeModule : IHttpModule
{
public void Dispose()
{
throw new NotImplementedException();
}
public void Init(HttpApplication context)
{
//context.Context.Response.Write("Module");
context.BeginRequest += context_BeginRequest;
context.PreRequestHandlerExecute += context_PreRequestHandlerExecute;
context.PostRequestHandlerExecute += context_PostRequestHandlerExecute;
}
void context_PostRequestHandlerExecute(object sender, EventArgs e)
{
((HttpApplication)sender).Context.Response.Write("PostRequestHandlerExecute <br> ");
}
void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
((HttpApplication)sender).Context.Response.Write("PreRequestHandlerExecute <br> ");
}
void context_BeginRequest(object sender, EventArgs e)
{
((HttpApplication)sender).Context.Response.Write("BeginRequest <br> ");
}
}
public class CustomeHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.Write("CustomeHandler <br>");
}
public bool IsReusable
{
get { return true; }
}
}
3.我們看頁(yè)面執(zhí)行結(jié)果申鱼,和管道事件的執(zhí)行順序是一致的
- 總結(jié) 常用思路:
httphandler 可以運(yùn)用在圖片盜鏈上等等;httpmodule 可以用在權(quán)限等等云头;
參考文檔 有直接使用博友的圖费变,在此對(duì)以下博友表示感謝:
博客園[http://www.cnblogs.com/edisonchou/p/4195259.html]
博客園[http://www.cnblogs.com/edisonchou/p/4201855.html]
博客園[http://www.cnblogs.com/OceanHeaven/p/6514230.html]
博客園[https://www.cnblogs.com/Rayblog/p/6394315.html]
博客園[https://www.cnblogs.com/fish-li/archive/2013/01/04/2844908.html]
biancheng[http://www.bianceng.cn/Programming/net/201210/34557_3.htm]
MSDN iis與asp.net流程[https://msdn.microsoft.com/zh-cn/library/bb470252(v=vs.100).aspx]