บทความ

Asynchronous Web Parts

เรตติ้ง
เขียนโดย admin เมื่อวันที่ 08 April 2008 ตอน 11:41

การสร้างเว็บไซต์ที่ปรับแต่งหน้าตาได้พร้อมทั้งสามารถเพิ่มเติมชุด   Web   Parts   ลงไปได้ ถือเป็นเรื่องที่ง่ายดายอย่างมาก ถ้าหากคุณใช้โครงสร้างพื้นฐานประตูท่าของ  ASP.NET 2.0 โมเดลนี้จัดว่ามีความคล่องตัวอย่างมาก โดยยอมให้ผู้ใช้ใส่  Web  Parts  ลงไปตรงจุดใดก็ได้ในเว็บเพจ เพื่อที่พวกเขาจะสามารถปรับแต่งหน้าตาของเว็บไซต์ได้โดยอิสระ อย่างไรก็ตามปมเด่นต่างๆเหล่านี้อาจนำไปสู่ระบบที่ไร้ประสิทธิภาพจนทำให้ผู้ใช้ไม่พอใจได้ เนื่องจากคุณไม่มีทางทราบได้ก่อนว่าจะมีคอมโพเน้นต์ใดที่สามารถนำมาใช้ร่วมกันบ้าง ด้วยเหตุนี้คุณจึงไม่สามารถปรับแต่งให้การเรียกใช้ข้อมูลของคอมโพเน้นต์แต่ละชนิดมีประสิทธิภาพสูงสุดได้

ปัญหาความไร้ประสิทธิภาพที่มักพบในไซต์ประตูท่าทั่วไปเกิดขึ้นเมื่อมี  Web Parts จำนวนมากเรียกขอข้อมูลจากระบบเครือข่ายพร้อมๆกัน คำสั่งแต่ละอัน (ไม่ว่าจะเป็นเว็บเซอร์วิสหรือรีโมทดาต้าเบสก็ตาม) มักจะทำให้การประมวลผลเพจโดยรวมเสียเวลานานขึ้น แม้ว่าคำสั่งเหล่านี้จะเป็นอิสระต่อกันและสามารถออกคำสั่งแบบคู่ขนานได้ก็ตาม

โชคดีที่ ASP.NET 2.0 มีโมเดลอะซิงโครนัสเพจที่ใช้ง่ายที่เมื่อใช้ร่วมกับการเรียกเว็บเซอร์วิสแบบอะซิงโครนัส และการเรียกใช้ดาต้าเบสแบบอะซิงโครนัสแล้วจะทำให้เวลาในการตอบสนองของเพจประตูท่าดีขึ้นอย่างมาก เนื่องจาก Web  Parts  อิสระจำนวนมากสามารถเรียกใช้ข้อมูลแบบคู่ขนานได้ ดังนั้นผมจะพูดถึงการสร้าง Web Parts ที่ทำการเรียกข้อมูลแยกมากขึ้น เพื่อทำให้เพจประตูท่าที่เก็บ Web Parts เหล่านี้เอาไว้ตอบสนองและขยายระบบได้ดีขึ้นกว่าเดิม

 

การใช้ Web Part

เรามาเริ่มต้นโดยการพิจารณาตัวอย่างเพจประตูท่าที่แสดงอยู่ในภาพที่ 1 กันก่อน ในตัวอย่างนี้เรามี Web Parts จำนวน  4  ชนิดอยู่ในเพจประตูท่า โดยแต่ละชนิดจะเรียกข้อมูลมาจากแหล่งข้อมูลที่แตกต่างกัน ซอร์ซโค้ดทั้งหมดของแอพพลิเคชันตัวอย่างนี้มีให้ดาวน์โหลดที่เว็บไซต์ของ   MSDN  Magazine  และผมอยากให้คุณทบทวนแอพพลิเคชันดังกล่าวขณะที่คุณกำลังอ่านบทความนี้อยู่ ซึ่งในตัวอย่างนี้มี  Web  Parts สามอันเรียกข้อมูลมาจากเว็บเซอร์วิส โดยมีการรอ  3  วินาทีก่อนที่จะส่งผลลัพธ์กลับมา ส่วน  Web  Parts อันที่ 4 ส่งคิวรี ADO.NET ไปยังดาต้าเบส SQL Server  ซึ่งก็มีการรอ 3 วินาทีเช่นกันก่อนที่จะส่งผลลัพธ์กลับมา แม้ปัญหานี้ดูออกจะเกินจริงอยู่บ้าง แต่ก็มีโอกาสเป็นไปได้

 

