Matt Powell的《Server-Side 非同步Web Methhods》

來源:互聯網
上載者:User
server|web|非同步|非同步 摘要:Matt Powell 介紹了如何在伺服器端使用非同步 Web 方法,來建立高效能的 Microsoft ASP.NET Web 服務。

  簡介

  在九月份的第三篇專欄(英文)中,我談到了利用 Microsoft? .NET Framework 的用戶端功能通過 HTTP 非同步呼叫 Web 服務的問題。這種調用 Web 服務的方法非常有用,使用時不必鎖定您的應用程式或產生過多後台線程。現在我們瞭解一下在伺服器端提供類似功能的非同步 Web 方法。非同步 Web 方法在編寫 ISAPI 擴充方面具有與 HSE_STATUS_PENDING 方法類似的高效能,但不需要為管理自己的線程池編寫代碼,同時又具有以Managed 程式碼方式啟動並執行所有優點。   首先我們考慮一下常規的同步 Microsoft? ASP.NET Web 方法。當您從同步 Web 方法返回時,將發送對該方法的響應。如果需要較長的時間來完成請求,則處理請求的線程會一直被佔用,直到方法調用結束。不幸的是,多數較長的調用是由較長的資料庫查詢或對另一個 Web 服務的調用等事件引起的。例如,如果您調用資料庫,當前線程會一直等待調用完成。線程無事可做,只是等待,直至聽到查詢的返回。當線程等待完成對 TCP 通訊端或後端 Web 服務的調用時,也會出現類似的問題。

  讓線程處於等待狀態很不好,特別是在伺服器的運行壓力很大的情況下。等待中的線程不會進行任何有效工作,例如為其他請求提供服務。我們需要找到一種方法,能夠在伺服器上開始較長的後台進程,同時又能將當前線程返回到 ASP.NET 進程池。然後,當較長的後台進程完成時,我們調用一個回呼函數,結束對請求的處理,並通過某種方式通知 ASP.NET 請求已完成。實際上,這種功能可由 ASP.NET 使用非同步 Web 方法提供。

  非同步 Web 方法的工作原理

  當您使用 Web 方法編寫典型的 ASP.NET Web 服務時,Microsoft? Visual Studio? .Net 只是編譯您的代碼以建立程式集;當收到對其 Web 方法的請求時,將調用該程式集。程式集本身並不知道關於 SOAP 的任何事情。因此,當您的應用程式初次開機時,ASMX 處理常式必須反映您的程式集,以確定提供哪些 Web 方法。對於常規的同步請求,這些操作都很簡單:找出哪些方法具有關聯的 WebMethod 屬性、基於 SOAPAction HTTP 標題來設定調用正確方法的邏輯。

  對於非同步請求,在反映過程中,ASMX 處理常式尋找具有某種簽名並將簽名識別為非同步 Web 方法。該處理常式將尋找符合以下規則的方法對:

  BeginXXX 和 EndXXX Web 方法,其中 XXX 是任一字元串,表示要提供的方法的名稱。
  BeginXXX 函數返回一個 IAsyncResult 介面,並分別接受 AsyncCallback 和一個對象,作為其最後兩個輸入參數。
  EndXXX 函數接受一個 IAsyncResult 介面,作為其唯一的參數。

  兩個方法都必須使用 WebMethod 屬性進行標識。

  如果 ASMX 處理常式發現兩個方法符合上述所有條件,則將方法 XXX 作為常規的 Web 方法在其 WSDL 中提供。該方法將接受在 BeginXXX 的簽名中的 AsyncCallback 參數之前定義的參數作為輸入,並返回由 EndXXX 函數返回的內容。因此,如果某個 Web 方法具有如下同步聲明:



  [WebMethod]
  public string LengthyProcedure(int milliseconds) {...}





  則非同步聲明將為:




  [WebMethod]
  public IAsyncResult BeginLengthyProcedure(
              int milliseconds,
              AsyncCallback cb,
              object s) {...}

  [WebMethod]
  public string EndLengthyProcedure(IAsyncResult call) {...}





  每個方法的 WSDL 都是相同的。

  在 ASMX 處理常式反映程式集並檢測到某個非同步 Web 方法後,它必須以不同於處理同步請求的方式處理對該方法的請求。它將調用 BeginXXX 方法,而不是某個簡單方法。它將傳入的請求還原序列化到要傳遞到函數的參數中(與處理同步請求時一樣);但是它還將指標傳遞到一個內部回呼函數(作為 BeginXXX 方法的額外 AsyncCallback 參數)。

  這種方法類似於 .NET Framework 中 Web 服務用戶端應用程式的非同步編程模式。如果用戶端支援非同步 Web 服務調用,則可以為用戶端電腦釋放佔用的線程;如果伺服器端支援非同步 Web 服務調用,則可以釋放伺服器電腦上佔用的線程。但這裡有兩個關鍵的區別。首先,不是由伺服器代碼調用 BeginXXX 和 EndXXX 函數,而是由 ASMX 處理常式調用。其次,您要為 BeginXXX 和 EndXXX 函數編寫代碼,而不能使用由 WSDL.EXE 或 Visual Studio .NET 中的 Add Web Reference(添加 Web 參考)嚮導產生的程式碼。但結果是相同的,即釋放線程以使其能夠執行其他進程。

  ASMX 處理常式調用伺服器的 BeginXXX 函數後,會將線程返回到進程線程池,使之能夠處理接收到的任何其他請求。但是,還不能釋放請求的 HttpContext。ASMX 處理常式將等待,直到它傳遞給 BeginXXX 函數的回呼函數被調用,它才結束處理請求。

  一旦回呼函數被調用,ASMX 處理常式將調用 EndXXX 函數,使您的 Web 方法可以完成任何所要執行的處理,並且可以得到被序列化到 SOAP 響應中的返回資料。EndXXX 函數返回後將發送響應,只有此時該請求的 HttpContext 才得到釋放。







