可靠的 XML Web Service (2)

來源:互聯網
上載者:User
web|xml 標題的作用
在查看代碼之前,我們需要瞭解一下 SOAP 主題,即標題。SOAP 1.1 規範中談論最少的內容之一就是 SOAP 標頭。標題提供了一種擴充訊息處理體繫結構的簡單方法。SOAP 1.1 規範中提到:標題在實現與訊息主體沒有特定關係的處理規則(例如驗證和交易管理)時非常有用。對任何類型的訊息來說,SOAP 標頭都是以獨立方式對可靠性資訊進行編碼的完美解決方案。規範中還概述了實施和處理這些標題的標準和規則。

下面我們來看看如何?包含可靠性資訊的 SOAP 標頭。首先要為標題確定架構。這很重要,因為它正是終端使用者在支援該標題的 Web 服務的 WSDL 檔案中看到的實際效果。對於此實現方案,我直接將處理 API 映射到 SOAP 標頭。

我來解釋一下。在我的處理 API 中有一個名為 ReliabilityInfo 的類。對此類進行執行個體化時,它將在運行時變成動態對象。也就是說,您可以從可靠性的角度設定確定如何處理出站訊息的屬性。此對象還可以在運行時序列化為 SOAP 標頭。下面是該類及其成員的一個快照。為了清楚起見,我刪除了具體的實現和私人成員。

[XmlRootAttribute(ElementName="ReliableHeader", _
   Namespace="http://ericRP/ReliableHeader/2001/", IsNullable=false)]
   public class ReliabilityInfo : SoapHeader
   {      
      public string Destination{}
      public string ConversationId{}
      public int MessageId{}
      public MessageStatus Status{}
      public DateTime SendDate{}
      public DateTime ExpireDate{}
      public string AckURL{}
public enum MessageStatus{}

[XmlIgnore]
      public int MaxRetry{}
      [XmlIgnore]
      public string Text{}
   }

序列化為出站 SOAP 訊息時,標題如下所示:

<soap:Header>
<ReliableHeader xmlns="http://ericRP/ReliableHeader/2001/">
<ConversationId>b9e029e1-af0f-42cb-83b0-7888f9e3ffc4</ConversationId>
<MessageId>1</MessageId>
<Status>新</Status>
<SendDate>2001-11-06T14:59:02.1021226-08:00</SendDate>
<ExpireDate>2001-11-06T18:59:02.1021226-08:00</ExpireDate>
<AckURL>http://localhost:8082/ericRPAck/POAck.asmx</AckURL>
</ReliableHeader>
</soap:Header>

這是通過 .NET 架構中兩個非常重要的類實現的。基本 XML 序列化塊使用 System.Xml.Serialization 名稱空間類來進行處理。這兩個類一個是 XmlRootAttribute 屬性類,我使用它告訴序列化程式將文檔片段的根稱為 ReliableHeader,並將它與名稱空間相關聯。此後,所有公用成員也同樣會被序列化,除非您告訴序列化程式忽略該成員。我使用的另一個重要名稱空間是 System.Web.Services.Protocols。具體地說,即 SoapHeader 類。從該類進行繼承時,它會自動將序列化的 XML 加入到 SOAP 訊息中。本文稍後將論述如何將標題加入訊息。

這非常強大,因為我不僅可以使用類型明確的、編譯好的對象作為標題的基礎,而且在這些類的成員內部還有特定的實現。

綜述
好啦,上面只是對可靠性進行了簡單的論述,並闡述了我自己的規範。下面讓我們看一看它的代碼。

擴充 Web 服務用戶端代理
第一步是重新設定現有的 .NET Web 服務用戶端代理。記住,此協議可以在任何 SOAP 處理引擎中實現。我選擇了 .NET 架構,因為它便於使用、基於標準且可擴充。

選取一個現有的 Web 服務用戶端代理(例如 PurchaseOrderProxy),然後添加以下代碼:

該類中必須有名為 ReliableHeader 的公用成員,並且其類型必須為 ericRP.ReliabilityInfo。此成員將在運行時通過調用用戶端進行設定。稍後將使用此成員為出站訊息提供標題資訊,並提供在跟蹤過程中應用了該標題的訊息的狀態資訊。例如:
public class PurchaseOrderProxy :
      System.Web.Services.Protocols.SoapHttpClientProtocol
   {
      public ReliabilityInfo ReliableHeader;
      
      //為了清楚起見,此處省略了其他代碼
   }