ภาพที่ 1 ตัวอย่างเพจประตูท่า

Web  Parts แต่ละอันในแอพพลิเคชันตัวอย่างถูกสร้างขึ้นมาโดยใช้ยูซเซอร์คอนโทรลและเชื่อมโยงผลลัพธ์ของข้อมูลที่ได้รับมาไปยังคอนโทรลที่ใช้แสดงผล โค้ดและมาร์กอัพของคอนโทรลแต่ละอันพยายามทำให้มีจำนวนน้อยที่สุดเพื่อที่ตัวอย่างจะได้เรียบง่ายที่สุด จากนั้นคุณก็จะหันไปให้ความสำคัญกับการทำให้ Web Parts ทำงานแบบอะซิงโครนัสได้

นี่คือตัวอย่างไฟล์ยูซเซอร์คอนโทรล NewsWebPart.ascx

   <%@ Control Language="C#"
           AutoEventWireup="true"
           CodeFile="NewsWebPart.ascx.cs" 
           Inherits="webparts_
           NewsWebPart" %>
   <asp:BulletedList ID="_newsHeadlines"
           runat="server">
   </asp:BulletedList>

public partial class webparts_NewsWebPart : UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        PortalServices ps = new PortalServices();
        _newsHeadlines.DataSource = ps.GetNewsHeadlines();
        _newsHeadlines.DataBind();
    }
}

หมายเหตุ:  ให้คุณลองสังเกตวิธีการที่ Web Parts โต้ตอบกับเว็บเซอร์วิสเพื่อเรียกดูข้อมูลพาดหัวข่าวตัวอย่างดู ในขณะที่  Web Part เรียกดูราคาหุ้นและ Web Part ข้อมูลพยากรณ์อากาศทำงานแบบเดียวกัน แต่ใช้ method ที่ต่างกันของเว็บเซอร์วิสเดียวกันเพื่อดึงข้อมูล สิ่งที่คล้ายคลึงกันก็คือภาพที่     2     แสดงไฟล์ยูซเซอร์คอนโทรล SalesReportWebPart.ascx  และไฟล์โค้ดเบื้องหลังที่เกี่ยวข้องเพื่อใช้กับ  Web Part ตัวอย่างรายงานยอดขาย ให้คุณลองสังเกตวิธีการใช้คอนโทรลใช้  ADO.NET  เพื่อดึงข้อมูลยอดขายมาจากดาต้าเบส แล้วนำเอาข้อมูลดังกล่าวไปใส่ไว้ในคอนโทรล GridView

 

ภาพที่ 3 การประมวลผล Web Part เชิงเส้น

