共用方式為


取用 Windows Communication Foundation (WCF) Web 服務

WCF 是 Microsoft 建置服務導向應用程式的統一架構。 它可讓開發人員建置安全、可靠、交易且互通的分散式應用程式。 本文示範如何從 Xamarin.Forms 應用程式取用 WCF Simple Object Access Protocol (SOAP) 服務。

WCF 描述具有各種不同合約的服務,包括:

  • 數據合約 – 定義構成訊息內內容基礎的數據結構。
  • 訊息合約 – 撰寫來自現有數據合約的訊息。
  • 錯誤合約 – 允許指定自訂 SOAP 錯誤。
  • 服務合約 – 指定服務支持的作業,以及與每個作業互動所需的訊息。 它們也會指定任何可與每個服務上作業相關聯的自定義錯誤行為。

ASP.NET Web 服務 (ASMX) 與 WCF 之間有差異,但 WCF 支援 ASMX 所提供的相同功能 – 透過 HTTP 的 SOAP 訊息。 如需取用 ASMX 服務的詳細資訊,請參閱 取用 ASP.NET Web 服務 (ASMX)

重要

WCF 的 Xamarin 平台支援僅限於使用 BasicHttpBinding 類別透過 HTTP/HTTPS 透過文字編碼的 SOAP 訊息。

WCF 支援只需要在 Windows 環境中使用工具,才能產生 Proxy 並裝載 TodoWCFService。 建置和測試 iOS 應用程式需要將 TodoWCFService 部署在 Windows 電腦上,或部署為 Azure Web 服務。

Xamarin Forms 原生應用程式通常會與 .NET Standard 類別庫共用程序代碼。 不過,.NET Core 目前不支援 WCF,因此共用專案必須是舊版可攜式類別庫。 如需 .NET Core 中 WCF 支援的資訊,請參閱 在伺服器應用程式的 .NET Core 與 .NET Framework 之間選擇。

範例應用程式解決方案包含可在本機執行的 WCF 服務,如下列螢幕快照所示:

範例應用程式

注意

在 iOS 9 和更新版本中,應用程式傳輸安全性 (ATS) 會強制執行因特網資源(例如應用程式後端伺服器)與應用程式之間的安全連線,以防止意外洩漏敏感性資訊。 由於 ATS 預設會在針對 iOS 9 建置的應用程式中啟用,因此所有連線都會受限於 ATS 安全性需求。 如果連線不符合這些需求,它們將會失敗併發生例外狀況。

如果無法使用 HTTPS 通訊協議和保護因特網資源的通訊,則可以退出宣告 ATS。 您可以藉由更新應用程式的 Info.plist 檔案來達成此目的。 如需詳細資訊,請參閱 應用程式傳輸安全性

取用 Web 服務

WCF 服務提供下列作業:

作業 描述 參數
GetTodoItems 取得待辦事項的清單
CreateTodoItem 建立新的 To-do 專案 XML 串行化的 TodoItem
EditTodoItem 更新待辦事項 XML 串行化的 TodoItem
DeleteTodoItem 刪除待辦事項 XML 串行化的 TodoItem

如需應用程式所用數據模型的詳細資訊,請參閱 將數據模型化。

必須產生 Proxy 才能取用 WCF 服務,讓應用程式能夠連線到服務。 Proxy 是藉由取用定義方法和相關聯服務組態的服務元數據來建構。 此元數據會以 Web 服務描述語言 (WSDL) 檔的形式公開,由 Web 服務產生。 您可以使用 Visual Studio 2017 中的 Microsoft WCF Web 服務參考提供者,將 Web 服務的服務參考新增至 .NET Standard 連結庫,來建置 Proxy。 在 Visual Studio 2017 中使用 Microsoft WCF Web 服務參考提供者建立 Proxy 的替代方法是使用 ServiceModel 元數據公用程式工具(svcutil.exe)。 如需詳細資訊,請參閱 ServiceModel 元數據公用程式工具(Svcutil.exe)。

產生的 Proxy 類別提供使用異步程式設計模型 (APM) 設計模式之 Web 服務的方法。 在此模式中,異步操作會實作為名為 BeginOperationNameEndOperationName 的兩種方法,以開始和結束異步操作。

BeginOperationName 方法會開始異步操作,並傳回實作 IAsyncResult 介面的物件。 呼叫 BeginOperationName 之後,應用程式可以繼續在呼叫線程上執行指令,而異步操作會在線程集區線程上執行。