在 Web 服務用戶端代理中調用的方法必須使用以下屬性進行批註:
[SoapHeader("ReliableHeader", Required=true)]

在序列化過程中,此屬性將在運行時把適當的標題值加入到出站 SOAP 訊息中。此處的 SubmitMessage 方法使用 SoapHeader 屬性進行標記。注意,ReliableHeader 是在步驟 1 中實現的成員,而且是必須的。也就是說,如果不在運行時設定此成員,將產生異常。例如:

[SoapHeader("ReliableHeader", Required=true)]
public void SubmitMessage(object message)
{
this.Invoke("SubmitMessage", new object[] {message});      
}
   
在 Web 服務用戶端代理中調用的方法必須包含以下屬性:
[ericRP.Client.RPClientTrace.TraceExtension()]

此屬性工作表示該方法支援自訂 SOAP 延伸模組。在訊息被序列化之前和之後、且在訊息被發送至底層傳輸機制之前,這種 SOAP 延伸模組將在運行時被調用。我通常是在訊息從用戶端電腦發送出去之前,對它進行一些簡單的跟蹤和記錄。稍後再查看此擴充的實現情況。例如:

[ericRP.Client.RPClientTrace.TraceExtension()]
[SoapHeaderAttribute("ReliableHeader", Required=true)]
public void SubmitMessage(object message)
{
this.Invoke("SubmitMessage", new object[] {message});      
}

該類必須從 ericRP.Client.RPClientTrace.IClientTrace 實現。這種介面實現方案提供了基本的跟蹤功能,以檢查調用程式是否支援特定的跟蹤協議。在後面的跟蹤功能中可以看到此代碼。例如:
public class PurchaseOrderProxy :
   System.Web.Services.Protocols.SoapHttpClientProtocol,
   ericRP.Client.RPClientTrace.IClientTrace
{
public ReliabilityInfo ReliableHeader;
   }

最後,該類必須實現 IClientTrace.GetReliabilityInfo 函數,該函數是 IClientTrace 介面要求的唯一函數。這是一個簡單的機制,用戶端可以使用它在運行時將訊息的狀態資訊發送到Tracing Service。例如:
public class PurchaseOrderProxy :
   System.Web.Services.Protocols.SoapHttpClientProtocol,
   ericRP.Client.RPClientTrace.IClientTrace
{
public ReliabilityInfo ReliableHeader;

ericRP.ReliabilityInfo ericRP.Client.RPClientTrace.IClientTrace.GetReliabilityInfo()
{      
return ReliableHeader;
}
   }

看起來代碼可能很多,但實際上卻很簡單。事實上,如果時間再多一些,我可以建立從 SoapHttpClientProtocol 繼承的新類並明確加以實現,但這種方式對於伺服器端來說會更有趣。

擴充 Web 服務伺服器存根
下一步,我們來擴充現有的 Web 服務伺服器存根。選取一個現有的 .NET Web 服務類(例如 ProcessPurchaseOrder),然後添加以下代碼:

該類中必須有一個類型為 ericRP.ReliabilityInfo 的公用成員 ReliableHeader。稍後將使用此成員為入站訊息提供還原序列化標題資訊,並提供在跟蹤過程中應用了該標題的訊息的狀態資訊。例如:
public class ProcessPurchaseOrder :
      System.Web.Services.WebService
   {
      public ReliabilityInfo ReliableHeader;
   }

在 Web 服務存根中調用的方法必須使用以下屬性進行批註:
[SoapHeader("ReliableHeader", Required=true)]

在還原序列化過程中,此屬性將在運行時對入站 SOAP 訊息中適當的標題值進行還原序列化。此處的 SubmitMessage 方法使用 SoapHeader 屬性進行標記。例如:

[WebMethod]
[SoapHeader("ReliableHeader", Required=true)]
public void SubmitMessage(object message)
{
//為了清楚起見,此處省略了一些代碼   
}

在 Web 服務存根中調用的方法必須使用以下屬性進行批註:
[ericRP.Server.RPServerTrace.TraceExtension()]

此屬性工作表示該方法支援自訂 SOAP 延伸模組。稍後再查看此擴充的實現情況。

注意:此擴充與用戶端擴充功能不同。
例如:

[SoapHeader("ReliableHeader", Required=true)]
[ericRP.Server.RPServerTrace.TraceExtension()]
public void SubmitMessage(object message)
{
//為了清楚起見,此處省略了一些代碼   
}

