Azure Functions C# スクリプト (.csx) 開発者向けリファレンス

この記事では、C# スクリプト ( .csx) を使用した Azure Functions 開発の概要を示します。

Azure Functions では、次のいずれかの方法で C# を使用して関数を開発できます。

実行プロセス Code 拡張機能 開発環境 リファレンス
C# スクリプト インプロセス .csx ポータル
Core Tools
この記事の内容は次のとおりです。
C# クラス ライブラリ インプロセス .cs Visual Studio
Visual Studio Code
Core Tools
インプロセス C# クラス ライブラリ関数
C# クラス ライブラリ (分離ワーカー プロセス) 分離ワーカー プロセス内 .cs Visual Studio
Visual Studio Code
Core Tools
.NET 分離ワーカー プロセス関数

この記事では、「Azure Functions の開発者向けガイド」を既に読んでいることを前提としています。

.csx のしくみ

データは、メソッドの引数を使用して C# 関数に渡されます。 引数名は function.json ファイルで指定され、関数のロガーやキャンセル トークンなどにアクセスするための定義済みの名前があります。

.csx の形式では、"定型" の記述が少なく、C# 関数のみの記述に重点が置かれています。 名前空間およびクラスにすべてをラップするのではなく、Run メソッドを定義するだけです。 通常どおり、すべてのアセンブリ参照と名前空間をファイルの先頭に含めます。

関数アプリの .csx ファイルは、インスタンスの初期化時にコンパイルされます。 このコンパイル手順は、C# クラス ライブラリと比較して C# スクリプト関数のコールド スタートに長い時間がかかることなどを意味します。 このコンパイル手順は、C# クラス ライブラリが編集可能でないのに対し、C# スクリプト関数が Azure portal 上で編集可能である理由でもあります。

フォルダー構造

C# スクリプト プロジェクトのフォルダー構造は、次の例のようになります。

FunctionsProject
 | - MyFirstFunction
 | | - run.csx
 | | - function.json
 | | - function.proj
 | - MySecondFunction
 | | - run.csx
 | | - function.json
 | | - function.proj
 | - host.json
 | - extensions.csproj
 | - bin

関数アプリの構成に使用できる共有 host.json ファイルがあります。 各関数には、独自のコード ファイル (.csx) とバインディング構成ファイル (function.json) があります。

Functions ランタイムのバージョン 2.x およびそれ以降 で必要なバインディング拡張機能は、bin フォルダー内の実際のライブラリファイルと共に、extensions.csprojファイルで定義されます。 ローカルで開発する場合は、バインド拡張機能を登録する必要があります。 Azure portal 上で関数を開発するときに、この登録が実行されます。

引数へのバインド

入力または出力データは、function.json 構成ファイルの name プロパティを介して C# スクリプト関数パラメーターにバインドされます。 次の例は、キューによってトリガーされる関数の function.json ファイルと run.csx ファイルを示しています。 キュー メッセージからデータを受信するパラメーターの名前は myQueueItem です。これは name プロパティの値であるためです。

{
    "disabled": false,
    "bindings": [
        {
            "type": "queueTrigger",
            "direction": "in",
            "name": "myQueueItem",
            "queueName": "myqueue-items",
            "connection":"MyStorageConnectionAppSetting"
        }
    ]
}
#r "Microsoft.WindowsAzure.Storage"

using Microsoft.Extensions.Logging;
using Microsoft.WindowsAzure.Storage.Queue;
using System;

public static void Run(CloudQueueMessage myQueueItem, ILogger log)
{
    log.LogInformation($"C# Queue trigger function processed: {myQueueItem.AsString}");
}

#r ステートメントについては、この記事の後半で説明します。

バインドでサポートされる型

各バインドには独自にサポートされている型があります。たとえば、BLOB トリガーは文字列パラメーター、POCO パラメーター、CloudBlockBlob パラメーター、またはサポートされるその他の複数の型のいずれかで使用できます。 BLOB バインディングのバインド リファレンスに関する記事では、BLOB トリガーでサポートされているすべてのパラメーター型の一覧を示しています。 詳細については、トリガーとバインドに関する記事と、各バインドの種類に対応するバインド リファレンス ドキュメントをご覧ください。

