本文章是由機器翻譯。

Windows 中的 C++

Windows Web 服務

Kenny Kerr

下載程式碼範例

許多開發人員 flocked 到 Microsoft.NET Framework 與 Java 較小者一定程度的主要原因是它變得更容易地撰寫軟體網際網路的事實。 是否您去的 HTTP 用戶端或伺服器應用程式,.NET Framework 有您涵蓋提出 HTTP 要求與輕易地處理 XML 的類別。 甚至可以從 WSDL 文件產生 SOAP 用戶端,實作與 ASP.NET SOAP 伺服器。 為標準周圍成熟的 Web 服務,Microsoft 開發在 Windows 通訊基礎 (WCF),也建置在.NET Framework 的來讓它更容易處理不同的傳輸例如 TCP 和 UDP,使用日益複雜的 Web 標準,並提供更加靈活的安全性選項。

C + + 開發人員不過,已保留想知道是否甚至實際使用 C + + 撰寫的 Web 應用程式。 Microsoft 有提供幾個暫存解決方案的 ATL 類別和 COM 為基礎的工具組,形式,但在這些 couldn’t 跟上進度受管理的 SOAP 堆疊必須進行,並因此已多半是放棄的結尾。

儘管看似 single-minded 焦點放在.NET Framework,在 Microsoft 的開發人員 haven’t 有關 C + + 開發人員忘記。 在實際上許多它們仍然是,且會繼續激情 C + + 開發人員。 如此一來協助 C + + 開發人員的解決方案是 Windows 平台的 Microsoft ’s 策略的一個金鑰組件。 當然許多 C + + 開發人員對象的 API 也最後基礎許多受管理的架構。

雖然有太多這裡列舉、 幾個很值得一提。 Windows HTTP 服務 API WinHTTP 提供強大且彈性的解決方案撰寫 HTTP 用戶端。 您可以閱讀更多關於 WinHTTP 我 2008 年八月] 欄中。 HTTP 伺服器 API HTTP.sys 提供地基建置高效能的 HTTP 伺服器,而不依賴完整的 Web 伺服器就像網際網路資訊服務 (IIS)。 在實際上 IIS 本身根據這個相同的 API。 並當然 XmlLite API 提供小且快速 XML 剖析器的原生程式碼。 您可以閱讀更多關於 XmlLite 我 2007 年四月功能文件中。