เมื่อเพจประตูท่าตัวอย่างเริ่มทำงาน ปัญหาก็เริ่มเห็นได้อย่างชัดเจนมากขึ้น ระบบต้องใช้เวลามากกว่า 12 วินาทีเพื่อเรียกการประมวลผล ซึ่งเป็นความล่าช้าที่จะทำให้ผู้ใช้ส่วนใหญ่ไม่กลับมาใช้แอพพลิเคชันนี้อีก สาเหตุที่เกิดความล่าช้านานขนาดนี้เหมือนอย่างที่แสดงเอาไว้ในภาพที่  3 มีสาเหตุมาจากเส้นทางที่ใช้ในการประมวลผลคำสั่งขณะที่เพจถูกสั่งงาน สิ่งที่เหมือนกับคอนโทรลอื่นๆในโครงสร้างแยกสาขาคอนโทรลในเพจก็คือ  Web  Part  แต่ละอันจะถูกโหลดเรียงตามลำดับที่กำหนดโดยโครงสร้างแยกสาขาของคอนโทรลที่อยู่ในเพจ การที่การประมวลผลเป็นเชิงเส้น ดังนั้น Web  Part แต่ละอันจึงจำเป็นต้องรอให้ Web Part อันก่อนหน้าในโครงสร้างทำงานให้เสร็จเสียก่อน จึงจะเริ่มต้นเรียกใช้ข้อมูลของตนเองและเตรียมตัวที่จะทำการตอบสนองได้ การที่ความล่าช้าปลอม  3  วินาทีเกิดขึ้นในช่วงของการเรียกใช้ข้อมูล ดังนั้นการตอบสนองทั้งหมดจึงต้องใช้เวลา  12  วินาที Web Part แต่ละอันทำการดึงข้อมูลที่ไม่เกี่ยวข้องกันโดยสิ้นเชิงทีละอันจนกว่าจะเสร็จ สิ่งสำคัญที่พึงตระหนักก็คือการเรียกข้อมูลทั้งหมดควรเกิดขึ้นแบบคู่ขนาน ก็จะทำให้เวลาในการตอบสนองลดลงร้อยละ 75 นั่นคือเป้าหมายที่ผมวางเอาไว้

 

การเรียกใช้เว็บแบบอะซิงโครนัส

ในตัวอย่างนี้  Web Parts สามอันใช้เว็บเซอร์วิสเพื่อดึงข้อมูลของตนเอง และ Web Part อีกอันหนึ่งใช้ ADO.NET เพื่อเรียกใช้ดาต้าเบส เราจะมาเริ่มต้นโดยการทำให้เว็บเซอร์วิสตัวนี้ทำงานแบบอะซิงโครนัสได้ เนื่องจากเครื่องมือ Web  Services  Description  Language ที่ชื่อ WSDL.exe (หรือเครื่องมือ Visual Studio 2005 Add Web  Service  Reference) สามารถสร้างบริการชั้นดีในเว็บเซอร์วิสพร็อกซีคลาสขึ้นมาได้สำหรับการเรียก Web method แบบอะซิงโครนัสนี้ได้

เมื่อมีการสร้างเว็บเซอร์วิสพร็อกซีคลาสขึ้นมาใน  ASP.NET 2.0 ที่จริงแล้วมีการสร้างวิธีการที่แตกต่างกันออกไป 3 แบบสำหรับเรียก method ใดๆขึ้นมา โดยจะเป็นการเรียกแบบซิงโครนัสหนึ่งวิธี และเป็นแบบอะซิงโครนัสสองวิธี ตัวอย่างเช่นเว็บเซอร์วิสพร็อกซีที่     Web     Parts    กำลังใช้อยู่มี    method    เหล่านี้ให้ใช้สำหรับเรียก GetNewsHeadlines Web method ได้

   public string[] GetNewsHeadlines()
   public IAsyncResult BeginGetNewsHeadlines(
       AsyncCallback callback, object asyncState)
   public string[] EndGetNewsHeadlines(       IAsyncResult asyncResult)
   public void GetNewsHeadlinesAsync()
   public void GetNewsHeadlinesAsync(       object userState)
   public event
       GetNewsHeadlinesCompletedEventHandler
       GetNewsHeadlinesCompleted;

method  ชนิดแรกที่ชื่อ GetNewsHeadlines จัดเป็น method ซิงโครนัสแบบมาตรฐาน ส่วน method อีกสองอันก็คือ  BeginGetNewsHeadlines และ EndGetNewsHeadlines สามารถใช้เพื่อเรียก method แบบอะซิงโครนัสได้ และสามารถเชื่อมโยงเข้าหากลไกอะซิงโครนัสมากน้อยขนาดไหนก็ได้ใน    .NET    ผ่านทางอินเทอร์เฟซ IASyncResult แบบมาตรฐาน