對於 BeginOperationName 的每個呼叫,應用程式也應該呼叫 EndOperationName 以取得作業的結果。 EndOperationName傳回值是同步 Web 服務方法所傳回的相同類型。 例如, EndGetTodoItems 方法會傳回 實例的 TodoItem 集合。 EndOperationName 方法也包含參數IAsyncResult,應該設定為 BeginOperationName 方法之對應呼叫所傳回的實例。

工作平行連結庫 (TPL) 可以藉由將異步操作封裝在相同 Task 物件中,來簡化取用 APM 開始/結束方法組的程式。 這個封裝是由方法的 TaskFactory.FromAsync 多個多載所提供。

如需 APM 的詳細資訊,請參閱 MSDN 上的異步程式設計模型TPL 和傳統 .NET Framework 異步程序設計

建立 TodoServiceClient 物件

產生的 Proxy 類別會提供 類別 TodoServiceClient ,用來透過 HTTP 與 WCF 服務通訊。 它提供從 URI 識別的服務實例叫用 Web 服務方法做為異步操作的功能。 如需異步操作的詳細資訊,請參閱 異步支援概觀

TodoServiceClient實例會在類別層級宣告,因此只要應用程式需要取用 WCF 服務,物件就會存留,如下列程式代碼範例所示:

public class SoapService : ISoapService
{
  ITodoService todoService;
  ...

  public SoapService ()
  {
    todoService = new TodoServiceClient (
      new BasicHttpBinding (),
      new EndpointAddress (Constants.SoapUrl));
  }
  ...
}

實例 TodoServiceClient 會使用系結資訊和端點位址來設定。 系結可用來指定應用程式和服務彼此通訊所需的傳輸、編碼和通訊協定詳細數據。 BasicHttpBinding指定會透過 HTTP 傳輸通訊協定傳送文字編碼的 SOAP 訊息。 指定端點位址可讓應用程式連線到 WCF 服務的不同實例,前提是有多個已發佈的實例。

如需設定服務參考的詳細資訊,請參閱 設定服務參考

建立數據傳輸物件

範例應用程式會 TodoItem 使用 類別來建立數據模型。 若要將專案儲存 TodoItem 在 Web 服務中,必須先轉換成 Proxy 產生的 TodoItem 類型。 此方法會完成此作業 ToWCFServiceTodoItem ,如下列程式代碼範例所示:

TodoWCFService.TodoItem ToWCFServiceTodoItem (TodoItem item)
{
  return new TodoWCFService.TodoItem
  {
    ID = item.ID,
    Name = item.Name,
    Notes = item.Notes,
    Done = item.Done
  };
}

這個方法只會建立新的 TodoWCFService.TodoItem 實例,並將每個屬性設定為實例中的 TodoItem 相同屬性。

同樣地,從 Web 服務擷取數據時,必須將它從 Proxy 產生的 TodoItem 類型 TodoItem 轉換成 實例。 這是使用 FromWCFServiceTodoItem 方法完成的,如下列程式代碼範例所示:

static TodoItem FromWCFServiceTodoItem (TodoWCFService.TodoItem item)
{
  return new TodoItem
  {
    ID = item.ID,
    Name = item.Name,
    Notes = item.Notes,
    Done = item.Done
  };
}

這個方法只會從 Proxy 產生的 TodoItem 型別擷取數據,並在新建立 TodoItem 的實例中設定它。

取出資料

TodoServiceClient.BeginGetTodoItemsTodoServiceClient.EndGetTodoItems 方法可用來呼叫 GetTodoItems Web 服務所提供的作業。 這些異步方法會封裝在物件中 Task ,如下列程式代碼範例所示:

public async Task<List<TodoItem>> RefreshDataAsync ()
{
  ...
  var todoItems = await Task.Factory.FromAsync <ObservableCollection<TodoWCFService.TodoItem>> (
    todoService.BeginGetTodoItems,
    todoService.EndGetTodoItems,
    null,
    TaskCreationOptions.None);

  foreach (var item in todoItems)
  {
    Items.Add (FromWCFServiceTodoItem (item));
  }
  ...
}

Task.Factory.FromAsync方法會Task建立 ,一旦TodoServiceClient.BeginGetTodoItems方法完成,就會執行 TodoServiceClient.EndGetTodoItems 方法,並使用 null 參數指出未將數據傳遞至BeginGetTodoItems委派。 最後,列舉的值 TaskCreationOptions 會指定應該使用建立和執行工作的默認行為。

方法 TodoServiceClient.EndGetTodoItems 會傳 ObservableCollection 回 實例的 TodoWCFService.TodoItem ,然後轉換成 List 實例的 TodoItem ,以供顯示。

