Visual Studio Code を使用して Azure Functions を Azure Storage に接続する

Azure Functions を使用すると、独自の統合コードを記述しなくても、Azure サービスやその他のリソースを関数に接続できます。 これらの バインド は、入力と出力の両方を表し、関数定義内で宣言されます。 バインドからのデータは、パラメーターとして関数に提供されます。 "トリガー" は、特殊な種類の入力バインドです。 関数はトリガーを 1 つしか持てませんが、複数の入力および出力バインドを持つことができます。 詳細については、「Azure Functions でのトリガーとバインドの概念」を参照してください。

この記事では、Visual Studio Code を使用して、前のクイックスタート記事で作成した関数に Azure Storage を接続する方法について説明します。 この関数に追加する出力バインドは、HTTP 要求のデータを Azure Queue storage キュー内のメッセージに書き込みます。

ほとんどのバインドでは、バインドされているサービスにアクセスするために関数が使用する、保存されている接続文字列が必要です。 作業を簡単にするために、関数アプリで作成したストレージ アカウントを使用します。 このアカウントへの接続は、既に AzureWebJobsStorage という名前のアプリ設定に保存されています。

ローカル環境を構成する

この記事を始める前に、以下の要件を満たす必要があります。

  • Visual Studio Code 用の Azure Storage 拡張機能をインストールする。

  • Azure Storage Explorer をインストールする。 Storage Explorer は、出力バインドによって生成されるキュー メッセージの調査に使用するツールです。 Storage Explorer は、macOS、Windows、Linux ベースのオペレーティング システムでサポートされます。

この記事では、Visual Studio Code から Azure サブスクリプションに既にサインインしていることを前提としています。 コマンド パレットから Azure: Sign In を実行するとサインインできます。

関数アプリの設定をダウンロードする

前のクイックスタートの記事では、必要なストレージ アカウントと共に Azure で関数アプリを作成しました。 このアカウントの接続文字列は、Azure のアプリ設定に安全に格納されています。 この記事では、同じアカウントのストレージ キューにメッセージを書き込みます。 関数をローカルで実行しているときにストレージ アカウントに接続するには、アプリ設定を local.settings.json ファイルにダウンロードする必要があります。

  1. F1 キーを押してコマンド パレットを開き、コマンド Azure Functions: Download Remote Settings.... を検索して実行します。

  2. 前の記事で作成した関数アプリを選択します。 [すべてはい] を選択して既存のローカル設定を上書きします。

    重要

    local.settings.json ファイルは、機密情報が含まれているため、公開されることはなく、ソース管理から除外されます。

  3. ストレージ アカウントの接続文字列値のキーである AzureWebJobsStorage をコピーします。 この接続を使用して、出力バインドが期待どおりに動作することを確認します。

バインディング拡張機能を登録する

Queue storage の出力バインドを使用しているため、このプロジェクトを実行する前に Storage のバインド拡張機能をインストールしておく必要があります。

プロジェクトは、拡張機能バンドルを使用するように構成されています。これにより、事前定義された一連の拡張機能パッケージが自動的にインストールされます。

拡張機能バンドルの使用は、プロジェクトのルートにある host.json ファイルで次のように有効になっています。

{
  "version": "2.0",
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[1.*, 2.0.0)"
  } 
}

HTTP トリガーとタイマー トリガーを除き、バインドは拡張機能パッケージとして実装されます。 ターミナル ウィンドウで次の dotnet add package コマンドを実行して、Storage 拡張機能パッケージをプロジェクトに追加します。

dotnet add package Microsoft.Azure.WebJobs.Extensions.Storage

これで、Storage の出力バインドをプロジェクトに追加できるようになります。

出力バインディングを追加する

Functions では、各種のバインドで、directiontype、および固有の name が function.json ファイル内で定義される必要があります。 これらの属性を定義する方法は、関数アプリの言語によって異なります。

バインドの属性は、function.json ファイルで直接定義されています。 バインドの種類によっては、追加のプロパティが必要になることもあります。 キュー出力構成では、Azure Storage キュー バインドに必要なフィールドについて説明されています。 この拡張機能により、バインドを簡単に function.json ファイルに追加できます。

バインドを作成するには、HttpTrigger フォルダー内の function.json ファイルを右クリック (macOS では Ctrl キーを押しながらクリック) して、 [バインドの追加] を選択します。プロンプトに従って、新しいバインドの次のバインド プロパティを定義します。