ヒント

HTTP または Webhook のバインディングを使用する予定がある場合は、不適切な HttpClient のインスタンス化によって生じるおそれのあるポートの枯渇を防止してください。 詳細については、「How to manage connections in Azure Functions」(Azure Functions で接続を管理する方法) を参照してください。

カスタム クラスの参照

カスタムの単純な従来の CLR オブジェクト (POCO) クラスを使用する必要がある場合は、クラス定義を同じファイルに含めることも、別のファイルに格納することもできます。

次の例は、POCO クラス定義を含む run.csx の例を示しています。

public static void Run(string myBlob, out MyClass myQueueItem)
{
    log.Verbose($"C# Blob trigger function processed: {myBlob}");
    myQueueItem = new MyClass() { Id = "myid" };
}

public class MyClass
{
    public string Id { get; set; }
}

POCO クラスでは、各プロパティにゲッターとセッターが定義されている必要があります。

.csx コードの再利用

他の .csx ファイルで定義されたクラスとメソッドを、run.csx ファイルで使用できます。 そのためには、run.csx ファイル内で #load ディレクティブを使用します。 次の例では、MyLogger という名前のログ記録ルーチンが myLogger.csx 内で共有され、#load ディレクティブを使用して run.csx に読み込まれます。

run.csxの例:

#load "mylogger.csx"

using Microsoft.Extensions.Logging;

public static void Run(TimerInfo myTimer, ILogger log)
{
    log.LogInformation($"Log by run.csx: {DateTime.Now}");
    MyLogger(log, $"Log by MyLogger: {DateTime.Now}");
}

mylogger.csxの例:

public static void MyLogger(ILogger log, string logtext)
{
    log.LogInformation(logtext);
}

共有された .csx ファイルの使用は、POCO オブジェクトを使用して関数間で渡されるデータを厳密に型宣言する場合の一般的なパターンです。 次の簡略化された例では、HTTP トリガーとキュー トリガーが Order という名前の POCO オブジェクトを共有して、注文データを厳密に型宣言しています。

例: HTTP トリガーの run.csx

#load "..\shared\order.csx"

using System.Net;
using Microsoft.Extensions.Logging;

public static async Task<HttpResponseMessage> Run(Order req, IAsyncCollector<Order> outputQueueItem, ILogger log)
{
    log.LogInformation("C# HTTP trigger function received an order.");
    log.LogInformation(req.ToString());
    log.LogInformation("Submitting to processing queue.");

    if (req.orderId == null)
    {
        return new HttpResponseMessage(HttpStatusCode.BadRequest);
    }
    else
    {
        await outputQueueItem.AddAsync(req);
        return new HttpResponseMessage(HttpStatusCode.OK);
    }
}

例: キュー トリガーの run.csx

#load "..\shared\order.csx"

using System;
using Microsoft.Extensions.Logging;

public static void Run(Order myQueueItem, out Order outputQueueItem, ILogger log)
{
    log.LogInformation($"C# Queue trigger function processed order...");
    log.LogInformation(myQueueItem.ToString());

    outputQueueItem = myQueueItem;
}

例: order.csx

public class Order
{
    public string orderId {get; set; }
    public string custName {get; set;}
    public string custAddress {get; set;}
    public string custEmail {get; set;}
    public string cartId {get; set; }

    public override String ToString()
    {
        return "\n{\n\torderId : " + orderId +
                  "\n\tcustName : " + custName +
                  "\n\tcustAddress : " + custAddress +
                  "\n\tcustEmail : " + custEmail +
                  "\n\tcartId : " + cartId + "\n}";
    }
}

#load ディレクティブで相対パスを使用できます。

  • #load "mylogger.csx" によって、関数フォルダーにあるファイルが読み込まれます。
  • #load "loadedfiles\mylogger.csx" によって、関数フォルダー内のフォルダーにあるファイルが読み込まれます。
  • #load "..\shared\mylogger.csx" によって、関数フォルダーと同じレベル ( wwwrootの直下) にあるフォルダーのファイルが読み込まれます。