แต่  method  ที่น่าสนใจที่สุดตามแนวทางนี้ก็คือ  method อันสุดท้ายที่ชื่อ GetNewsHeadlinesAsync การที่จะใช้ method  นี้ได้ ผมต้องลงจองสร้าง delegate ตัวหนึ่งขึ้นมาพร้อมกับเหตุการณ์ของพร็อกซีคลาส ที่ถูกสร้างขึ้นมาเพื่อรวบรวมผลลัพธ์ของคำสั่งแบบอะซิงโครนัส  (ในตัวอย่างนี้ก็คือ  GetNewsHeadlinesCompleted  event) จากนั้น delegate  signature  จะถูกกำหนดให้รับค่าที่คืนมาของ method เพื่อที่ผมจะได้ตัดต่อผลลัพธ์ใน method ไปใช้งาน

การใช้  method  อะซิงโครนัสที่อิงกับเหตุการณ์นี้ ช่วยให้การแก้ไขคำสั่ง Web method ที่อยู่ใน Web Part ข่าวพาดหัวให้สามารถทำงานแบบอะซิงโครนัสเป็นเรื่องที่ทำได้ง่ายมากเหมือนอย่างที่แสดงเอาไว้ในภาพที่ 4 ก่อนอื่นผมทำการจองตัวแทนให้แก่    GetNewsHeadlinesCompleted    event    ของพร็อกซีคลาส ตามด้วยการเรียก GetNewsHeadlinesAsync        method       ส่วนวิธีการใช้       method       ที่จองเอาไว้ให้แก่ GetNewsHeadlinesCompleted  event ผมได้เชื่อมผลลัพธ์ของการเรียก Web method ไปยัง BulletedList เพื่อส่งการแสดงผลไปยังไคล์เอ็นต์ สิ่งที่จำเป็นต้องพิจารณาอีกอย่างหนึ่งก็คือ method อะซิงโครนัสเหล่านี้จะทำงานได้ก็ต่อเมื่อ  Web  Part  ถูกใส่เอาไว้ในเพจโดยมีการกำหนดค่าของ  Async  ให้เป็น  true เท่านั้น ซึ่งคุณสามารถตรวจสอบการเขียนโปรแกรมได้โดยเข้าไปดูที่  IsAsync property ของเพจที่เก็บ Web Parts เอาไว้ ถ้าหากเพจที่ใส่  Web  Part  เอาไว้ไม่ได้มีค่าเป็นอะซิงโครนัส ผมจึงต้องใช้การเชื่อมโยงอะซิงโครนัสแบบมาตรฐานแทนเหมือนอย่างที่แสดงเอาไว้ในภาพที่ 4

ในตอนนี้เพื่อทำให้   Web  Part  อะซิงโครนัสเรียกข้อมูลแบบอะซิงโครนัสได้ มันจะต้องใส่เอาไว้ในเพจที่ตัวแปร Async กำหนดให้เป็น true ดังนั้นผมจึงได้ทำการแก้ไข Page directive ของเพจประตูท่าให้มีหน้าตาแบบนี้

<%@ Page Language="C#" AutoEventWireup="true"  Async="true" %>

หลังจากที่ผมทำการแก้ไข Web Parts อีกสองอันที่ใช้เว็บเซอร์วิสเพื่อดึงข้อมูลแบบอะซิงโครนัสแล้ว เพจประตูท่าก็จะตอบสนองได้ดีขึ้นกว่าเดิมมาก ที่จริงแล้วมันอาจแสดงผลไปยังไคล์เอ็นต์โดยใช้เวลาแค่  3 วินาทีเท่านั้น ขึ้นอยู่กับลำดับการโหลด Web Parts (ถ้าหากมีการโหลด Web Parts รายงานยอดขายก่อน มันจะใช้เวลามากกว่า 6 วินาที) แม้ว่า  Web  Part รายงานยอดขายยังคงเรียกใช้ดาต้าเบสเชิงเส้นอยู่ก็ตาม แต่ในตอนนี้ Web Parts อื่นๆอีก 3 อันจะสั่งงานเว็บเซอร์วิสแบบอะซิงโครนัส ดังนั้นคำสั่งของการทำงานหลักจึงไม่จำเป็นต้องรอให้ Web Part อื่นๆทำงานเสร็จอีกต่อไป แน่ละผมต้องการให้งานทั้งหมดที่เกี่ยวข้องกับ I/O ทำงานแบบอะซิงโครนัสได้ เพื่อที่ไคล์เอ็นต์จะมีโอกาสใช้ทั้งเว็บเซอร์วิสและ Web Part ที่อิงกับดาต้าเบสได้โดยที่ไม่ต้องรออีกต่อไป