在 Web 服務存根中調用的方法必須使用以下屬性進行批註:
[SoapDocumentMethod(OneWay=true)]

此屬性工作表示被調用的函數不傳回值。更具體地說,即一旦訊息被還原序列化,此屬性就會強制 Web 服務向用戶端返回 HTTP 202 響應。對於分離訊息的最終處理來說,這不失為一個有效機制,否則,用戶端就不得不同步地等待服務返迴響應。例如:

[WebMethod]
[SoapDocumentMethod(OneWay=true)]
[SoapHeader("ReliableHeader", Required=true)]
[ericRP.Server.RPServerTrace.TraceExtension()]
public void SubmitMessage(object message)
{
//為了清楚起見,此處省略了一些代碼   
}

該類必須從 ericRP.Server.RPServerTrace.IServerTrace 實現。這種介面實現方案提供了基本的跟蹤功能,以檢查調用程式是否支援特定的跟蹤協議。在後面的跟蹤功能中可以看到此代碼。例如:
public class ProcessPurchaseOrder :
System.Web.Services.WebService, ericRP.Server.RPServerTrace.IServerTrace
   {
      public ReliabilityInfo ReliableHeader;
   }

最後,該類必須實現 IServerTrace.GetReliabilityInfo 函數。這是 IServerTrace 介面要求的唯一函數。例如:
public class ProcessPurchaseOrder :
System.Web.Services.WebService, ericRP.Server.RPServerTrace.IServerTrace
   {
      public ReliabilityInfo ReliableHeader;

ericRP.ReliabilityInfo ericRP.Server.RPServerTrace.IServerTrace.GetReliabilityInfo()
      {   
         return ReliableHeader;
      }
   }

好啦,現有的 Web 服務用戶端和伺服器已準備就緒。下面我們來看看 SoapExtension 是如何工作的。

查看 RPClientTrance 和 RPServerTrace
為了實現可靠性處理,我決定使用 SoapExtension。SoapExtension 是一個可繼承的基類,使用它可以跟蹤 SOAP 訊息的出站序列化和入站還原序列化。正是在這個跟蹤過程中,對訊息進行記錄並檢查其狀態。記得前面講過,Web 服務用戶端代理方法實現 [ericRP.Client.RPClientTrace.TraceExtension()]。當調用該方法時,此屬性將在 SOAP 訊息出站序列化時調用以下代碼。

需要特別指出的主要函數是 ProcessMessage。發送出站訊息時,ProcessMessage 將提供有關該訊息序列化之前和之後的全部狀態資訊。這時,將檢查誰在調用並將 Client 屬性的類層級成員與當前訊息分離。然後檢查訊息是否處於 AfterSerialize 狀態。如果已經序列化,則可以在訊息被發送至伺服器之前進行記錄。通過名為 ProcessOutgoingMessageText 的自訂函數,首先進行一些流交換以免破壞底層訊息流程。然後檢查用戶端是否支援 IClientTrace 介面。如果用戶端支援該介面,則表明它們也支援可靠性協議。通過介面檢查功能,可以調用 GetReliabilityInfo 以便將當前訊息返回可應用於該訊息的 ConversationManager,然後設定一些屬性並調用 LogMessage。LogMessage 將當前訊息資訊寫入本機資料庫,然後發送事件,通知用戶端已記錄該訊息。

public class RPClientTrace : SoapExtension
{      
public override void ProcessMessage(SoapMessage message)
{
  SoapClientMessage tmpMsg = (SoapClientMessage)message;
  _client = tmpMsg.Client;

  if (message.Stage == SoapMessageStage.AfterSerialize)
  {
    ProcessOutgoingMessageText(message);
  }
}

  public void ProcessOutgoingMessageText(SoapMessage message)
  {
   newStream.Position = 0;
   TextReader reader = new StreamReader(newStream);
   StringBuilder strMessage = new StringBuilder();
   strMessage.Append(reader.ReadToEnd());
   newStream.Position = 0;
   Copy(newStream, oldStream);

   if(_client is Client.RPClientTrace.IClientTrace)
   {
    try
    {
Client.RPClientTrace.IClientTrace _ptrClient = _
   (Client.RPClientTrace.IClientTrace)_client;
   ReliabilityInfo rInfo = _ptrClient.GetReliabilityInfo();
      rInfo.Text = strMessage.ToString();
      rInfo.Destination = message.Url;
   rInfo.Manager.LogMessage(rInfo);
     }
     catch(Exception e)
     {
      throw e;
     }
    }
   }
}