#load ディレクティブは、 .csx ファイルでのみ機能し、 .cs ファイルでは機能しません。

メソッドの戻り値へのバインド

function.json 内の名前 $return を使用して、出力バインディングにメソッド戻り値を使用できます。 例については、トリガーとバインディングに関するページを参照してください。

正常な関数の実行によって、常に戻り値が出力バインドに渡される場合のみ、戻り値を使用してください。 それ以外の場合は、次のセクションに示すように ICollector または IAsyncCollector を使用してください。

複数の出力値の書き込み

1 つの出力バインドに複数の値を書き込むため、または正常な関数の呼び出しによって出力バインドに渡される値がない場合、ICollector または IAsyncCollector 型を使用してください。 これらの型は、メソッド完了時に出力バインドに書き込まれる、書き込み専用接続です。

この例では、ICollector を使用して複数のキュー メッセージを同じキューに書き込みます。

public static void Run(ICollector<string> myQueue, ILogger log)
{
    myQueue.Add("Hello");
    myQueue.Add("World!");
}

ログ記録

出力を C# のストリーミング ログにログ記録するために、ILogger 型の引数を含めます。 これの名前を logにすることをお勧めします。 Azure Functions では Console.Write を使用しないでください。

public static void Run(string myBlob, ILogger log)
{
    log.LogInformation($"C# Blob trigger function processed: {myBlob}");
}

Note

TraceWriter の代わりに使用できる新しいログ記録フレームワークについては、.NET クラス ライブラリ開発者ガイドのドキュメント「ILogger」を参照してください。

カスタム メトリックのログ記録

ILoggerLogMetric 拡張メソッドを使用して、Application Insights でカスタム メトリックを作成できます。 メソッド呼び出しの例を次に示します。

logger.LogMetric("TestMetric", 1234);

.NET 用 Application Insights API を使用して TrackMetric を呼び出す代わりに、このコードを使用できます。

非同期

関数を非同期にするには、 キーワードを使用して Task オブジェクトを返します。

public async static Task ProcessQueueMessageAsync(
        string blobName,
        Stream blobInput,
        Stream blobOutput)
{
    await blobInput.CopyToAsync(blobOutput, 4096);
}

非同期関数では out パラメーターを使用できません。 出力バインドには、代わりに関数の戻り値またはコレクター オブジェクトを使用します。

キャンセル トークン

関数は CancellationToken パラメーターを受け付けることができます。これにより、オペレーティング システムは、その関数をいつ終了しようとしているかをコードに通知できます。 この通知を使用すれば、関数が予期せず終了してデータが不整合な状態になることを防止できます。

次の例は、関数の終了が迫っているかどうかを確認する方法を示しています。

using System;
using System.IO;
using System.Threading;

public static void Run(
    string inputText,
    TextWriter logger,
    CancellationToken token)
{
    for (int i = 0; i < 100; i++)
    {
        if (token.IsCancellationRequested)
        {
            logger.WriteLine("Function was cancelled at iteration {0}", i);
            break;
        }
        Thread.Sleep(5000);
        logger.WriteLine("Normal processing for queue message={0}", inputText);
    }
}

名前空間のインポート

名前空間をインポートする必要がある場合は、 using 句を使用して、通常どおりにインポートできます。

using System.Net;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

public static Task<HttpResponseMessage> Run(HttpRequestMessage req, ILogger log)

次の名前空間は自動的にインポートされるため、オプションとなります。

  • System
  • System.Collections.Generic
  • System.IO
  • System.Linq
  • System.Net.Http
  • System.Threading.Tasks
  • Microsoft.Azure.WebJobs
  • Microsoft.Azure.WebJobs.Host

外部アセンブリの参照

フレームワークのアセンブリには、 #r "AssemblyName" ディレクティブを使用して参照を追加します。

#r "System.Web.Http"

using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

public static Task<HttpResponseMessage> Run(HttpRequestMessage req, ILogger log)

次のアセンブリは、Azure Functions をホストしている環境によって自動的に追加されます。

  • mscorlib
  • System
  • System.Core
  • System.Xml
  • System.Net.Http
  • Microsoft.Azure.WebJobs
  • Microsoft.Azure.WebJobs.Host
  • Microsoft.Azure.WebJobs.Extensions
  • System.Web.Http
  • System.Net.Http.Formatting