Prompt 説明
Select binding direction (バインド方向を選択する) out バインドは出力バインドです。
Select binding with direction... (方向を使用してバインドを選択する...) Azure Queue Storage バインドは Azure Storage キュー バインドです。
コードでこのバインドの特定に使用する名前 msg コードで参照されているバインド パラメーターを識別する名前。
The queue to which the message will be sent (メッセージの送信先のキュー) outqueue バインドが書き込むキューの名前。 queueName が存在しない場合は、バインドによって最初に使用されるときに作成されます。
Select setting from "local.setting.json" ("local.setting.json" から設定を選択する) AzureWebJobsStorage ストレージ アカウントの接続文字列を含むアプリケーション設定の名前。 AzureWebJobsStorage 設定には、関数アプリで作成したストレージ アカウントの接続文字列が含まれています。

バインドは、function.json の bindings 配列に追加されます。このファイルは次のようになります。

{
  "type": "queue",
  "direction": "out",
  "name": "msg",
  "queueName": "outqueue",
  "connection": "AzureWebJobsStorage"
}

C# プロジェクトでは、バインドは関数メソッドのバインド属性として定義されます。 具体的な定義は、お使いのアプリがインプロセス (C# クラス ライブラリ) で実行されるのか分離プロセスで実行されるのかによって異なります。

HttpExample.cs プロジェクト ファイルを開いて、Run メソッドの定義に次のパラメーターを追加します。

[Queue("outqueue"),StorageAccount("AzureWebJobsStorage")] ICollector<string> msg,

msg パラメーターは ICollector<T> 型です。これは、関数の完了時に出力バインドに書き込まれるメッセージのコレクションを表します。 この場合、出力は outqueue という名前のストレージ キューです。 このストレージ アカウントの接続文字列は、StorageAccountAttribute で設定されます。 この属性は、ストレージ アカウントの接続文字列を含む設定を示し、クラス、メソッド、パラメーター レベルで適用できます。 この例では、既定のストレージ アカウントを既に使用しているため、StorageAccountAttribute を省略できます。

Run メソッドの定義は次のようになります。

[FunctionName("HttpExample")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, 
    [Queue("outqueue"),StorageAccount("AzureWebJobsStorage")] ICollector<string> msg, 
    ILogger log)

Java プロジェクトでは、バインドは関数メソッドのバインド注釈として定義されます。 その後、これらの注釈に基づいて function.json ファイルが自動的に生成されます。

src/main/java の下の対象の関数コードの場所を参照し、Function.java プロジェクト ファイルを開きます。run メソッド定義に、次のパラメーターを追加します。

@QueueOutput(name = "msg", queueName = "outqueue", 
connection = "AzureWebJobsStorage") OutputBinding<String> msg,

msg パラメーターは OutputBinding<T> 型です。これは、関数の完了時に出力バインドにメッセージとして書き込まれる文字列のコレクションを表します。 この場合、出力は outqueue という名前のストレージ キューです。 このストレージ アカウントの接続文字列は、connection メソッドによって設定されます。 接続文字列自体ではなく、ストレージ アカウントの接続文字列を含むアプリケーション設定を渡します。

run メソッドの定義は次の例のようになります。

@FunctionName("HttpExample")
public HttpResponseMessage run(
        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) 
        HttpRequestMessage<Optional<String>> request, 
        @QueueOutput(name = "msg", queueName = "outqueue", 
        connection = "AzureWebJobsStorage") OutputBinding<String> msg, 
        final ExecutionContext context) {

出力バインディングを使用するコードを追加する

バインドが定義されたら、そのバインドの name を使用して、関数シグネチャの属性としてアクセスできます。 出力バインドを使用すると、認証、キュー参照の取得、またはデータの書き込みに、Azure Storage SDK のコードを使用する必要がなくなります。 Functions ランタイムおよびキューの出力バインドが、ユーザーに代わってこれらのタスクを処理します。

context.bindingsmsg 出力バインド オブジェクトを使用してキュー メッセージを作成するコードを追加します。 このコードを context.res ステートメントの前に追加します。

// Add a message to the Storage queue,
// which is the name passed to the function.
context.bindings.msg = (req.query.name || req.body.name);

この時点で、関数は次のようになります。

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    if (req.query.name || (req.body && req.body.name)) {
        // Add a message to the Storage queue,
        // which is the name passed to the function.
        context.bindings.msg = (req.query.name || req.body.name);
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: "Hello " + (req.query.name || req.body.name)
        };
    }
    else {
        context.res = {
            status: 400,
            body: "Please pass a name on the query string or in the request body"
        };
    }
};

context.bindingsmsg 出力バインド オブジェクトを使用してキュー メッセージを作成するコードを追加します。 このコードを context.res ステートメントの前に追加します。

context.bindings.msg = name;

この時点で、関数は次のようになります。