簡單的非同步 Web 方法

  為舉例說明非同步 Web 方法,我從一個名為 LengthyProcedure 的簡單同步 Web 方法開始,其代碼如下所示。然後我們再看一看如何非同步完成相同的任務。LengthyProcedure 只佔用給定的毫秒數。



[WebService]
public class SyncWebService : System.Web.Services.WebService
{
  [WebMethod]
  public string LengthyProcedure(int milliseconds)
  {
    System.Threading.Thread.Sleep(milliseconds);
    return "成功";
  }
}





  現在我們將 LengthyProcedure 轉換為非同步 Web 方法。我們必須建立如前所述的 BeginLengthyProcedure 函數和 EndLengthyProcedure 函數。請記住,我們的 BeginLengthyProcedure 調用需要返回一個 IAsyncResult 介面。這裡,我打算使用一個委託以及該委託上的 BeginInvoke 方法,讓我們的 BeginLengthyProcedure 調用進行非同步方法呼叫調用。傳遞到 BeginLengthyProcedure 的回呼函數將被傳遞到委託上的 BeginInvoke 方法,從 BeginInvoke 返回的 IAsyncResult 將被 BeginLengthyProcedure 方法返回。

  當委託完成時,將調用 EndLengthyProcedure 方法。我們將調用委託上的 EndInvoke 方法,以傳入 IAsyncResult,並將其作為 EndLengthyProcedure 調用的輸入。返回的字串將是從該 Web 方法返回的字串。下面是其代碼:




[WebService]
public class AsyncWebService : System.Web.Services.WebService
{
  public delegate string LengthyProcedureAsyncStub(
    int milliseconds);

  public string LengthyProcedure(int milliseconds)
  {
    System.Threading.Thread.Sleep(milliseconds);
    return "成功";
  }

  public class MyState
  {
    public object previousState;
    public LengthyProcedureAsyncStub asyncStub;
  }

  [ System.Web.Services.WebMethod ]
  public IAsyncResult BeginLengthyProcedure(int milliseconds,
    AsyncCallback cb, object s)
  {
    LengthyProcedureAsyncStub stub
      = new LengthyProcedureAsyncStub(LengthyProcedure);
    MyState ms = new MyState();
    ms.prev



相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。