次のアセンブリは、ランタイム バージョンによって単純な名前で参照できます。

  • Newtonsoft.Json
  • Microsoft.WindowsAzure.Storage*

*ランタイムのバージョン 4.x で削除されました。

コードでは、アセンブリは次の例のように参照されます。

#r "AssemblyName"

カスタム アセンブリの参照

カスタム アセンブリを参照するために、共有アセンブリまたはプライベート アセンブリのいずれかを使用できます。

  • 共有アセンブリは、関数アプリ内のすべての関数にわたって共有されます。 カスタム アセンブリを参照するには、そのアセンブリをご自分の関数アプリのルート フォルダー (wwwroot) 内の bin という名前のフォルダーにアップロードします。

  • プライベート アセンブリは、特定の関数のコンテキストの一部であり、異なるバージョンのサイドローディングをサポートします。 プライベート アセンブリを関数ディレクトリ の bin フォルダーにアップロードする必要があります。 #r "MyAssembly.dll" などのファイル名を使用してアセンブリを参照します。

関数フォルダーにファイルをアップロードする方法については、パッケージ管理に関するセクションをご覧ください。

監視対象のディレクトリ

関数のスクリプト ファイルを含むディレクトリは、アセンブリの変更を自動的に監視されています。 その他のディレクトリでアセンブリの変更を監視するには、host.jsonwatchDirectories の一覧にそのディレクトリを追加します。

NuGet パッケージを使用する

バインド拡張機能パッケージと他の NuGet パッケージの両方を関数アプリに追加する方法は、Functions ランタイムの対象バージョンによって異なります。

既定では、サポートされている一連の Functions 拡張機能NuGet パッケージは、拡張機能バンドルを使用して C# スクリプト関数アプリで使用できるようになります。 詳細については、「拡張機能バンドル」を参照してください。

何らかの理由でプロジェクトの拡張機能バンドルを使用できない場合は、Azure Functions Core Tools を使用して、アプリの function.json ファイルで定義されているバインドに基づいて拡張機能をインストールすることもできます。 コアツールを使用して拡張機能を登録する場合は、必ず [--csx] オプションを使用してください。 詳細については、「拡張機能をインストールする」を参照してください。

既定では、Core Tools は function.json ファイルを読み取り、関数アプリのファイル システム (wwwroot) のルートにある extensions.csproj C# クラス ライブラリ プロジェクト ファイルに必要なパッケージを追加します。 Core Tools は dotnet.exe を使用するため、これを使用して、この拡張ファイルに任意の NuGet パッケージ参照を追加できます。 インストール時に、Core Tools は extensions.csproj をビルドして、必要なライブラリをインストールします。 Microsoft.ProjectOxford.Face バージョン 1.1.0 への参照を追加する extensions.csproj ファイルの例を次に示します。

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.ProjectOxford.Face" Version="1.1.0" />
    </ItemGroup>
</Project>

Note

C# スクリプト (.csx) の場合は、TargetFrameworknetstandard2.0 の値に設定する必要があります。 net6.0 などの他のターゲット フレームワークはサポートされていません。

カスタム NuGet フィードを使用するには、関数アプリのルート フォルダー内の Nuget.Config ファイルでフィードを指定します。 詳しくは、「NuGet の動作の構成」をご覧ください。

ポータルでのみプロジェクトで作業している場合は、サイト内で直接、extensions.csproj ファイルまたは Nuget.Config ファイルを手動で作成する必要があります。 詳細については、「拡張機能を手動でインストールする」を参照してください。

環境変数

環境変数またはアプリ設定値を取得するには、次のコード例のように、 System.Environment.GetEnvironmentVariableを使用します。

public static void Run(TimerInfo myTimer, ILogger log)
{
    log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
    log.LogInformation(GetEnvironmentVariable("AzureWebJobsStorage"));
    log.LogInformation(GetEnvironmentVariable("WEBSITE_SITE_NAME"));
}