給予所有的這,是仍然很吃力任務寫入 SOAP 用戶端或伺服器。 雖然 SOAP 啟動關閉 「 簡單 」 (,’s 「 S 」 代表 「,) 它 didn’t 對於長時間保持這種方法。 WinHTTP、 HTTP.sys 和 XmlLite 可能取得您以長的方式處理 HTTP 傳輸,並剖析 [XML,但仍要寫入處理通訊層的程式碼噸:事情喜歡的格式和解譯 SOAP 標頭不到提支援其他像是 TCP 或 UDP 傳輸。 即使您可以某種方式管理所有的這,將您帶剖析 SOAP 信封,而不是能夠以 [邏輯 SOAP 作業視為函式呼叫仍離開。

嗯,這些頭痛是一件事的最過去。 隨著 Windows Web 服務 (WWS) API 的推出,C++ 開發人員再也不會認為自己是 Web 服務世界中的次等公民了。 WWS 設計從地面最多會包括支援許多 WS-的 SOAP 的一個完全的原生碼實作 * 通訊協定。 嚴格說,WWS 透過進行交互操作性與其他語言和執行階段非常直截了當一個 C API 所公開,但它是 C + + 開發人員可能會對最。 在實際上從 C + + 的有點協助,它可以是使用真實享受這 — 您應該在本文中看到。

架構和原則

WWS embodies 不是.NET Framework 為基礎的文件庫的所有內容。 它是專為原生程式碼設計的。 它被設計來引入少量的相依性。 它被設計來作為越少的記憶體。 並設計為快速。 真的快速。 小組負責開發 WWS 以 WCF 和 RPC 比較每個新組建的執行效能測試。 由於執行任何動作可能是速度,但它並提供可靠的方法,追蹤速度回復的 RPC 是用來當做排序比較基準。 它,但是,照亮當您比較 WCF 和 WWS 時。 圖 1 顯示用戶端分別使用 WCF 和 WWS 工作組的比較。 ’s 很明顯的邊界為但也許不,尊重何時您認為涉及.NET Framework。 圖 2,但是,應該如果 ; 令人驚訝,如果您,像其他許多人,考慮成為的最先進的 WCF。 它會顯示產能的伺服器,分別使用 WCF 和 WWS 每秒的操作中。 WWS 是超過兩次以快速! don’t 幫我錯誤:有錯誤與 WCF] 或 [.NET] Framework 執行任何動作但當您需要的東西,小型及快速,’s 硬打敗 C + + 和原生程式碼。 不過,您已經知道 !


圖 1 比較工作設定的用戶端 (低是較佳)

WWS 執行階段被封裝在 WebServices.dll,這是隨附於 Windows 7 和 Windows Server 2008 R2。 也是可用的系統更新 Windows XP 與更新版本。 從 WebServices.dll 匯出的函式代表 WWS API 和您可以藉由連結到 WebServices.lib 並包括 WebServices.h 標頭檔,從 Windows SDK 獲得存取它們。 到目前為止還不錯吧! 但確實 API 外觀想什麼嗎? 嗯,不像 XmlLite 或 Direct2D 的 [COM 樣式 API 像這個 C API 要求您想像一組邏輯層及居住在幕後,並只等候中斷的物件。 let’s 先看看它的圖層的角度。 圖 3 說明於其下一個建置每個圖層與 WWS 的 API 所公開的功能層級。 每個圖層由函式和結構的數字表示,並提供一組的抽象概念。 您可以猜測可以讓應用程式使用任何圖層的但大多數的情況下,您會想要停具有服務模型,提供最簡單的程式設計模型,並隱藏許多詳細資料為您。 傳輸層是只是提醒,其所有有下將會某些網路通訊協定。 WWS 將取決於選取的傳輸和用來實作在用戶端或伺服器是否使用 WinHTTP、 HTTP.sys 或 Winsock。


圖 2 比較伺服器輸送量 (越高是較佳)


圖 3 分層 API

如其名稱會建議,服務模型層完全摘取 SOAP 訊息交換,並且模型邏輯的 Web 服務作業,作為函式呼叫。 它並不,但是,獨立存在,但依賴稱為 Wsutil.exe 從 Windows SDK 的命令列工具的使用。 指定 WSDL 檔案,此工具會產生標頭檔,以及兩者所需程式碼大部分的 C 原始程式檔連接到指定描述的 Web 服務和實作如採取小心以確保通道繫結 Web 服務已正確設定和訊息的格式都正確。 這是目前為止最簡單的方法,並提供程式設計的模型,就像您所預期從傳統 RPC 很多。

通道層,另一方面,公開訊息傳送和接收於特定的傳輸,但仍然選擇性地防護您不必實際格式化訊息自己。 這裡的好處是您隔離從特定的傳輸,以及使用編碼方式。 通道層是您用來控制繫結資訊,而且您可以保障您的通訊安全的驗證或隱私權。

XML 層公開您的訊息和序列化資料的格式設定。 訊息內容的完整存取,但是否與文字二進位通訊,從特定的編碼方式隔離或 MTOM。 您可能聽 WWS 有它自己的 XML 剖析器感到驚訝。 為什麼 doesn’t 它只是使用 XmlLite? 雖然 XmlLite 肯定輕量及非常快速,它 isn’t 很完美符合多個原因。 最明顯的原因是 WWS 必須支援不同的編碼方式,雖然 XmlLite 支援只有文字。 SOAP 訊息也通常是 XmlLite 公開 (Expose) 與 Unicode 字串的所有屬性和複製值時,這會介紹不必要的成本時使用 UTF-8 編碼。 WWS 也有非常嚴格的記憶體耗用量目標 (沒有實際上這,API 如同我們稍後看到) 不能與 XmlLite 符合。 到最後 WWS 小組便能特別為比 XmlLite 急遽快的 SOAP 實作自訂的剖析器。 請記住,WWS 剖析器不是用來取代 XmlLite。 作為一般用途 XML 剖析器,硬打敗,但是 WWS XML 層讓程式開發人員瞄準的 SOAP 訊息使用的所需的 SOAP 的 XML 子集有效地序列化資料非常特定的功能。

除了從函式和邏輯上屬於這些三個層級的資料結構,WWS API 提供了數個常見包括錯誤處理、 非同步完成、 取消、 記憶體管理和更多的所有層次的設施。 因為我空間有限,而且想要協助您快速入門我打算限制本文的其餘部分,建置 Web 服務用戶端和伺服器的服務模型使用。 在未來的文章中,我深入更深的 WWS 其他部分。

快速入門

若要從開始我使用最少的 Web 服務定義,從 的 圖 4。 這個 WSDL 文件定義了型別、 訊息、 作業、 端點和服務的通道繫結。 第一件要做的事情就是執行它透過 Wsutil.exe,如下所示:

Wsutil.exe Calculator.wsdl

這將會產生稱為 Calculator.wsdl.h 與一個叫做 Calculator.wsdl.c C 原始程式檔的標頭檔。

圖 4 的 Web 服務定義

<wsdl:definitions xmlns:wsdl="https://schemas.xmlsoap.org/wsdl/"
 xmlns:soap="https://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:xsd="ttp://www.w3.org/2001/XMLSchema"
 xmlns:tns="http://calculator.example.org/"
 targetNamespace="http://calculator.example.org/">
    
 <wsdl:types>
   <xsd:schema elementFormDefault="qualified" 
    targetNamespace="http://calculator.example.org/">
    <xsd:element name="AddRequest">
     <xsd:complexType>
      <xsd:sequence>
       <xsd:element name="first" type="xsd:double" />
       <xsd:element name="second" type="xsd:double" />
      </xsd:sequence>
     </xsd:complexType>
    </xsd:element>
    <xsd:element name="AddResponse">
     <xsd:complexType>
      <xsd:sequence>
       <xsd:element name="result" type="xsd:double" />
      </xsd:sequence>
     </xsd:complexType>
    </xsd:element>
   </xsd:schema>
  </wsdl:types>

  <wsdl:message name="AddRequestMessage">
    <wsdl:part name="parameters" element="tns:AddRequest" />
  </wsdl:message>
  <wsdl:message name="AddResponseMessage">
    <wsdl:part name="parameters" element="tns:AddResponse" />
  </wsdl:message>

  <wsdl:portType name="CalculatorPort">
    <wsdl:operation name="Add">
      <wsdl:input message="tns:AddRequestMessage" />
      <wsdl:output message="tns:AddResponseMessage" />
    </wsdl:operation>
  </wsdl:portType>

  <wsdl:binding name="CalculatorBinding" type="tns:CalculatorPort">
    <soap:binding transport="https://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="Add">
      <soap:operation soapAction=
       "http://calculator.example.org/Add" style="document"/>
      <wsdl:input>
       <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
       <soap:body use="literal"/>
      </wsdl:output>
     </wsdl:operation>
   </wsdl:binding>

   <wsdl:service name="CalculatorService">
    <wsdl:port name="CalculatorPort" binding="tns:CalculatorBinding">
     <soap:address location="http://localhost:81/calculator"/>
    </wsdl:port>
   </wsdl:service>

</wsdl:definitions>

我們看一下什麼產生之前我們需要取得完成不論是否實作在用戶端或伺服器某些基礎。 必須在第一件事,就是地表達資訊時發生錯誤。 WWS API 公開 Rich 錯誤資訊同時為它自己的函式以及透過錯誤物件的 SOAP 錯誤。 正在 C API,這個物件會以不透明的控點及函式的集合。 在這種情況下,WS_ERROR * 表示錯誤物件控點,並且 WsCreateError 是建立它的函數。 藉由呼叫 WsFreeError 函式釋放該物件。 錯誤物件可以儲存字串的數的字,以不同的層級錯誤的相關資訊。 若要擷取這些,您必須先決定多少的字串都存在。 這是藉由呼叫 WsGetErrorProperty 函式,讓它控制代碼錯誤物件指定 WS_ERROR_PROPERTY_STRING_COUNT 常數。 武裝有了這項資訊,您呼叫該 WsGetErrorString 函數,給予它控制代碼給物件時發生錯誤,以及要擷取之字串之以零起始的索引。 您也可以使用 API 函數來填入您自己的錯誤物件。 自然,小小的 C + + 會進入長的方式,若要讓這更簡單、 更可靠。 圖 5 提供簡單的錯誤物件包裝函式。 圖 6 所示,您可以輕易地列舉中的錯誤物件的字串。

圖 5 的 Error 物件包裝函式

class WsError
{
    WS_ERROR* m_h;
public:
    WsError* m_h(0)
    {}
    ~WsError()
    {
        if (0 != m_h)
    }
    HRESULT Create(const WS_ERROR_PROPERTY* properties,
                        ULONG propertyCount)
    {
        return WsCreateError(properties, propertyCount, &m_h);
    }
    HRESULT GetProperty(WS_ERROR_PROPERTY_ID id, void* buffer,
                            ULONG bufferSize)
    {
        return WsGetErrorProperty(m_h, id, buffer, bufferSize);
    }
    template <typename T>
    HRESULT GetProperty(WS_ERROR_PROPERTY_ID id, out T* buffer)
    {
        return GetProperty(id, buffer, sizeof(T));
    }
    HRESULT GetString(ULONG index, WS_STRING* string)
    {
        return WsGetErrorString(m_h, index, string);
    }
    operator WS_ERROR*() const
    {
        return m_h;
    }
};

圖 6 列舉在錯誤物件字串

WsError error;
HR(error.Create(0, 0));
// Something goes wrong . . .
ULONG stringCount = 0;
HR(error.GetProperty(WS_ERROR_PROPERTY_STRING_COUNT,&stringCount));

for (ULONG i = 0; i < stringCount; ++i)
{
    WS_STRING string;
    HR(error.GetString(i, &string));
    wprintf(L"Error %d: %.*s\n", i, string.length, string.chars);
}

我們需要下一件事是堆積的物件。 堆積物件提供精確的控制,透過記憶體配置時產生或消耗的郵件,並在需要配置各種其他 API 結構時。 因為不需要,您知道精確多少記憶體是需要的任何特定的函式會成功,它也簡化了程式設計模型。 在 Windows SDK 中許多較舊的函式將,例如需要您猜出多少儲存空間是必要或第一次呼叫函式來判斷多少記憶體以特定方式,您應該配置函式會成功。 WWS 堆積物件的使用會移除所有此額外編碼,並提供不錯的方法來控制 API 的記憶體使用量。 這也來自方便好用安全性的觀點來看可能會想要在 API 可能會配置多少指定預期的限制。 WS_HEAP * 表示一個堆積物件控點,而且 WsCreateHeap 函式會建立它。 藉由呼叫 WsFreeHeap 函式釋放該物件。 一旦它建立您可以從使用 WsAlloc] 函數堆積配置記憶體,但在本文中我們只是傳遞控制代碼要他們在使用其他 API 函式之堆積物件如有必要。

圖 7 提供簡單的堆積物件包裝函式。 指定這,您就可以建立一個限於 250 個位元組的堆積物件,如下所示:

WsHeap heap;

HR(heap.Create(250, // max size
               0, // trim size
               0, // properties
               0, // property count
               error));

請注意如何我傳遞至堆積物件 ’s Create 方法的物件時發生錯誤。 應該任何項目出錯建立堆積物件時,我能夠詢問錯誤物件,以找出原因。

圖 7 的 堆積物件包裝函式

class WsError
{
    WS_ERROR* m_h;
public:
    WsError* m_h(0)
    {}
    ~WsError()
    {
       if (0 != m_h)
    }
    HRESULT Create(const WS_ERROR_PROPERTY* properties, 
            ULONG propertyCount)
    {
       return WsCreateError(properties, propertyCount, &m_h);
    }
    HRESULT GetProperty(WS_ERROR_PROPERTY_ID id, void* buffer, 
               ULONG bufferSize)
    {
        return WsGetErrorProperty(m_h, id, buffer, bufferSize);
    }
    template <typename T>
    HRESULT GetProperty(WS_ERROR_PROPERTY_ID id, out T* buffer)
    {
        return GetProperty(id, buffer, sizeof(T));
    }
    HRESULT GetString(ULONG index, WS_STRING* string)
    {
        return WsGetErrorString(m_h, index, string);
    }
    operator WS_ERROR*() const
    {
      return m_h;
    }
};
class WsHeap
{
    WS_HEAP* m_h;
public:
    WsHeap() : m_h(0)
    {}
    ~WsHeap()
    {
        if (0 != m_h) WsFreeHeap(m_h);
    }
    HRESULT Create(SIZE_T maxSize, SIZE_T trimSize, 
            const WS_HEAP_PROPERTY* properties, 
            ULONG propertyCount, 
            in_opt WS_ERROR* error)
    {
        return WsCreateHeap(maxSize, trimSize, properties, propertyCount,
                      &m_h, error);
    }
    operator WS_HEAP*() const
    {
        return m_h;
    }
};

用戶端

服務模型的用戶端置服務 Proxy 物件上。 產生的原始程式碼包含稱為 CalculatorBinding_CreateServiceProxy 函式。 名稱衍生自的結束點或繫結名稱在 WSDL 文件中定義。 此函式會建立服務 Proxy 物件,並傳回一個 WS_SERVICE_PROXY * 代表該物件的不透明的控制代碼。 藉由呼叫 WsFreeServiceProxy 函式釋放該物件。 一旦建立,您的應用程式可以開啟使用 WsOpenServiceProxy 函式的服務端點,然後再進行到 Web 服務的 [透過服務 Proxy 的呼叫。 完全 WsOpenServiceProxy 的功用是所使用的傳輸而定。 您必須也小心關閉服務 Proxy 之前要釋放物件,使用 WsCloseServiceProxy 函式。 自然,這個內部的所有可得很好包裝 的 圖 8 中所提供的簡單類別中。 指定這,您可以建立並開啟服務] Proxy,如 的 圖 9 所示。

圖 8 的 服務 Proxy 包裝函式

class WsServiceProxy
{
    WS_SERVICE_PROXY* m_h;
public:
    WsServiceProxy() : m_h(0)
    {}
    ~WsServiceProxy()
    {
        if (0 != m_h)
        {
            Close(0, 0); // error
            WsFreeServiceProxy(m_h);
        }
    }
    HRESULT Open(const WS_ENDPOINT_ADDRESS* address, 
            const WS_ASYNC_CONTEXT* asyncContext, 
            WS_ERROR* error)
    {
        return WsOpenServiceProxy(m_h, address, asyncContext, error);
    }
    HRESULT Close(const WS_ASYNC_CONTEXT* asyncContext, 
            WS_ERROR* error)
    {
        return WsCloseServiceProxy(m_h, asyncContext, error);
    }
    WS_SERVICE_PROXY** operator&()
    {
        return &m_h;
    }
    operator WS_SERVICE_PROXY*() const
    {
        return m_h;
    }
};

圖 9 建立及開啟服務 Proxy

WsServiceProxy serviceProxy;

HR(CalculatorBinding_CreateServiceProxy(0, // template value
                                        0, // properties
                                        0, // property count
                                        &serviceProxy,
                                        error));

WS_ENDPOINT_ADDRESS address =
{
    {
        static_cast<ULONG>(wcslen(url)),
        const_cast<PWSTR>(url)
    }
};

HR(serviceProxy.Open(&address,
                     0, // async context
                     error));

WS_ENDPOINT_ADDRESS 結構用來解決所傳送的訊息。 在通道層程式設計時,通常會使用這個結構。 在這種情況下,我們填入 URL 部分,並且服務 Proxy 會處理的其餘部分。

這個時候我們可以使用另一個產生的函式也就是 CalculatorBinding_Add,unsurprisingly 代表 Web 服務 ’s Add 作業。 它真的 doesn’t 得到比這簡單多了:

const double first = 1.23;
const double second = 2.34;
double result = 0.0;

HR(CalculatorBinding_Add(serviceProxy,
                         first,
                         second,
                         &result,
                         heap,
                         0, // properties
                         0, // property count
                         0, // async context
                         error));

ASSERT(3.57 == result);

一旦您完成與 Web 服務互動您只需要關閉服務 Proxy ’s 通訊通道:

HR(serviceProxy.Close(0, // async context
                      error));

「 伺服器

雖然用戶端程式撰寫模型中心服務 Proxy 上,伺服器而是建立及管理提供必要的執行階段根據提供的通道資訊的各種端點上接聽的服務主機。 再次,因為我們使用服務模型,大部分的詳細資料抽象化在離開,而我們剩下只能夠建立服務端點和主機。 WWS 將進行其餘部分。

第一個步驟是建立服務端點。 服務模型負責這另一個產生的函式,也就是 CalculatorBinding_CreateServiceEndpoint 的形式,如 的 圖 10 所示。 建立端點需要指定在其的結束點即將要接聽的位址。 這會提供由 [WS_STRING 終止結構是長度為前置字元的 Unicode 字串,並不需要是 null。 因為端點負責滿足要求,所以您需要提供對應至公開的服務作業的函式指標的表格。 產生的 CalculatorBindingFunctionTable 結構用於此目的。 最後,端點本身 WS_SERVICE_ENDPOINT 結構所表示,並提供堆積中配置。

圖 10 CalculatorBinding_CreateServiceEndpoint

class WsServiceHost
{
    WS_SERVICE_HOST* m_h;
public:
  WsServiceHost() : m_h(0)
  {}
  ~WsServiceHost()
  {
    if (0 != m_h)
    {
        Close(0, 0); 
        WsFreeServiceHost(m_h);
    }
  }
  HRESULT Create(const WS_SERVICE_ENDPOINT** endpoints, 
          const USHORT endpointCount, 
          const WS_SERVICE_PROPERTY* properties, 
          ULONG propertyCount, WS_ERROR* error)
  {
     return WsCreateServiceHost(endpoints, endpointCount, properties,
                      propertyCount, &m_h, error);
  }
  HRESULT Open(const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
  {
    return WsOpenServiceHost(m_h, asyncContext, error);
  }
  HRESULT Close(const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
  {
    return WsCloseServiceHost(m_h, asyncContext, error);
  }
  operator WS_SERVICE_HOST*() const
  {
    return m_h;
  }
};

WsServiceProxy serviceProxy;
const WS_STRING address =
{
    static_cast<ULONG>(wcslen(url)),
    const_cast<PWSTR>(url)
};

CalculatorBindingFunctionTable functions =
{
    AddCallback
};

WS_SERVICE_ENDPOINT* endpoint = 0;

HR(CalculatorBinding_CreateServiceEndpoint(0, // template value
                                           &address,
                                           &functions,
                                           0, // authz callback
                                           0, // properties
                                           0, // property count
                                           heap,
                                           &endpoint,
                                           error));

下一步是建立服務主機。 WS_SERVICE_HOST * 表示服務主機物件控點,而且 WsCreateServiceHost 函式會建立它。 藉由呼叫 WsFreeServiceHost 函式釋放該物件。 WsCreateServiceHost 函式會建立服務主機物件指定端點的清單。 這個時候,您可以使用 WsOpenServiceHost 函式的所有端點上啟動接聽程式。 停止使用 WsCloseServiceHost 函式的通訊。 如同服務] Proxy 務必關閉之前要釋放它服務主機。 再次,這個內部的所有可得很好包裝 的 圖 11 中所提供的簡單類別中。 指定這,您就可以啟動 Web 服務,如下所示:

const WS_SERVICE_ENDPOINT* endpoints[] = { endpoint };

WsServiceHost serviceHost;

HR(serviceHost.Create(endpoints,
                      _countof(endpoints),
                      0, // properties
                      0, // property count
                      error));

HR(serviceHost.Open(0, // async context
                    error));

在這種情況下沒有只有單一端點,但是您可以看到將額外的端點加入至服務主機就是的多麼簡單。 當停止服務的時間,您只需要關閉服務主機 ’s 通訊通道。

HR(serviceHost.Close(0, // async context
                     error));

實際實作 Web 服務作業是關於最簡單的一部份:

HRESULT CALLBACK AddCallback(__in const WS_OPERATION_CONTEXT*, 
                 __in double first, 
                 __in double second, 
                 __out double* result, 
                 __in_opt const WS_ASYNC_CONTEXT* /*asyncContext*/,
                 __in_opt WS_ERROR* /*error*/)
{
    *result = first + second;
    return S_OK;
}

AddCallback 函式簽章也提供產生的原始程式碼應該您有任何疑問有關如何指定它。

和,’s 所有我這個月有空間,但是現在您應該有的功能和 Windows Web 服務 API 所提供的好處是個好主意。 您可以看到 C + + 開發人員最後有現代的 SOAP 堆疊右現成。 它提供了最可能的效能和記憶體使用量,而且是使用從 C + + 有點說明享受。

圖 11 的 服務主機包裝函式

class WsServiceHost
{
    WS_SERVICE_HOST* m_h;
public:
    WsServiceHost() : m_h(0)
    {}
    ~WsServiceHost()
    {
        if (0 != m_h)
        {
            Close(0, 0);
            WsFreeServiceHost(m_h);
        }
    }
    HRESULT Create(const WS_SERVICE_ENDPOINT** endpoints,
            const USHORT endpointCount,
            const WS_SERVICE_PROPERTY* properties,
            ULONG propertyCount, WS_ERROR* error)
    {
        return WsCreateServiceHost(endpoints, endpointCount, properties,
                                            propertyCount, &m_h, error);
    }
    HRESULT Open(const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
    {
        return WsOpenServiceHost(m_h, asyncContext, error);
    }
    HRESULT Close(const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
    {
        return WsCloseServiceHost(m_h, asyncContext, error);
    }
    operator WS_SERVICE_HOST*() const
    {
        return m_h;
    }
};

誰使用它?

在 Microsoft 的各種小組已經開始採用 Windows Web 服務 (WWS) API 內自己的產品或技術。 在許多情況下這會取代自建 SOAP 堆疊,並有些甚至選擇取代 WWS 商業實作像 Windows Communication Foundation (WCF)。 以下是少數幾個範例。

Microsoft Web 服務上的裝置 (WSD) API 可以讓開發人員撰寫用戶端和伺服器根據裝置設定檔的 [Web 服務] (DPWS)。 Windows 7 WSD API 已建立和 WSD 執行階段會送出的 SOAP 訊息中的 XML 規範化使用 WWS 啟動的。 WSD 小組計劃展開 WWS 用法,當他們加入新功能和重整現有程式碼。

Windows CardSpace 是 Microsoft ’s 實作的 Web 服務標準為基礎的身份識別系統。 原始已實作與 WCF,它已被改寫使用原生程式碼] 和 [WWS 符合可下載的安裝程式和執行階段工作組的大小非常嚴格的商務需求。

Microsoft Forefront 威脅管理閘道 (TMG) 是安全的平台提供防火牆和快取功能,以確保安全並改善網路效能。 其 URL 篩選功能會使用 WWS 連線到 Microsoft 信譽服務,來分類的 URL。

最後,Windows 公開金鑰基礎結構 (PKI) 用戶端自動註冊與使用者和應用程式導向的憑證註冊和一起提供自動的生命週期管理憑證。 Windows 7 引進了一組新的 Web 服務,可讓憑證註冊以 LDAP 和 DCOM 的 
traditional 限制沒有完成。 PKI 用戶端可使用的 WWS 做包括新的憑證註冊原則 (MS XCEP) 通訊協定] 及 [憑證註冊 (MS WSTEP) 的 WS-Trust 副檔名的所有作業。 WWS 用戶端會與一組新的使用中目錄憑證服務在 Windows Server 2008 R2 中實作與 WCF,以及與公用憑證簽發者所提供的 Web 服務進行通訊。

Kenny Kerr 是一位軟體工藝師,專門開發 Windows 的軟體。 他熱愛撰寫及教導開發人員程式設計和軟體設計的相關知識。 您可以在 weblogs.asp.net/kennykerr 到達 Kerr。