import { AzureFunction, Context, HttpRequest } from "@azure/functions"

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
    context.log('HTTP trigger function processed a request.');
    const name = (req.query.name || (req.body && req.body.name));

    if (name) {
        // Add a message to the storage queue, 
        // which is the name passed to the function.
        context.bindings.msg = name; 
        // Send a "hello" response.
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: "Hello " + (req.query.name || req.body.name)
        };
    }
    else {
        context.res = {
            status: 400,
            body: "Please pass a name on the query string or in the request body"
        };
    }
};

export default httpTrigger;

Push-OutputBinding コマンドレットと msg 出力バインディングを使用してキューにテキストを書き込むコードを追加します。 if ステートメントで OK ステータスを設定する前に、このコードを追加してください。

$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg

この時点で、関数は次のようになります。

using namespace System.Net

# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)

# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."

# Interact with query parameters or the body of the request.
$name = $Request.Query.Name
if (-not $name) {
    $name = $Request.Body.Name
}

if ($name) {
    # Write the $name value to the queue, 
    # which is the name passed to the function.
    $outputMsg = $name
    Push-OutputBinding -name msg -Value $outputMsg

    $status = [HttpStatusCode]::OK
    $body = "Hello $name"
}
else {
    $status = [HttpStatusCode]::BadRequest
    $body = "Please pass a name on the query string or in the request body."
}

# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = $status
    Body = $body
})

次のコードに合わせて HttpExample\__init__.py を更新します。関数の定義に msg パラメーターを、if name: ステートメントの下に msg.set(name) を追加してください。

import logging

import azure.functions as func


def main(req: func.HttpRequest, msg: func.Out[func.QueueMessage]) -> str:

    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

    if name:
        msg.set(name)
        return func.HttpResponse(f"Hello {name}!")
    else:
        return func.HttpResponse(
            "Please pass a name on the query string or in the request body",
            status_code=400
        )

msg パラメーターは、azure.functions.Out class のインスタンスです。 その set メソッドでは、文字列メッセージ (この場合、URL のクエリ文字列として関数に渡された名前) をキューに書き込みます。

msg 出力バインド オブジェクトを使用してキュー メッセージを作成するコードを追加します。 このコードは、メソッドから制御が戻る前に追加します。

if (!string.IsNullOrEmpty(name))
{
    // Add a message to the output collection.
    msg.Add(string.Format("Name passed to the function: {0}", name));
}

この時点で、関数は次のようになります。

[FunctionName("HttpExample")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, 
    [Queue("outqueue"),StorageAccount("AzureWebJobsStorage")] ICollector<string> msg, 
    ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");

    string name = req.Query["name"];

    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    dynamic data = JsonConvert.DeserializeObject(requestBody);
    name = name ?? data?.name;

    if (!string.IsNullOrEmpty(name))
    {
        // Add a message to the output collection.
        msg.Add(string.Format("Name passed to the function: {0}", name));
    }
    return name != null
        ? (ActionResult)new OkObjectResult($"Hello, {name}")
        : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}

これで、新しい msg パラメーターを使用して、関数コードから出力バインドに書き込むことができます。 成功応答の前に次のコード行を追加して、name の値を msg 出力バインドに追加します。

msg.setValue(name);

出力バインドを使用すると、認証、キュー参照の取得、またはデータの書き込みに、Azure Storage SDK のコードを使用する必要がなくなります。 Functions ランタイムおよびキューの出力バインドが、ユーザーに代わってこれらのタスクを処理します。

run メソッドは次の例のようになります。

@FunctionName("HttpExample")
public HttpResponseMessage run(
        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) 
        HttpRequestMessage<Optional<String>> request, 
        @QueueOutput(name = "msg", queueName = "outqueue", 
        connection = "AzureWebJobsStorage") OutputBinding<String> msg, 
        final ExecutionContext context) {
    context.getLogger().info("Java HTTP trigger processed a request.");

    // Parse query parameter
    String query = request.getQueryParameters().get("name");
    String name = request.getBody().orElse(query);

    if (name == null) {
        return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
        .body("Please pass a name on the query string or in the request body").build();
    } else {
        // Write the name to the message queue. 
        msg.setValue(name);

        return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
    }
}

テストを更新する

アーキタイプはテストのセットも作成するため、run メソッド シグネチャ内の新しい msg パラメーターを処理するためにこれらのテストを更新する必要があります。

src/main/java の下の対象のテスト コードの場所を参照し、Function.java プロジェクト ファイルを開きます。//Invoke の下のコード行を次のコードに置き換えます。

@SuppressWarnings("unchecked")
final OutputBinding<String> msg = (OutputBinding<String>)mock(OutputBinding.class);
final HttpResponseMessage ret = new Function().run(req, msg, context);