public static string GetEnvironmentVariable(string name)
{
    return name + ": " +
        System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
}

実行時のバインド

C# および他の .NET 言語では、function.json宣言型のバインドではなく命令型のバインド パターンを使用できます。 命令型のバインドは、設計時ではなくランタイム時にバインド パラメーターを計算する必要がある場合に便利です。 このパターンを使用すると、サポートされている入力バインドと出力バインドに関数コード内でバインドできます。

次のように命令型のバインドを定義します。

  • 必要な命令型のバインドの function.json にエントリを含めないでください。
  • 入力パラメーター Binder binder または IBinder binder を渡します。
  • 次の C# パターンを使用してデータ バインドを実行します。
using (var output = await binder.BindAsync<T>(new BindingTypeAttribute(...)))
{
    ...
}

BindingTypeAttribute はバインドを定義する .NET 属性、T はそのバインドの種類でサポートされている入力または出力の型です。 Tout パラメーター型 (out JObject など) にすることはできません。 たとえば、Mobile Apps テーブルの出力バインドは 6 種類の出力をサポートしますが、T に使用できるのは ICollector<T> または IAsyncCollector<T> のみです。

単一属性の例

次のコード例は、実行時に BLOB パスが定義された Storage Blob の出力バインドを作成し、この BLOB に文字列を書き込みます。

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host.Bindings.Runtime;

public static async Task Run(string input, Binder binder)
{
    using (var writer = await binder.BindAsync<TextWriter>(new BlobAttribute("samples-output/path")))
    {
        writer.Write("Hello World!!");
    }
}

BlobAttributeStorage Blob の入力バインドまたは出力バインドを定義します。TextWriter はサポートされている出力バインドの種類です。

複数属性の例

前の例では、関数アプリのメイン ストレージ アカウント接続文字列 (AzureWebJobsStorage) のアプリ設定を取得します。 ストレージ アカウントに使用するカスタム アプリ設定を指定するには、StorageAccountAttribute を追加し、属性の配列を に渡します。 IBinderではなく、Binder パラメーターを使用します。 次に例を示します。

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host.Bindings.Runtime;

public static async Task Run(string input, Binder binder)
{
    var attributes = new Attribute[]
    {
        new BlobAttribute("samples-output/path"),
        new StorageAccountAttribute("MyStorageAccount")
    };

    using (var writer = await binder.BindAsync<TextWriter>(attributes))
    {
        writer.Write("Hello World!");
    }
}

次の表に、各バインドの種類の .NET 属性と、それらが定義されているパッケージを示します。

バインド 属性 参照の追加
Azure Cosmos DB Microsoft.Azure.WebJobs.DocumentDBAttribute #r "Microsoft.Azure.WebJobs.Extensions.CosmosDB"
Event Hubs Microsoft.Azure.WebJobs.ServiceBus.EventHubAttribute, Microsoft.Azure.WebJobs.ServiceBusAccountAttribute #r "Microsoft.Azure.Jobs.ServiceBus"
Mobile Apps Microsoft.Azure.WebJobs.MobileTableAttribute #r "Microsoft.Azure.WebJobs.Extensions.MobileApps"
Notification Hubs Microsoft.Azure.WebJobs.NotificationHubAttribute #r "Microsoft.Azure.WebJobs.Extensions.NotificationHubs"
Service Bus Microsoft.Azure.WebJobs.ServiceBusAttribute, Microsoft.Azure.WebJobs.ServiceBusAccountAttribute #r "Microsoft.Azure.WebJobs.ServiceBus"
ストレージ キュー Microsoft.Azure.WebJobs.QueueAttribute, Microsoft.Azure.WebJobs.StorageAccountAttribute
Storage Blob Microsoft.Azure.WebJobs.BlobAttribute, Microsoft.Azure.WebJobs.StorageAccountAttribute
ストレージ テーブル Microsoft.Azure.WebJobs.TableAttribute, Microsoft.Azure.WebJobs.StorageAccountAttribute
Twilio Microsoft.Azure.WebJobs.TwilioSmsAttribute #r "Microsoft.Azure.WebJobs.Extensions.Twilio"

次のステップ