使用 ASP.NET Web 服務 (ASMX)

Download Sample 下載範例

ASMX 可讓您建置 Web 服務,以使用簡單物件存取通訊協定 (SOAP) 傳送訊息。 SOAP 是平台獨立且與語言無關的通訊協定,可用於建置和存取 Web 服務。 ASMX 服務的取用者不需要知道用來實作服務的平臺、物件模型或程式設計語言。 他們只需要瞭解如何傳送和接收SOAP訊息。 本文示範如何從 Xamarin.Forms 應用程式取用 ASMX SOAP 服務。

SOAP 訊息是包含下列元素的 XML 檔:

  • 名為 Envelope 的根元素,會將 XML 檔識別為 SOAP 訊息。
  • 選擇性 的 Header 元素,其中包含應用程式特定資訊,例如驗證數據。 如果 Header 元素存在,它必須是 Envelope 元素的第一個子元素
  • 必要的 Body 元素,其中包含要供收件者使用的 SOAP 訊息。
  • 選擇性 的Fault 元素,用來指出錯誤訊息。 如果 Fault 元素存在,它必須是 Body 元素的子元素。

SOAP 可以透過許多傳輸通訊協議運作,包括 HTTP、SMTP、TCP 和 UDP。 不過,ASMX 服務只能透過 HTTP 運作。 Xamarin 平臺透過 HTTP 支援標準 SOAP 1.1 實作,這包括許多標準 ASMX 服務組態的支援。

此範例包含在實體或模擬裝置上執行的行動應用程式,以及提供取得、新增、編輯和刪除數據之方法的 ASMX 服務。 當行動應用程式執行時,它們會連線到本機裝載的 ASMX 服務,如下列螢幕快照所示:

Sample Application

注意

在 iOS 9 和更新版本中,應用程式傳輸安全性 (ATS) 會強制執行因特網資源(例如應用程式後端伺服器)與應用程式之間的安全連線,以防止意外洩漏敏感性資訊。 由於 ATS 預設會在針對 iOS 9 建置的應用程式中啟用,因此所有連線都會受限於 ATS 安全性需求。 如果連線不符合這些需求,它們將會失敗併發生例外狀況。 如果無法使用 HTTPS 通訊協議和保護因特網資源的通訊,則可以退出宣告 ATS。 您可以藉由更新應用程式的 Info.plist 檔案來達成此目的。 如需詳細資訊,請參閱 應用程式傳輸安全性

取用 Web 服務

ASMX 服務提供下列作業:

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

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

建立 TodoService Proxy

稱為 TodoService的 Proxy 類別會擴充 SoapHttpClientProtocol 並提供透過 HTTP 與 ASMX 服務通訊的方法。 Proxy 是藉由將 Web 參考新增至 Visual Studio 2019 或 Visual Studio 2017 中的每個平臺特定項目來產生。 Web 參考會針對服務 Web 服務描述語言 (WSDL) 檔案中定義的每個動作產生方法和事件。

例如, GetTodoItems 服務動作會導致 GetTodoItemsAsync 方法及 GetTodoItemsCompleted Proxy 中的事件。 產生的方法具有 void 傳回型別,並在父SoapHttpClientProtocol類別上叫用GetTodoItems動作。 當叫用的方法收到來自服務的回應時,它會 GetTodoItemsCompleted 引發 事件,並提供事件 Result 屬性內的響應數據。

建立 ISoapService 實作

為了讓共用的跨平臺項目能夠與服務搭配使用,此範例會 ISoapService 定義 介面,其遵循 C# 中的工作異步程序設計模型。 每個平台都會實作 ISoapService 來公開平臺特定的 Proxy。 此範例會使用 TaskCompletionSource 物件將 Proxy 公開為工作異步介面。 如需使用 TaskCompletionSource 的詳細數據,請參閱下列各節中每個動作類型的實作。

範例 SoapService

  1. 將 具現化 TodoService 為類別層級實例
  2. 建立稱為 Items 的集合以儲存 TodoItem 物件
  3. 指定上選擇性 Url 屬性的自訂端點 TodoService
public class SoapService : ISoapService
{
    ASMXService.TodoService todoService;
    public List<TodoItem> Items { get; private set; } = new List<TodoItem>();

    public SoapService ()
    {
        todoService = new ASMXService.TodoService ();
        todoService.Url = Constants.SoapUrl;
        ...
    }
}

建立數據傳輸物件

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

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

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

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

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

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

取出資料