関数をローカルで実行する

  1. 前の記事と同様、F5 キーを押して関数アプリ プロジェクトと Core Tools を起動します。

  2. Core Tools を実行したまま、Azure: Functions 領域に移動します。 [Functions][ローカル プロジェクト] > [Functions] を展開します。 HttpExample 関数を右クリック (Mac では Ctrl キーを押しながらクリック) し、 [Execute Function Now](今すぐ関数を実行) を選択します。

    Visual Studio Code から今すぐ関数を実行する

  3. [Enter request body](要求本文を入力してください) に、要求メッセージ本文の値として { "name": "Azure" } が表示されます。 Enter キーを押して、この要求メッセージを関数に送信します。

  4. 応答が返されたら、Ctrl + C キーを押して Core Tools を停止します。

ストレージの接続文字列を使用しているため、ローカルで実行されている関数は Azure ストレージ アカウントに接続します。 出力バインディングを最初に使用するときに、outqueue という名前の新しいキューが、Functions ランタイムによってストレージ アカウントに作成されます。 このキューが新しいメッセージと共に作成されたことを確認するために、Storage Explorer を使用します。

ストレージ エクスプローラーをアカウントに接続する

既に Azure Storage Explorer をインストールして Azure アカウントに接続している場合は、このセクションをスキップしてください。

  1. Azure Storage Explorer ツールを実行し、左側の接続アイコンを選択して、 [アカウントの追加] を選択します。

    Microsoft Azure Storage Explorer に Azure アカウントを追加する

  2. [接続] ダイアログで、 [Add an Azure account](Azure アカウントを追加する) を選択し、お使いの Azure 環境 を選択して、 [サインイン] を選択します。

    Azure アカウントへのサインイン

自分のアカウントへのサインインが成功すると、そのアカウントに関連付けられている Azure サブスクリプションがすべて表示されます。

出力キューを確認する

  1. Visual Studio Code で、F1 キーを押してコマンド パレットを開き、コマンド Azure Storage: Open in Storage Explorer を検索して実行し、自分のストレージ アカウント名を選択します。 Azure Storage Explorer で自分のストレージ アカウントが開きます。

  2. [キュー] ノードを展開して、outqueue という名前のキューを選択します。

    このキューには、HTTP によってトリガーされる関数を実行したときにキューの出力バインディングが作成されたというメッセージが含まれます。 Azure の既定の name 値で関数を呼び出した場合、キュー メッセージは「Name passed to the function: Azure」(関数に渡された名前: Azure) になります。

    Azure Storage Explorer に表示されたキュー メッセージ

  3. 関数を再度実行し、別の要求を送信すると、キューに新しいメッセージが表示されます。

ここで、更新された関数アプリを Azure に再発行します。

更新したアプリを再デプロイして検証する

  1. Visual Studio Code で、F1 キーを押してコマンド パレットを開きます。 コマンド パレットで、Azure Functions: Deploy to function app... を検索して選択します。

  2. 最初の記事で作成した関数アプリを選択します。 同じアプリにプロジェクトを再デプロイしているため、 [デプロイ] を選択して、ファイルの上書きに関する警告を無視します。

  3. デプロイの完了後、もう一度 [Execute Function Now](今すぐ関数を実行) 機能を使用して Azure で関数をトリガーできます。

  4. もう一度ストレージ キューのメッセージを表示して、出力バインドによってキューに新しいメッセージが再生成されていることを確認します。

リソースをクリーンアップする

Azure では、"リソース" とは、関数アプリ、関数、ストレージ アカウントなどのことを指します。 これらは "リソース グループ" に分類されており、グループを削除することでグループ内のすべてのものを削除できます。

これらのクイックスタートを完了するためにリソースを作成しました。 これらのリソースには、アカウントの状態サービスの価格に応じて課金される場合があります。 リソースの必要がなくなった場合にそれらを削除する方法を、次に示します。

  1. Visual Studio Code で、F1 キーを押してコマンド パレットを開きます。 コマンド パレットで、Azure Functions: Open in portal を検索して選択します。

  2. 関数アプリを選択し、Enter キーを押します。 その関数アプリのページが Azure portal で開きます。

  3. [概要] タブで、 [リソース グループ] の横にある名前付きリンクを選択します。

    関数アプリのページから削除するリソース グループを選択する。

  4. [リソース グループ] ページで、含まれているリソースの一覧を確認し、削除するものであることを確認します。

  5. [リソース グループの削除] を選択し、指示に従います。

    削除には数分かかることがあります。 実行されると、通知が数秒間表示されます。 ページの上部にあるベルのアイコンを選択して、通知を表示することもできます。

次のステップ

HTTP によってトリガーされる関数を、ストレージ キューにデータを書き込むように更新しました。 この後は、Visual Studio Code を使用した Functions の開発について理解を深めましょう。