建立資料

TodoServiceClient.BeginCreateTodoItemTodoServiceClient.EndCreateTodoItem 方法可用來呼叫 CreateTodoItem Web 服務所提供的作業。 這些異步方法會封裝在物件中 Task ,如下列程式代碼範例所示:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
  ...
  var todoItem = ToWCFServiceTodoItem (item);
  ...
  await Task.Factory.FromAsync (
    todoService.BeginCreateTodoItem,
    todoService.EndCreateTodoItem,
    todoItem,
    TaskCreationOptions.None);
  ...
}

Task.Factory.FromAsync方法會Task建立,這個方法會在方法完成時TodoServiceClient.BeginCreateTodoItem執行 TodoServiceClient.EndCreateTodoItem 方法,並將 todoItem 參數當做傳遞至BeginCreateTodoItem委派的數據,以指定要TodoItem由 Web 服務建立的 。 最後,列舉的值 TaskCreationOptions 會指定應該使用建立和執行工作的默認行為。

如果 Web 服務無法建立 TodoItem應用程式所處理的 ,則會擲回 FaultException

更新資料

TodoServiceClient.BeginEditTodoItemTodoServiceClient.EndEditTodoItem 方法可用來呼叫 EditTodoItem Web 服務所提供的作業。 這些異步方法會封裝在物件中 Task ,如下列程式代碼範例所示:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
  ...
  var todoItem = ToWCFServiceTodoItem (item);
  ...
  await Task.Factory.FromAsync (
    todoService.BeginEditTodoItem,
    todoService.EndEditTodoItem,
    todoItem,
    TaskCreationOptions.None);
  ...
}

方法Task.Factory.FromAsyncTask建立 ,一旦TodoServiceClient.BeginCreateTodoItem方法完成,就會執行 TodoServiceClient.EndEditTodoItem 方法,並將 todoItem 參數當做傳遞至BeginEditTodoItem委派的數據,以指定要TodoItem由 Web 服務更新的 。 最後,列舉的值 TaskCreationOptions 會指定應該使用建立和執行工作的默認行為。

如果 Web 服務找不到或更新TodoItem應用程式所處理的 ,則會擲回 FaultException

刪除資料

TodoServiceClient.BeginDeleteTodoItemTodoServiceClient.EndDeleteTodoItem 方法可用來呼叫 DeleteTodoItem Web 服務所提供的作業。 這些異步方法會封裝在物件中 Task ,如下列程式代碼範例所示:

public async Task DeleteTodoItemAsync (string id)
{
  ...
  await Task.Factory.FromAsync (
    todoService.BeginDeleteTodoItem,
    todoService.EndDeleteTodoItem,
    id,
    TaskCreationOptions.None);
  ...
}

Task.Factory.FromAsync方法會Task建立,這個方法會在方法完成時TodoServiceClient.BeginDeleteTodoItem執行 TodoServiceClient.EndDeleteTodoItem 方法,並將 id 參數當做傳遞至BeginDeleteTodoItem委派的數據,以指定要TodoItem由 Web 服務刪除的 。 最後,列舉的值 TaskCreationOptions 會指定應該使用建立和執行工作的默認行為。

如果 Web 服務找不到或移除TodoItem應用程式所處理的 ,則會擲回 FaultException

設定 IIS Express 的遠端訪問

在 Visual Studio 2017 或 Visual Studio 2019 中,您應該能夠在沒有額外設定的電腦上測試 UWP 應用程式。 測試 Android 和 iOS 用戶端可能需要本節中的其他步驟。 如需詳細資訊,請參閱從 iOS 模擬器和 Android 模擬器 連線 至本機 Web 服務。

