ASP.NET Web サービス (ASMX) を使用する

サンプルのダウンロードサンプルのダウンロード

ASMX は、Simple Object Access Protocol (SOAP) を使用してメッセージを送信する Web サービスを構築する機能を提供します。 SOAP は、Web サービスを構築およびアクセスするためのプラットフォームに依存しない、言語に依存しないプロトコルです。 ASMX サービスのコンシューマーは、サービスの実装に使用されるプラットフォーム、オブジェクト モデル、またはプログラミング言語について何も知る必要はありません。 SOAP メッセージの送受信方法を理解するだけで済みます。 この記事では、アプリケーションから ASMX SOAP サービスを使用する方法について Xamarin.Forms 説明します。

SOAP メッセージは、次の要素を含む XML ドキュメントです。

  • XML ドキュメントを SOAP メッセージとして識別する Envelope という名前のルート要素。
  • 認証データなどのアプリケーション固有の情報を含む省略可能な Header 要素。 Header 要素が存在する場合は、Envelope 要素の最初の子要素である必要があります。
  • 受信者を対象とした SOAP メッセージを含む必須の Body 要素。
  • エラー メッセージを示すために使用される省略可能な Fault 要素。 Fault 要素が存在する場合は、Body 要素の子要素である必要があります。

SOAP は、HTTP、SMTP、TCP、UDP など、多くのトランスポート プロトコルで動作できます。 ただし、ASMX サービスは HTTP 経由でのみ動作できます。 Xamarin プラットフォームでは、HTTP 経由の標準 SOAP 1.1 実装がサポートされており、これには多くの標準 ASMX サービス構成のサポートが含まれます。

このサンプルには、物理デバイスまたはエミュレートされたデバイスで実行されるモバイル アプリケーションと、データを取得、追加、編集、削除するメソッドを提供する ASMX サービスが含まれます。 モバイル アプリケーションを実行すると、次のスクリーンショットに示すように、ローカルでホストされている ASMX サービスに接続します。

サンプル アプリケーション

注意

iOS 9 以降では、App Transport Security (ATS) によってインターネット リソース (アプリのバックエンド サーバーなど) とアプリ間のセキュリティで保護された接続が強制されるため、機密情報が誤って開示されるのを防ぎます。 iOS 9 用に構築されたアプリでは ATS が既定で有効になっているため、すべての接続には ATS セキュリティ要件が適用されます。 接続がこれらの要件を満たしていない場合は、例外で失敗します。 インターネット リソースに対してプロトコルとセキュリティで保護された通信を HTTPS 使用できない場合は、ATS をオプトアウトできます。 これは、アプリの Info.plist ファイルを更新することで実現できます。 詳細については、「 App Transport Security」を参照してください。

Web サービスを使用する

ASMX サービスでは、次の操作が提供されます。

操作 説明 パラメーター
GetTodoItems To Do アイテムのリストの取得
CreateTodoItem 新しい To Do アイテムを作成する シリアル化された XML TodoItem
EditTodoItem To Do アイテムの更新 シリアル化された XML TodoItem
DeleteTodoItem To Do アイテムの削除 シリアル化された XML TodoItem

アプリケーションで使用されるデータ モデルの詳細については、「 データのモデリング」を参照してください。

TodoService プロキシを作成する

と呼ばれる TodoServiceプロキシ クラスは、 を拡張 SoapHttpClientProtocol し、HTTP 経由で ASMX サービスと通信するためのメソッドを提供します。 プロキシは、Visual Studio 2019 または Visual Studio 2017 の各プラットフォーム固有のプロジェクトに Web 参照を追加することによって生成されます。 Web 参照は、サービスの Web サービス記述言語 (WSDL) ドキュメントで定義されている各アクションのメソッドとイベントを生成します。

たとえば、サービス アクションの GetTodoItems 結果として、 GetTodoItemsAsync メソッドとプロキシ内の GetTodoItemsCompleted イベントが発生します。 生成されたメソッドは void 戻り値の型を持ち、親SoapHttpClientProtocolクラスでGetTodoItemsアクションを呼び出します。 呼び出されたメソッドは、サービスから応答を受信すると、イベントを GetTodoItemsCompleted 発生させ、イベントの Result プロパティ内に応答データを提供します。

ISoapService 実装を作成する

共有のクロスプラットフォーム プロジェクトでサービスを操作できるようにするために、サンプルでは、C# のタスク非同期プログラミング モデルに従う インターフェイスを定義ISoapServiceします。 各プラットフォームでは、 を ISoapService 実装してプラットフォーム固有のプロキシを公開します。 このサンプルでは、 オブジェクトを使用 TaskCompletionSource して、プロキシをタスク非同期インターフェイスとして公開します。 の使用方法 TaskCompletionSource の詳細については、以下のセクションの各アクションの種類の実装を参照してください。

サンプル SoapService:

  1. TodoService クラス レベルのインスタンスとしてインスタンス化します
  2. オブジェクトを格納TodoItemするために 呼び出されるItemsコレクションを作成します
  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 使用してデータをモデル化します。 Web サービスにアイテムを TodoItem 格納するには、最初にプロキシで生成された 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 サービスからデータを取得する場合は、プロキシによって生成された TodoItem 型からインスタンスに変換する TodoItem 必要があります。 これは、次の FromASMXServiceTodoItem コード例に示すように、 メソッドを使用して実現されます。

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

このメソッドは、プロキシによって生成された TodoItem 型からデータを取得し、新しく作成 TodoItem されたインスタンスに設定します。

データを取得する

インターフェイスでは ISoapService 、 メソッドが項目コレクションを RefreshDataAsync 含む を Task 返す必要があります。 ただし、 メソッドは TodoService.GetTodoItemsAsync void を返します。 インターフェイス パターンを満たすには、 を呼び出し GetTodoItemsAsync、イベントが GetTodoItemsCompleted 発生するまで待機し、コレクションにデータを設定する必要があります。 これにより、有効なコレクションを UI に返すことができます。

次の例では、新しい TaskCompletionSourceを作成し、 メソッドで非同期呼び出しをRefreshDataAsync開始し、 によって提供される TaskCompletionSourceTask待機します。 イベント ハンドラーが 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 サービスからいつ 応答を受信したかがわかります (これらは同じ操作を実行するため、1 つのハンドラーに結合できます)。 次の例では、インターフェイスとイベント ハンドラーの実装と、 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 のポート番号です。