เหตุผลอื่นๆที่จะดัดแปลงให้งานที่เกี่ยวข้องกับ  I/O  กลายเป็นการเรียกใช้  I/O  แบบอะซิงโครนัสก็คือการช่วยให้การทำงานหลักกลับมาอยู่ในกลุ่มการทำงานเร็วขึ้นเพื่อช่วยให้สามารถให้บริการคำสั่งอื่นๆได้ ถ้าหากตอนนี้ผมดึงงานหลักกลับมาก็ต่อเมื่อการคิวรีดาต้าเบสรายงานยอดขายเสร็จแล้วเท่านั้น นั่นหมายความว่าผมต้องรอเฉยๆ  3  วินาทีเต็มๆ ในขณะที่กลุ่มการทำงานน่าจะถูกใช้ไปให้บริการคำสั่งอื่นๆได้ ดังนั้นถ้าหากผมสามารถทำให้คำสั่งที่เกี่ยวกับ I/O   อันสุดท้ายนี้เรียกใช้ข้อมูลแบบอะซิงโครนัสได้เช่นกัน เพจของผมก็จะใช้คำสั่งดังกล่าวโดยใช้เวลานานเท่ากับการทำ spool ให้คำสั่ง I/O แบบอะซิงโครนัสทั้งหมดเท่านั้นก็จะย้อนกลับมายังกลุ่มทำงานหลักได้

 

วิธีการทำงาน

ถ้าหากคุณเคยเขียนโปรแกรมอะซิงโครนัสมาก่อน คุณอาจมีความรู้สึกว่าการเปลี่ยนแปลงเล็กน้อยกับคำสั่งเว็บเซอร์วิสน่าจะยังไม่พอ ผมยังไม่ได้เข้าไปยุ่งกับอินเทอร์เฟซ  IAsyncResult  เลย แถมยังไม่ได้บอกให้เพจที่เก็บเว็บเซอร์วิสเอาไว้ทราบว่า ผมได้ทำงานแบบอะซิงโครนัสอยู่ (โดยการจองงานหรือการใช้เทคนิคอื่นๆ) แต่ดูเหมือนมันก็ใช้งานได้เหมือนอย่างที่ผมหวังเอาไว้

ความลับอยู่ตรงที่การใช้      method      แบบอะซิงโครนัสของเว็บเซอร์วิสพร็อกซีคลาส รวมทั้งคลาสที่ชื่อ AsyncOperationManager   ของ   Microsoft  .NET  Framework  2.0  ที่เข้ามาช่วย ถ้าหากผมเรียก GetNewsHeadlinesAsync  method  ของพร็อกซีคลาส ระบบจะทำการเทียบการเรียกกับ method ตัวช่วยที่ชื่อ InvokeAsync  ซึ่งอยู่ภายในคลาสพื้นฐานที่ชื่อ  SoapHttpClientProtocol โดยที่พร็อกซีคลาสก็มาจากที่นี่นั่นเอง InvokeAsync  ทำงานสำคัญ  2 ประการก็คือมันจะจองการทำงานอะซิงโครนัสโดยการเรียก CreateOperation method        ของ        AsyncOperationManager        จากนั้นก็เรียกคำสั่งแบบอะซิงโครนัสโดยใช้ BeginGetReguestStream ของคลาส WebRequest

