ภาพรวม:
บทความนี้อิงตามซอร์สโค้ดของ ASP.NET 2.0 และดำเนินการวิเคราะห์รันไทม์ ASP.NET 2.0 โดยย่อ ฉันหวังว่าบทความนี้จะช่วยให้คุณเข้าใจกระบวนการประมวลผลคำขอและโมเดลการคอมไพล์เพจใน ASP.NET 2.0
คำสำคัญ:
รันไทม์ ASP.NET 2.0, หลักการ, การประมวลผลคำขอ, การคอมไพล์เพจ,
คลาสหลักของ ASP.NET 2.0 HTTP Runtime:
System.Web.HttpRuntime
System.Web.HttpApplicationFactory
System.Web.HttpApplication
System.Web.Compilation.BuildManager
System.Web.Compilation.ApplicationBuildProvider
System.Web.Compilation.BuildProvidersCompiler
System.Web.UI.PageHandlerFactory
ผังงานโดยย่อของการประมวลผลคำขอ:
คำแนะนำในการอ่าน:
ใช้เครื่องมือ Reflector เพื่อดูซอร์สโค้ดของ ASP.NET 2.0 ขณะอ่าน
วิเคราะห์:
เมื่อเราเริ่มต้นการร้องขอไปยังเพจ asp.net บนเว็บไซต์ ASP.NET 2.0 ผ่านทางเบราว์เซอร์ IIS จะได้รับคำขอทางฝั่งเซิร์ฟเวอร์ก่อน เมื่อ IIS เห็นว่าเป็นเพจ asp.net ฉันรู้สึกมีความสุขมากเพราะสิ่งนี้ คำขอไม่จำเป็นต้องได้รับการประมวลผล เพียงปล่อยให้เป็น ASP.NET ISAPI การทำงานของ ASP.NET ISAPI นั้นค่อนข้างง่ายเช่นกัน หน้าที่หลักคือการจัดให้มี aspnet_wp.exe เพื่อประมวลผลคำขอและตรวจสอบการดำเนินการของกระบวนการ aspnet_wp.exe หากกระบวนการ aspnet_wp.exe เหนื่อยเกินไปและไม่สามารถทำงานให้เสร็จสิ้นได้ ASP.NET ISAPI จะเลิกจ้างเขาและแทนที่เขาด้วย aspnet_wp.exe ใหม่เพื่อจัดการงาน
งานหลักของ aspnet_wp.exe คือการส่งคำขอไปยังชุดของอ็อบเจ็กต์ที่ได้รับการจัดการที่เรียกว่า HTTP ไปป์ไลน์ ถ้า ASP.NET ISAPI ถูกเปรียบเทียบกับผู้จัดการฝ่ายขาย ดังนั้น aspnet_wp.exe จะเป็นผู้จัดการฝ่ายผลิต และไปป์ไลน์ HTTP ก็คือไปป์ไลน์การผลิต ทีมงานที่รับผิดชอบในสายการประกอบคือ HttpRuntime ผู้จัดการฝ่ายผลิต aspnet_wp.exe จะมอบคำสั่งซื้อ (คำขอ HTTP) ให้กับสมาชิกทีม HttpRuntime ProcessRequest (HttpWorkerRequest wr) ในที่สุด HttpRuntime จะถูกสร้างขึ้นบนสายการประกอบโดย ProcessRequestInternal (HttpWorkerRequest wr) ) ตามการแบ่งส่วนภายในของแรงงาน ดังนั้น ProcessRequestInternal(HttpWorkerRequest wr) จึงเป็นจุดสนใจของการวิเคราะห์ของเรา
งานหลักของ ProcessRequestInternal คือ:
1. สร้างอินสแตนซ์ HttpContext
2. เริ่มต้นคำขอแรก (EnsureFirstRequestInit)
ก) ดำเนินการเริ่มต้นบางอย่างใน SureFirstRequestInit โดยการเรียก System.Web.HttpRuntime.FirstRequestInit เช่น การอ่านการกำหนดค่า Web.Config ลงใน RuntimeConfig และโหลดไฟล์ dll ทั้งหมดจากไดเร็กทอรี bin
3. สร้างอินสแตนซ์ HttpWriter
4. สร้างอินสแตนซ์ HttpApplication โดยการเรียก HttpApplicationFactory.GetApplicationInstance
มีสามวิธีหลักใน HttpApplicationFactory.GetApplicationInstance:
HttpApplicationFactory._theApplicationFactory.EnsureInited();
HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled (บริบท);
HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);
มาวิเคราะห์ทั้งสามวิธีนี้ทีละรายการ:
1) HttpApplicationFactory._theApplicationFactory.EnsureInited();
วิธีการนี้จะตรวจสอบว่า HttpApplicationFactory ได้รับการเตรียมใช้งานหรือไม่ หากไม่เป็นเช่นนั้น จะมีการเตรียมใช้งานผ่าน HttpApplicationFactory.Init()
ใน Init() ขั้นแรกให้รับเส้นทางแบบเต็มของไฟล์ global.asax จากนั้นเรียก CompileApplication() เพื่อคอมไพล์ global.asax
การรวบรวมดำเนินการอย่างไร?
งานคอมไพล์เสร็จสมบูรณ์โดย BuildManager BuildManager รับ GlobalAsaxType ก่อน (นั่นคือ HttpApplication) จากนั้นเรียก BuildManager.GetGlobalAsaxBuildResult() = 》GetGlobalAsaxBuildResultInternal() = 》EnsureTopLevelFilesCompiled() สำหรับการคอมไพล์
ใน SureTopLevelFilesCompiled นั้น CompilationStage.TopLevelFiles จะถูกคอมไพล์ก่อน และไฟล์ในสามไดเร็กทอรีต่อไปนี้จะถูกคอมไพล์:
ก. CompileResourcesDirectory();
รวบรวมไดเร็กทอรี App_GlobalResources
ข. CompileWebRefDirectory();
รวบรวมไดเร็กทอรี App_WebReferences
ค. CompileCodeDirectories();
รวบรวมไดเร็กทอรี App_Code
จากนั้นคอมไพล์ CompilationStage.GlobalAsax, คอมไพล์ global.asax และการเรียกใช้เมธอด: CompileGlobalAsax()=》ApplicationBuildProvider.GetGlobalAsaxBuildResult(BuildManager.IsPrecompiledApp)
การคอมไพล์เฉพาะใน GetGlobalAsaxBuildResult เสร็จสมบูรณ์โดย ApplicationBuildProvider และ BuildProvidersCompiler
BuildProvidersCompiler.PerformBuild(); ดำเนินการคอมไพล์
ApplicationBuildProvider.GetBuildResult ได้รับผลลัพธ์ที่คอมไพล์แล้ว
หลังจากการคอมไพล์สำเร็จ ไฟล์ dll ที่คล้ายกับ App_global.asax.mlgx7n2v.dll จะถูกสร้างขึ้นในไดเร็กทอรีที่เกี่ยวข้องของ C:WINDOWSMicrosoft.NETFrameworkv2.0.50727Temporary ASP.NET Files
คลาสที่คอมไพล์แล้วมีชื่อว่า ASP.global_asax และสืบทอดมาจาก HttpApplication
หมายเหตุ: หากไม่มีไฟล์ Global.asax ในไดเร็กทอรีเว็บ ไฟล์เช่น App_global.asax.mlgx7n2v.dll จะไม่ถูกคอมไพล์และสร้าง
2) HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled (บริบท);
สร้างอินสแตนซ์ HttpApplication เฉพาะ ทริกเกอร์เหตุการณ์ ApplicationOnStart และดำเนินการเมธอด Application_Start(object sender, EventArgs e) ใน ASP.global_asax อินสแตนซ์ HttpApplication ที่สร้างขึ้นที่นี่จะถูกรีไซเคิลหลังจากประมวลผลเหตุการณ์
3) HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance (บริบท);
เมธอดนี้จะสร้างอินสแตนซ์ HttpApplication และเตรียมใช้งาน (เรียกเมธอด System.Web.HttpApplication.InitInternal())
การสร้างอินสแตนซ์ HttpApplication จะขึ้นอยู่กับ _theApplicationType จริง หากไม่มีไฟล์ global.asa ในไดเร็กทอรีเว็บ กล่าวคือ ไม่มีการคอมไพล์แบบไดนามิกเพื่อสร้างประเภท ASP.global_asax ให้สร้างอินสแตนซ์ HttpApplication โดยตรง หากประเภท ASP.global_asax ถูกสร้างขึ้น ให้สร้างอินสแตนซ์ ASP.global_asa
หลังจากสร้างอินสแตนซ์ HttpApplication ให้เรียกใช้เมธอด InitInternal ของอินสแตนซ์
เมธอด InitInternal ก็เป็นเมธอดที่เราเน้นเช่นกัน ฟังก์ชันหลักของเมธอดนี้มีดังนี้:
1. InitModules(): สร้าง HttpModules ที่สอดคล้องกันตามการตั้งค่าของ Web.Config
2. HookupEventHandlersForAppplicationAndModules: ขึ้นอยู่กับเหตุการณ์ที่เกิดขึ้น ให้เรียกใช้ฟังก์ชันการประมวลผลเหตุการณ์ที่เกี่ยวข้องในอินสแตนซ์ HttpApplication
3. สร้างอินสแตนซ์จำนวนมากของคลาสที่ใช้อินเทอร์เฟซ IExecutionStep และเพิ่มลงใน _execSteps ของอินสแตนซ์ HttpApplication ปัจจุบัน และรอการดำเนินการเรียกกลับ จากที่นี่เราจะเห็นว่า HttpApplication ประมวลผลคำขอในลักษณะอะซิงโครนัส และงานการประมวลผลจำนวนมากสำหรับคำขอถูกใส่ไว้ใน _execStep เพื่อรอให้ดำเนินการโทรกลับ
งานการประมวลผลหลักใน _execStep มีดังนี้:
1) ดำเนินการตรวจสอบความปลอดภัยบนเส้นทางที่ร้องขอและห้ามการเข้าถึงเส้นทางที่ผิดกฎหมาย (ValidatePathExecutionStep)
2) หากตั้งค่า UrlMappings ให้ดำเนินการ RewritePath(UrlMappingsExecutionStep)
3) ดำเนินการฟังก์ชันการประมวลผลเหตุการณ์ เช่น BeginRequest, AuthenticateRequest เป็นต้น
4) รับ HttpHandler ที่จัดการคำขอปัจจุบัน การรวบรวมรันไทม์ของเพจ ASP.NET ก็ดำเนินการที่นี่เช่นกัน (ขั้นตอน MapHandlerExecution)
การประมวลผลนี้เสร็จสิ้นโดยการเรียกเมธอด System.Web.HttpApplication.MapHttpHandler
ใน MapHttpHandler ขั้นแรกให้รับประเภทที่เกี่ยวข้องซึ่งใช้ IHttpHandlerFactory จาก web.config ตามที่อยู่ที่เข้าถึง สำหรับเพจ asp.net ค่าเริ่มต้นคือ PageHanlderFactory จากนั้นสร้างอินสแตนซ์ PageHanlderFactory เรียก GetHandlerHelper เรียก BuildManager.CreateInstanceFromVirtualPath ใน GetHandlerHelper เพื่อคอมไพล์และสร้างอินสแตนซ์ของเพจ ASP.NET ที่ร้องขอในปัจจุบัน (หากคอมไพล์แล้ว ให้โหลดโดยตรงจากแคช)
CreateInstanceFromVirtualPath ส่งงานการคอมไพล์ไปยัง BuildManager CompileWebFile() หลังจากการเรียกเมธอดหลายวิธี CompileWebFile รับ BuildProvider ที่เกี่ยวข้องจาก web.config สำหรับไฟล์ .aspx BuildProvider ที่เกี่ยวข้องคือ PageBuildProvider วิธีที่ PageBuildProvider รวบรวมเพจจะไม่ได้รับการวิเคราะห์เพิ่มเติมที่นี่ หากคุณสนใจ คุณสามารถศึกษาซอร์สโค้ดของ ASP.NET 2.0 เพิ่มเติมได้
5) เรียกใช้เมธอด .ProcessRequest ของ HttpHandler ที่เกี่ยวข้องเพื่อประมวลผลคำขอ (หากเป็นแบบอะซิงโครนัส ให้เรียก BeginProcessReques) (ขั้นตอน CallHandlerExecution)
6) เขียนเนื้อหาการตอบกลับลงในตัวกรอง (CallFilterExecutionStep)
5. เรียก BeginProcessRequest ของอินสแตนซ์ HttpApplication เพื่อประมวลผลคำขอแบบอะซิงโครนัส
หลายสิ่งที่เกิดขึ้นใน _execSteps ที่กล่าวถึงข้างต้นจะถูกดำเนินการหลังจากที่ HttpRuntime เรียก HttpApplication BeginProcessRequest แล้วเรียก ResumeSteps ใน BeginProcessRequest
รันไทม์ ASP.NET 2.0 เป็นส่วนที่ซับซ้อนมาก เข้าใจยาก และเป็นส่วนสำคัญของ ASP.NET 2.0 การศึกษาซอร์สโค้ดรันไทม์ ASP.NET 2.0 จะช่วยให้เราเข้าใจหลักการของ ASP.NET 2.0 ลึกซึ้งยิ่งขึ้นและจะ ให้เราพัฒนาแอปพลิเคชัน ASP.NET 2.0 นำมาซึ่งความช่วยเหลือมากมาย บทความนี้เป็นครั้งแรกของฉันในการเรียนรู้รันไทม์ ASP.NET 2.0 บทความนี้เขียนขึ้นเพื่อช่วยให้ฉันเข้าใจรันไทม์ ASP.NET 2.0 ได้ดีขึ้น คุณสามารถวิจารณ์และให้คำแนะนำเกี่ยวกับเนื้อหาของบทความได้
ฉันรู้สึกว่าการเขียนบทความไม่เพียงแต่สามารถพัฒนาทักษะการเขียนและอำนวยความสะดวกในการสื่อสารเท่านั้น แต่ยังผ่านการเขียนบทความอีกด้วย เราสามารถทำให้ความคิดของตนเองชัดเจนขึ้น ส่งเสริมการคิดเชิงลึก และทำให้ความเข้าใจในเทคโนโลยีลึกซึ้งยิ่งขึ้น นักพัฒนาซอฟต์แวร์อาจใช้เวลาห่างจากการเขียนโค้ด การเขียนบทความทางเทคนิคบางส่วนยังมีประโยชน์มากในการปรับปรุงตนเอง