根據預設,IIS Express 只會回應 的要求 localhost。 遠端裝置(例如 Android 裝置、i 電話 甚至模擬器)將無法存取您的本機 WCF 服務。 您必須知道局域網路上的 Windows 10 工作站 IP 位址。 針對此範例的目的,假設您的工作站具有IP位址 192.168.1.143。 下列步驟說明如何設定 Windows 10 和 IIS Express 以接受遠端連線,並從實體或虛擬設備連線至服務:

  1. 將例外狀況新增至 Windows 防火牆。 您必須透過 Windows 防火牆開啟埠,子網上的應用程式才能用來與 WCF 服務通訊。 在防火牆中建立開啟埠 49393 的輸入規則。 從系統管理命令提示字元中,執行此命令:

    netsh advfirewall firewall add rule name="TodoWCFService" dir=in protocol=tcp localport=49393 profile=private remoteip=localsubnet action=allow
    
  2. 將 IIS Express 設定為接受遠端連線。 您可以在 [方案目錄].vs\config\applicationhost.config 編輯 IIS Express 的組態檔,以設定 IIS Expresssite尋找名稱TodoWCFService為的專案。 它看起來應該類似下列 XML:

    <site name="TodoWCFService" id="2">
        <application path="/" applicationPool="Clr4IntegratedAppPool">
            <virtualDirectory path="/" physicalPath="C:\Users\tom\TodoWCF\TodoWCFService\TodoWCFService" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:49393:localhost" />
        </bindings>
    </site>
    

    您必須新增兩 binding 個元素,以開啟埠 49393 至外部流量和 Android 模擬器。 系結會使用 [IP address]:[port]:[hostname] 格式,指定 IIS Express 如何回應要求。 外部要求將具有必須指定為 binding的主機名。 將下列 XML 新增至 bindings 元素,並將 IP 位址取代為您自己的 IP 位址:

    <binding protocol="http" bindingInformation="*:49393:192.168.1.143" />
    <binding protocol="http" bindingInformation="*:49393:127.0.0.1" />
    

    變更之後, bindings 元素看起來應該如下所示:

    <site name="TodoWCFService" id="2">
        <application path="/" applicationPool="Clr4IntegratedAppPool">
            <virtualDirectory path="/" physicalPath="C:\Users\tom\TodoWCF\TodoWCFService\TodoWCFService" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:49393:localhost" />
            <binding protocol="http" bindingInformation="*:49393:192.168.1.143" />
            <binding protocol="http" bindingInformation="*:49393:127.0.0.1" />
        </bindings>
    </site>
    

    重要

    根據預設,基於安全性考慮,IIS Express 將不會接受來自外部來源的連線。 若要啟用來自遠端裝置的連線,您必須以 管理員 許可權執行 IIS Express。 若要這麼做,最簡單的方式是使用 管理員 許可權來執行Visual Studio 2017。 這會在執行 TodoWCFService 時啟動具有 管理員 許可權的 IIS Express。

    完成這些步驟后,您應該能夠執行 TodoWCFService,並從子網上的其他裝置連線。 您可以執行應用程式並瀏覽 http://localhost:49393/TodoService.svc來測試此專案。 如果您在流覽該 URL 時收到 錯誤要求 錯誤,在 bindings IIS Express 設定中可能不正確(要求已連線到 IIS Express,但遭到拒絕)。 如果您收到不同的錯誤,可能是您的應用程式未執行或防火牆設定不正確。

    若要讓 IIS Express 繼續執行並提供服務,請關閉 Project Properties Web 調試程式中[編輯後繼續] 選項。>>

  3. 自定義用來存取服務的端點裝置。 此步驟牽涉到設定在實體或模擬裝置上執行的用戶端應用程式,以存取 WCF 服務。

    Android 模擬器會使用內部 Proxy 來防止模擬器直接存取主計算機的 localhost 位址。 相反地,模擬器上的位址 10.0.2.2 會透過內部 Proxy 路由傳送至 localhost 主電腦上。 這些 Proxy 要求將具有 127.0.0.1 要求標頭中的主機名,這就是為什麼您在上述步驟中為此主機名建立 IIS Express 系結的原因。

    即使您使用適用於 Windows遠端 iOS 模擬器,iOS 模擬器仍會在 Mac 組建主機上執行。 來自模擬器的網路要求會將您的工作站IP放在區域網路作為主機名(在此範例中為 192.168.1.143,但您的實際IP位址可能會不同)。 這就是為什麼您在上述步驟中為此主機名建立 IIS Express 系結的原因。

    SoapUrl請確定 TodoWCF (可攜式) 專案中Constants.cs檔案中的 屬性具有正確的網路值:

    public static string SoapUrl
    {
        get
        {
            var defaultUrl = "http://localhost:49393/TodoService.svc";
    
            if (Device.RuntimePlatform == Device.Android)
            {
                defaultUrl = "http://10.0.2.2:49393/TodoService.svc";
            }
            else if (Device.RuntimePlatform == Device.iOS)
            {
                defaultUrl = "http://192.168.1.143:49393/TodoService.svc";
            }
    
            return defaultUrl;
        }
    }
    

    使用適當的端點設定Constants.cs之後,您應該能夠從實體或虛擬設備連線到 Windows 10 工作站上執行的 TodoWCFService。