介面 ISoapService 預期 RefreshDataAsync 方法會傳回 Task 具有專案集合的 。 不過, TodoService.GetTodoItemsAsync 方法會傳回 void。 若要滿足介面模式,您必須呼叫 GetTodoItemsAsync、等候 GetTodoItemsCompleted 事件引發,並填入集合。 這可讓您將有效的集合傳回UI。

下列範例會建立新的 TaskCompletionSource、開始 方法中的 RefreshDataAsync 異步呼叫,並等候 Task 所提供的 TaskCompletionSource。 叫用事件處理程式時 TodoService_GetTodoItemsCompleted ,它會填入集合並 Items 更新 TaskCompletionSource

public class SoapService : ISoapService
{
    TaskCompletionSource<bool> getRequestComplete = null;
    ...

    public SoapService()
    {
        ...
        todoService.GetTodoItemsCompleted += TodoService_GetTodoItemsCompleted;
    }

    public async Task<List<TodoItem>> RefreshDataAsync()
    {
        getRequestComplete = new TaskCompletionSource<bool>();
        todoService.GetTodoItemsAsync();
        await getRequestComplete.Task;
        return Items;
    }

    private void TodoService_GetTodoItemsCompleted(object sender, ASMXService.GetTodoItemsCompletedEventArgs e)
    {
        try
        {
            getRequestComplete = getRequestComplete ?? new TaskCompletionSource<bool>();

            Items = new List<TodoItem>();
            foreach (var item in e.Result)
            {
                Items.Add(FromASMXServiceTodoItem(item));
            }
            getRequestComplete?.TrySetResult(true);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(@"\t\tERROR {0}", ex.Message);
        }
    }

    ...
}

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

建立或編輯數據

當您建立或編輯數據時,必須實作 ISoapService.SaveTodoItemAsync 方法。 這個方法會 TodoItem 偵測 是新的或更新的專案,並在 物件上 todoService 呼叫適當的方法。 CreateTodoItemCompleted也應該實作 和 EditTodoItemCompleted 事件處理程式,以便您知道何時todoService收到 ASMX 服務的回應(這些可以合併成單一處理程式,因為它們執行相同的作業)。 下列範例示範介面和事件處理程序實作,以及 TaskCompletionSource 用來異步操作的物件:

public class SoapService : ISoapService
{
    TaskCompletionSource<bool> saveRequestComplete = null;
    ...

    public SoapService()
    {
        ...
        todoService.CreateTodoItemCompleted += TodoService_SaveTodoItemCompleted;
        todoService.EditTodoItemCompleted += TodoService_SaveTodoItemCompleted;
    }

    public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
    {
        try
        {
            var todoItem = ToASMXServiceTodoItem(item);
            saveRequestComplete = new TaskCompletionSource<bool>();
            if (isNewItem)
            {
                todoService.CreateTodoItemAsync(todoItem);
            }
            else
            {
                todoService.EditTodoItemAsync(todoItem);
            }
            await saveRequestComplete.Task;
        }
        catch (SoapException se)
        {
            Debug.WriteLine("\t\t{0}", se.Message);
        }
        catch (Exception ex)
        {
            Debug.WriteLine("\t\tERROR {0}", ex.Message);
        }
    }

    private void TodoService_SaveTodoItemCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
    {
        saveRequestComplete?.TrySetResult(true);
    }

    ...
}

刪除資料

刪除數據需要類似的實作。 TaskCompletionSource定義、實作事件處理程式和 ISoapService.DeleteTodoItemAsync 方法:

public class SoapService : ISoapService
{
    TaskCompletionSource<bool> deleteRequestComplete = null;
    ...

    public SoapService()
    {
        ...
        todoService.DeleteTodoItemCompleted += TodoService_DeleteTodoItemCompleted;
    }

    public async Task DeleteTodoItemAsync (string id)
    {
        try
        {
            deleteRequestComplete = new TaskCompletionSource<bool>();
            todoService.DeleteTodoItemAsync(id);
            await deleteRequestComplete.Task;
        }
        catch (SoapException se)
        {
            Debug.WriteLine("\t\t{0}", se.Message);
        }
        catch (Exception ex)
        {
            Debug.WriteLine("\t\tERROR {0}", ex.Message);
        }
    }

    private void TodoService_DeleteTodoItemCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
    {
        deleteRequestComplete?.TrySetResult(true);
    }

    ...
}

測試 Web 服務

使用本機裝載服務測試實體或模擬裝置時,需要備妥自定義 IIS 組態、端點位址和防火牆規則。 如需如何設定環境以進行測試的詳細資訊,請參閱 設定 IIS Express 的遠端訪問。 測試 WCF 與 ASMX 之間唯一的差異是 TodoService 的埠號碼。