เมื่อถึงจุดนี้จะมีการส่งค่ากลับมา และเพจจะเริ่มต้นการประมวลผลวงจรชีวิตของมัน แต่การที่เพจมีการกำหนดให้ Async เป็น true อยู่ ดังนั้นมันจะยังคงประมวลผลคำสั่งต่อไปผ่านทาง PreRender event และจะมีการส่งงานคำสั่งกลับไปยังกลุ่มทำงานหลังจากที่ทำคำสั่งเก็บแบบอะซิงโครนัสเสร็จแล้ว ระบบจะเรียก method ที่ผมจองเอาไว้กับ GetNewsHeadlinesCompleted  event  ของพร็อกซีในงานแยกต่างหากซึ่งดึงมาจากกลุ่มงาน I/O ถ้าหากงานนี้เป็นงานอะซิงโครนัสงานสุดท้ายที่ทำเสร็จ  (โดยมี  AsyncOperationManager  คอยเฝ้าติดตามดูอยู่) เพจจะถูกเรียกกลับมา และคำสั่งจะประมวลผลจนเสร็จงานที่ค้างอยู่โดยเริ่มจาก  PreRender Complete event ภาพที่ 5 แสดงวงจรชีวิตทั้งหมดเมื่อคุณใช้คำสั่งเว็บอะซิงโครนัสในขอบเขตของเพจแบบอะซิงโครนัส

 

ภาพที่ 5 คำสั่งอะซิงโครนัสในเพจอะซิงโครนัส

AsyncOperationManager เป็นคลาสที่ถูกออกแบบมาเพื่อใช้ในสภาพแวดล้อมต่างๆสำหรับบริหารคำสั่ง method อะซิงโครนัสโดยตรง ตัวอย่างเช่นถ้าหากผมเรียกเว็บเซอร์วิสแบบอะซิงโครนัสจากแอพพลิเคชัน  Windows  Forms แล้วละก็ เว็บเซอร์วิสจะเชื่อมโยงกับคลาส AsyncOperationManager ด้วย ความแตกต่างของสภาพแวดล้อมแต่ละแบบก็คือ  SyncronizationContext  เกี่ยวข้องกับ  AsyncOperationManager ถ้าหากสั่งงานในขอบเขตของแอพพลิเคชัน   ASP.NET   แล้ว  SynchronizatioinContext  จะถูกกำหนดให้เป็น  instance  ของคลาส AspNetSynchronizationContext     จุดมุ่งหมายหลักตรงนี้ก็คือการคอยเฝ้าติดตามว่ายังมีคำสั่งอะซิงโครนัสอีกมากน้อยขนาดไหนที่ยังรออยู่ ดังนั้นเมื่อคำสั่งเหล่านี้ทำงานเสร็จแล้ว การประมวลผลคำสั่งของเพจก็จะทำต่อไป ในทางตรงกันข้าม ถ้าหากอยู่ในแอพพลิเคชันประเภท Windows Forms แล้ว SynchronizationContext จะถูกกำหนดให้เป็น  instance  ของคลาส  Windows Forms SynchronizatioinContext จุดมุ่งหมายหลักตรงนี้ก็คือการช่วยให้ควบคุมคำสั่งจากงานแบกกราวน์ไปยังงาน UI ได้ง่ายขึ้น

 

การเรียกใช้ข้อมูลแบบอะซิงโครนัส