伺服器端的情況有點複雜,因為伺服器需要為入站訊息執行額外的操作。被調用的 Web 方法用於實現 [ericRP.Server.RPServerTrace.TraceExtension()]。以下代碼將在入站訊息還原序列化之前和之後被調用:

public class RPServerTrace : SoapExtension
{
public override void ProcessMessage(SoapMessage message)
{
try
{
  switch (message.Stage)
  {
   case SoapMessageStage.BeforeDeserialize:
        ReadIncomingMessageText(message);
    break;
   case SoapMessageStage.AfterDeserialize:
     SoapServerMessage tmpMsg = (SoapServerMessage)message;
     _server = tmpMsg.Server;
     if(_server is Server.RPServerTrace.IServerTrace)
     {
          Server.RPServerTrace.IServerTrace _ptrServer = _
             (Server.RPServerTrace.IServerTrace)_server;
     ReliabilityInfo rInfo = _ptrServer.GetReliabilityInfo();
   ericRP.ReliabilityInfo tempInfo = (ericRP.ReliabilityInfo)message.Headers[0];
   tempInfo.Text = _tempMessage;
   Server.ConversationManager manager = new Server.ConversationManager();
   manager.ProcessMessage(tempInfo);

     }
   break;
   }
}

進行流交換和介面檢查後,將在伺服器對話管理器上調用 ProcessInboundMessage。ProcessInboundMessage 用於檢查核心訊息的狀態。訊息限制程式即在此使用。首先檢查訊息是否到期,然後檢查其是否重複,最後檢查其是否有序。如果滿足所有三個條件,則將記錄該訊息並向用戶端發送確認;如果不能滿足任一條件,則將更改訊息的狀態並向用戶端發送確認。

public void ProcessInboundMessage(ericRP.ReliabilityInfo rInfo)
{         
    try
    {
   if(IsExpired(rInfo))
   {
   rInfo.Status = ericRP.ReliabilityInfo.MessageStatus.Expired;
   SendAck(rInfo);
   }
   else if(IsDulplicate(rInfo))
   {
   rInfo.Status = ericRP.ReliabilityInfo.MessageStatus.Duplicate;
   SendAck(rInfo);
   }
   else if(IsNotOrdered(rInfo))
   {
   rInfo.Status = ericRP.ReliabilityInfo.MessageStatus.NotOrdered;
   SendAck(rInfo);
   }
   else
{
   rInfo.Status = ericRP.ReliabilityInfo.MessageStatus.Success;
   LogMessage(rInfo);
   SendAck(rInfo);
   }
    }
    catch(Exception e)
    {
   throw e;
    }
  }
}

要使本樣本在生產環境中可行,還需要做大量的實施工作。更重要的是,API 應當基於一個以後將會發布的公用標準。本文的主要目的就是引發讀者思考問題,瞭解一下 .NET 架構中的主要 Web 服務類,我想這兩個目的都已經達到。如果您正在尋求可靠非同步訊息處理的成熟可用的實現方案,建議您看一看 Microsoft BizTalk™ Server 2000。

最後,您可以使用類似的跟蹤功能執行所有類型的操作,例如加密、客戶分配和通知。記住,這項附加的功能增加了 Web 服務所需的處理基礎結構。

展望
無論是在規範還是在實現方面,XML Web Service 的未來都是光明的。Microsoft 將以協作的、標準驅動的方式工作,確保 XML Web Service 成為編寫鬆散耦合的分散式應用程式的最佳體繫結構。可靠的訊息處理和事務規範將在以後發布。儘管還有大量的實現工作要做,但您現在就可以開始使用 SOAP 和 WSDL 構建您的架構。與公用規範進程越接近,以後的改動工作就越容易進行。SOAP 規範就是這種概念的一個顯著例子。世界各地的開發人員都可以跟蹤 SOAP 規範的發展進程,因此可以毫不費力地對自己的實現方案進行相應地調整。

希望我能有一個水晶球,為您準確地描繪未來 XML Web Service 的基礎結構;希望我們目前依賴的所有公用服務,例如安全性、事務、儲存、查詢、路由、進程協調等等,將來都能夠直接映射至 Web 服務體繫結構;而且 GXA 實現方案可以滲透到核心開發語言、應用程式架構、業務處理架構和企業基礎結構中。到那時,我們就能夠真正地以無縫方式將任意兩種服務耦合在一起。但願 ericRP 不會真的成為服務背後的可靠性層。<微笑>





相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

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 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。