ในตอนนี้เราจะย้อนกลับไปหาปัญหาการสร้าง  Web  Part  อันสุดท้ายให้ทำงานแบบอะซิงโครนัสได้ และปัญหาทั่วไปของการเรียกข้อมูลแบบอะซิงโครนัสโดยใช้  ADO.NET  โชคไม่ดีที่ไม่มีวิธีที่เท่าเทียมกับกลไกอะซิงโครนัสแบบง่ายๆที่เว็บเซอร์วิสพร็อกซีสามารถนำไปใช้เพื่อเรียกข้อมูลแบบอะซิงโครนัสได้ ดังนั้นผมจึงจำเป็นต้องทำงานเพิ่มเติมอีกเล็กน้อยเพื่อทำให้  Web  Part  อันสุดท้ายนี้ทำงานแบบอะซิงโครนัสได้ ผมสามารถทำงานกับ method อะซิงโครนัสอันใหม่ในคลาส  SqlCommand  รวมทั้งคุณสมบัติการทำงานแบบอะซิงโครนัสของ ASP.NET ได้ การใช้ SqlCommand ช่วยให้ในตอนนี้ผมสามารถเรียกคำสั่งแบบอะซิงโครนัสได้โดยใช้ methods ต่างๆดังต่อไปนี้

  • IAsyncResult BeginExecuteReader(AsyncCallback ac, object state)
  • IAsyncResult BeginExecuteNonQuery(AsyncCallback ac, object state)
  • IAsyncResult BeginExecuteXmlReader(AsyncCallback ac, object state)

และในตอนนี้ผมสามารถเรียก method ที่ช่วยทำงานให้เสร็จ หลังจากที่สตริงข้อมูลพร้อมแล้วโดยเริ่มการอ่าน

  • SqlDataReader EndExecuteReader(IAsyncResult ar)
  • int EndExecuteNonQuery(IAsyncResult ar)
  • XmlReader EndExecuteXmlReader(IAsyncResult ar)

ถ้าหากต้องการใช้ method เรียกข้อมูลแบบอะซิงโครนัสเหล่านี้ คุณต้องเพิ่ม "async=true" ลงไปในสตริงเชื่อมต่อเสียก่อน ซึงถ้าหากดูจากตัวอย่างของเรา ผมต้องการใส่ข้อมูลลงไปใน GridView โดยการเชื่อมโยง GridView กับ SqlDataReader ดังนั้นผมจะใช้ BeginExecuteReader method เพื่อเริ่มการเรียกแบบอะซิงโครนัส

นอกจากนั้นเพื่อเป็นการเชื่อมโยงเข้าหาเพจอะซิงโครนัส  ASP.NET 2.0 ยังยอมให้คุณจองงานอะซิงโครนัสที่จำเป็นต้องประมวลผลก่อนที่เพจจะทำการแสดงผลเสร็จอีกด้วย โมเดลนี้มีความชัดเจนมากกว่าโมเดลที่ผมใช้กับเว็บเซอร์วิสพร็อกซี และมีความคล่องตัวมากกว่าด้วย ถ้าหากผมต้องการจองงานอะซิงโครนัส ผมจะสร้าง intance ของคลาส  PageAsyncTask  ขึ้นมา จากนั้นก็สั่งให้มันเริ่มทำงานโดยใช้ตัวแทน  3 ชนิดก็คือ begin handler, end handler  และ  timeout handler โดยที่ begin handler จำเป็นต้องคืนอินเทอร์เฟซ LAsyncResult กลับมา ซึ่งตรงนี้จะเป็นจุดที่ผมเรียกคำสั่งข้อมูลแบบอะซิงโครนัสโดยใช้  BeginExecuteReader จากนั้นจะมีการเรียก end  handler เมื่องานเสร็จแล้ว (เมื่อมีข้อมูลพร้อมที่จะอ่านขึ้นมาได้ในตัวอย่างนี้) เพื่อที่ผมจะนำเอาผลลัพธ์ไปใช้ได้ APS.NET จะเป็นตัวคอยจัดการการเรียก begin handler ขึ้นมา ก่อนที่ปลดระหว่างงานคำสั่งเรียกข้อมูล (ทันทีหลังจากที่  PreRender event ทำงานเสร็จ) ภาพที่ 6 แสดงการอัพเดต Web Part รายงานยอดขาย ซึ่งมีการเรียกข้อมูลแบบอะซิงโครนัสโดยใช้การทำงานอะซิงโครนัสและ   BeginExecuteReader   อะซิงโครนัสของคลาส SqlCommand

หมายเหตุ: ผมใช้เทคนิคเดียวกันนี้กับการเรียกใช้เว็บเซอร์วิส โดยการใช้ methods อะซิงโครนัสอันอื่นที่อยู่ในพร็อกซีคลาส  (ตัวอย่างเช่น  BeginGetNewsHeadlines เป็นต้น) ปมเด่นอย่างหนึ่งของเทคนิคนี้ก็คือผมสามารถกำหนด timeout  handler ได้ ถ้าหากคำสั่งรีโมทไม่สามารถส่งค่ากลับมาได้ทันเวลา ระบบจะเรียก timeout handler ที่เกี่ยวข้องกันขึ้นมาแทน  timeout  handler ตัวนี้กำหนดเอาไว้ใน Page directive โดยใช้ AsyncTimeout attribute และกำหนดเวลาปกติเป็น 20 วินาที

สิ่งที่ผมอยากบอกอีกอย่างหนึ่งก็คือสิ่งที่ต่างจากการใช้รูปแบบอะซิงโครนัสที่อิงกับเหตุการณ์ก็คือ เมื่อมีการใช้  Page.RegisterAsyncTask   แล้ว ผมไม่จำเป็นต้องแยกไปยังคำสั่งอะซิงโครนัสที่อิงกับผลลัพธ์ของ  Page.IsAsync อีกครั้ง การจัดการเพจอะซิงโครนัสใน Web Parts ทำงานได้เป็นอย่างดีในเพจซิงโครนัส แถมยังยอมให้มีการประมวลผล  Web Parts แบบคู่ขนานอีกด้วย ความแตกต่างหลักก็คือในเพจซิงโครนัส (เพจที่ไม่ได้กำหนดตัวแปร Async เป็น true) งานหลักของเพจจะไม่ได้ถูกปล่อยกลับมายังกลุ่มทำงานในช่วงการประมวผลลอะซิงโครนัส

ในตอนนี้เมื่อ  Web  Parts  ทั้งหมดสามารถทำงานแบบอะซิงโครนัสได้แล้ว ในตอนนี้ผมสามารถใช้  Web  Part เหล่านี้ได้ในเพจใดๆที่เป็นแบบอะซิงโครนัสได้ และผมจะมั่นใจว่าเวลาตอบสนองจะไม่เท่ากับเวลารวมที่    Web Parts  ทั้งหมดใช้ในการดึงข้อมูลอีกต่อไป แต่จะเป็นเวลาสูงสุดของ Web Part ตัวใดตัวหนึ่งเท่านั้น การกำหนดให้เพจเป็นแบบอะซิงโครนัสและใช้   Web  Parts  ให้ทำงานกับ  I/O  แบบอะซิงโครนัสจะช่วยให้ความสามารถในการขยายเว็บไซต์ดีขึ้นอย่างมาก เนื่องจากเพจจะเปิดโอกาสให้การทำงานหลักให้บริการไคล์เอ็นต์อื่นๆที่รอข้อมูลอยู่ได้

ของแถมอีกอย่างหนึ่งก็คือถ้าหากคุณสร้างไซต์ประตูท่าโดยใช้ ASP.NET 2.0 คุณควรจำเอาไว้ว่าคุณสมบัติอะซิงโครนัสแบบใหม่ทั้งหมดเพิ่งมีอยู่ในซอฟต์แวร์เวอร์ชันนี้ และคุณควรนำเอาคุณสมบัติเหล่านี้ไปใช้ปรับปรุงอัตราการตอบสนองและความสามารถในการขยายระบบของแอพพลิเคชันของคุณเอง ถ้าหากต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับบริการอะซิงโครนัสใน ASP .NET 2.0 ให้คุณเข้าไปดูคอลัมน์ Wicked Code ของ Jeff Prosise นิตยสาร MSDN เดือนตุลาคม ปี 2005

Filed under: ,
No Comments

Leave a Comment

(required)  
(optional)
(required)  
Add