- Visual Studio で Azure Functions に HttpTrigger のAPIを作成する
- Visual Studio で Azure Functions に QueueTrigger のAPIを作成する
- Azure Functions を Visual Studio で発行する際に発生したエラーの解決方法
- HttpRequest のQueryとBodyから値を取得する拡張メソッド
- Azure Functions プロジェクトの .gitignore ファイル
- Azure Functions で MeCab.DotNet を使って形態素解析
- Azure Functions で Azure Blob Storage からファイルを取得する
- Azure Functions で Azure Storage への接続情報
- Azure Functions で Azure Key Valut から設定を読み込む
- Azure Functions で Startup クラスを定義して DI を利用する
- Azure Functions で Azure App Configuration から設定を読み込む
- Azure Managed ID を利用する
- Azure Functions で Shared Access Signatures (SAS) を発行する
- Azure Functions で Azure Blob Storage にファイルを保存する
- Azure Functions で Azure Table Storage を操作する
- Azure Functions で Azure Queue Storage を操作する
- Azure Functions で Azure Cosmos DB (Table) を操作する
- Azure Functions で Swagger UI
- Azure Functions で 複数ファイルをアップロードする
- Azure Functions 備忘録
Azure Functions 備忘録
目次
AuthorizationLevel
値 | 説明 |
---|---|
Anonymous | API キーは必要ありません。 |
User | *EasyAuth で使われる予定らしいが未だサポートされていないらしい |
Function | 関数固有の API キーが必要です。 何も指定されなかった場合は、これが既定値になります。 |
System | |
Admin | マスター キーが必要です。 |
リクエストのサイズ制限
HTTP 要求の長さは 100 MB (104,857,600 バイト) に、URL の長さは 4 KB (4,096 バイト) バイトに制限されています。 これらの制限は、ランタイムの Web.config ファイルの httpRuntime 要素で指定されています。
Windows ローカルで実行した場合は 30MB で制限されてしまう不具合があるとかないとか。
Azure Functions で 複数ファイルをアップロードする
目次
検証環境
サーバーサイド
クライアントからは、multipart/form-data 形式で POST してもらう想定。
[FunctionName("Upload")] public async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); // UserAgent を取得するキーは "User-Agent" log.LogInformation(req.Headers["User-Agent"][0]); var form = await req.ReadFormAsync(); foreach (var file in form.Files) { log.LogInformation(file.FileName); } foreach (var kvp in form) { log.LogInformation($"{kvp.Key}({kvp.Value.Count}): {kvp.Value}"); } return new OkObjectResult("OK"); }
クライアント再度
webkitdirectory 属性
webkitdirectory 属性を使用すると、ファイルを選択する代わりにフォルダを選択できるようになる。送信されたファイルのファイル名は相対パス付きのため、ディレクトリのツリー構造の情報も取得できるようになる。
<form action="http://localhost:7071/api/Upload", method="POST", enctype="multipart/form-data"> BaseDir: <input type="text" name=projectId/><br/> Folder: <input type="file" name="files" webkitdirectory multiple/><br/> <input type="submit" value="Submit"/> <input type="reset" value="Reset"/> </form>
サーバーサイドの実行結果。
ファイル名が選択したフォルダを基点とした相対パスになっている。
[2021-02-26T17:46:19.298Z] C# HTTP trigger function processed a request. [2021-02-26T17:46:19.320Z] Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 [2021-02-26T17:46:19.322Z] wallpapers/glanpalace1.jpg [2021-02-26T17:46:19.322Z] wallpapers/photo1/aurora2.jpg [2021-02-26T17:46:19.323Z] wallpapers/photo1/icelandlake2540.jpg [2021-02-26T17:46:19.323Z] basedir/(1): wallpapers [2021-02-26T17:46:19.325Z] Executed 'Upload' (Succeeded, Id=6a51b942-e294-401c-b344-b3395e53f9a5, Duration=140ms)
Postman
Postman では form-data
のファイル選択でフォルダを選択することができない。そのため複数ファイルを選択する場合ツリー構造の情報は除外される。そもそもひとつの Key-Value には同じ階層のファイルしか含めることができない。階層が違うファイルは別のプロパティとして設定する必要がある。
特にツリー構造の情報が必要ない場合はファイルだけを、ツリー構造の情報が必要な場合は別途その情報を設定して送信する。
type
は Text
と File
が選べる。File
は1つでも複数でも選択できるようになっている。
File
の Key-Value は複数定義すると1つの配列にまとめられて送信されるため、階層が違うファイルを選択する場合はそれぞれの階層に応じた Key-Value を増やせば一括で送信できる。
サーバーサイドの実行結果。
[2021-02-26T17:45:20.643Z] C# HTTP trigger function processed a request. [2021-02-26T17:45:20.676Z] PostmanRuntime/7.26.5 [2021-02-26T17:45:20.676Z] glanpalace1.jpg [2021-02-26T17:45:20.677Z] aurora2.jpg [2021-02-26T17:45:20.677Z] icelandlake2540.jpg [2021-02-26T17:45:20.678Z] basedir(1): wallpapers [2021-02-26T17:45:20.679Z] filePaths(3): glanpalace1.jpg,photo1/aurora2.jpg,photo1/icelandlake2540.jpg [2021-02-26T17:45:20.689Z] Executed 'Upload' (Succeeded, Id=5172d86a-1074-40bb-a3d7-f4c793d35157, Duration=265ms)
Azure Functions で Swagger UI
NSwag は NSwag.SwaggerGeneration.AzureFunctionsV2 が更新されておらず、V3ではエラーが出て動かなかったため、Swashbuckle を使用する。
目次
検証環境
- Azure Functions v3
- AzureExtensions.Swashbuckle v3.2.2
古いライブラリに注意
- AzureFunctions.Extensions.Swashbuckle は更新されておらずエラーが出て動かない
実装
NuGet でライブラリをインストールする。
Statup
クラスを追加する。
using AzureFunctions.Extensions.Swashbuckle; ... [assembly: FunctionsStartup(typeof(Startup))] namespace FunctionApp1 { public class Startup : FunctionsStartup { public override void Configure(IFunctionsHostBuilder builder) { builder.AddSwashBuckle(Assembly.GetExecutingAssembly()); } } }
Open API と Swagger UI の Functions を追加する。
public static class SwaggerFunctions { [SwaggerIgnore] [FunctionName("Swagger")] public static Task<HttpResponseMessage> Run( [HttpTrigger(AuthorizationLevel.Function, "get", Route = "Swagger/json")] HttpRequestMessage req, [SwashBuckleClient] ISwashBuckleClient swashBuckleClient) { return Task.FromResult(swashBuckleClient.CreateSwaggerDocumentResponse(req)); } [SwaggerIgnore] [FunctionName("SwaggerUi")] public static Task<HttpResponseMessage> Run2( [HttpTrigger(AuthorizationLevel.Function, "get", Route = "Swagger/ui")] HttpRequestMessage req, [SwashBuckleClient] ISwashBuckleClient swashBuckleClient) { return Task.FromResult(swashBuckleClient.CreateSwaggerUIResponse(req, "swagger/json")); } }
対象の Functions に属性をつける。
public class Function1 { [QueryStringParameter("name", "User Name", DataType = typeof(string), Required = false)] [ProducesResponseType(typeof(string), (int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.InternalServerError, Type = typeof(Error))] [FunctionName("Function1")] public async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, 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; string responseMessage = string.IsNullOrEmpty(name) ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response." : $"Hello, {name}. This HTTP triggered function executed successfully."; return new OkObjectResult(responseMessage); } } public class Error { public string Title { get; set; } public string Description { get; set; } }
http://localhost:7071/api/Swagger/ui
で Swagger UI にアクセス。
参考
ASP.NET Core の場合に参考になりそうな記事。
Azure API Management
API Management (APIM) は、既存のバックエンドのサービスに対して一貫性のある最新の API ゲートウェイを迅速に作成する手段です。
API Management が組織にもたらす利点は、外部のパートナーや社内の開発者に API を公開することによって、社内に眠っているデータやサービスの可能性を発掘できることです。 どの企業も、その業務をデジタル プラットフォームで拡大し、新しい販路と顧客を開拓すると共に、既存の顧客との絆を深めようと模索しています。 API Management は、開発者の取り組み、ビジネス インサイト、分析、セキュリティ、保護を通じて API プログラムの価値を高め、企業にコア コンピテンシーをもたらします。 Azure API Management を任意のバックエンドで実行し、それに基づいて本格的な API プログラムを起動できます。
Azure Functions で Azure Cosmos DB (Table) を操作する
目次
検証環境
- Azure Functions v3
- Microsoft.Azure.Cosmos.Table v1.0.8
古いライブラリに注意
- WindowsAzure.Storage は非推奨
- Microsoft.Azure.CosmosDB.Table はまもなく非推奨
実装
NuGet でライブラリをインストールする。
using Microsoft.Azure.Cosmos.Table;
データ定義は、TableEntity
を継承したクラスを作成する。
取得時にパラメータなしのコンストラクタが必要になる。
public class CustomerEntity : TableEntity { public CustomerEntity() { } public CustomerEntity(string lastName, string firstName) { PartitionKey = lastName; RowKey = firstName; } public string Email { get; set; } public string PhoneNumber { get; set; } }
CloudTable
のインスタンスを取得する。
var connectionString = "ConnectionString"; var tableName = "TableA"; var storageAccount = CloudStorageAccount.Parse(connectionString); var tableClient = storageAccount.CreateCloudTableClient(); var cloudTalbe = tableClient.GetTableReference(tableName);
テーブル作成
// なければ作成する await table.CreateIfNotExistsAsync(IndexingMode.Consistent, throughput: 400, null, CancellationToken.None);
プロビジョニングされたスループットの場合、throughput
を指定せずに作成すると 800 で作成されてしまうので注意。最低コストの2倍発生する。
IndexingMode
と defaultTimeToLive
はこの指定で手動で作成した時のデフォルト値と同じになる。
テーブルに設定されたスループットは、ポータル上の下図から確認できる。
挿入
1件挿入する場合。
var entity = new CustomerEntity("Tanaka", "Taro") { Email = "aaa", PhoneNumber = "001" }; await cloudTalbe.ExecuteAsync(TableOperation.InsertOrReplace(entity));
まとめて挿入する場合。
var entities = new[] { new CustomerEntity("Tanaka", "Taro"){ Email = "aaa", PhoneNumber = "001"}, new CustomerEntity("Tanaka", "Jiro"){ Email = "bbb", PhoneNumber = "002"}, }; var operation = new TableBatchOperation(); foreach (var entity in entities) { operation.Add(TableOperation.InsertOrReplace(entity)); } await cloudTalbe.ExecuteBatchAsync(operation);
取得
PartitionKeyとRowKeyを指定して1件取得する場合。
var entity = new CustomerEntity("Tanaka", "Taro") { Email = "aaa", PhoneNumber = "001" }; var tableResult = await cloudTalbe.ExecuteAsync(TableOperation.Retrieve<CustomerEntity>(entity.PartitionKey, entity.RowKey)); var result = tableResult.Result as CustomerEntity;
クエリを使う場合。
var entity = new CustomerEntity("Tanaka", "Taro") { Email = "aaa", PhoneNumber = "001" }; var query = new TableQuery<CustomerEntity>(); query.FilterString = TableQuery.CombineFilters( TableQuery.GenerateFilterCondition(nameof(CustomerEntity.PartitionKey), QueryComparisons.Equal, entity.PartitionKey), TableOperators.And, TableQuery.GenerateFilterCondition(nameof(CustomerEntity.RowKey), QueryComparisons.Equal, entity.RowKey)); var tableResult = await cloudTalbe.ExecuteQuerySegmentedAsync(query, null); var results = tableResult.Results;
ソートしたい場合。
var where = TableQuery.GenerateFilterCondition(nameof(CustomerEntity.PartitionKey), QueryComparisons.Equal, entity.PartitionKey); var query = new TableQuery<CustomerEntity>() .Where(where) .Order(nameof(CustomerEntity.Timestamp)); var tableResult = await cloudTalbe.ExecuteQuerySegmentedAsync(query, null);
cloudTalbe.CreateQuery<CustomerEntity>()
を使おうとすると NotSupportedException
が発生するので注意*1
削除
取得時の Entity が書き換わってないかチェックして削除する場合。
await cloudTalbe.ExecuteAsync(TableOperation.Delete(entity));
気にせず削除する場合は ETag にワイルドカードを使う。
var entity = new CustomerEntity("Tanaka", "Taro"); entity.ETag = "*"; await cloudTalbe.ExecuteAsync(TableOperation.Delete(entity));
参考
- .NET Standard SDK を使用した Azure Cosmos DB Table API | Microsoft Docs
- Azure Cosmos DB の Table API についてよく寄せられる質問 | Microsoft Docs
- Azure Cosmos DB Emulator を使用したローカルでのインストールと開発 | Microsoft Docs
- Azure Cosmos DB入門(7) - ryuichi111stdの技術日記
- Azure Cosmos DB入門(目次) - ryuichi111stdの技術日記
- Azure Cosmos DB の課金内容の理解 | Microsoft Docs
- Azure Cosmos DB の無償枠 (Free Tier) の注意点 - Qiita
関連記事
- Azure Functions で Azure Table Storage を操作する
- Azure Functions で Azure Queue Storage を操作する
- Azure Functions で Azure Blob Storage にファイルを保存する
- Azure Functions で Azure Blob Storage からファイルを取得する
- Azure Functions で Azure Storage への接続情報
- Azure Functions で Azure Key Valut から設定を読み込む
- Azure Functions で Startup クラスを定義して DI を利用する
- Azure Managed ID を利用する
Azure Functions で Azure Queue Storage を操作する
目次
検証環境
- Azure Functions v3
- Azure.Storage.Queues v12.6.0
実装
NuGet でライブラリをインストールする。
using Azure.Storage.Queues; using Azure.Storage.Queues.Models;
キューの作成
var connectionString = "ConnectionString"; var queueName = "QueueName”; var queueClient = new QueueClient(connectionString, queueName); await queueClient.CreateAsync();
メッセージの追加
await queueClient.SendMessageAsync("First"); await queueClient.SendMessageAsync("Second"); // 最近はBinaryも追加できるらしい var binary = new BinaryData(new byte[0]); await queueClient.SendMessageAsync(binary);
メッセージの表示
Azure.Response
でラップされてるので Value
プロパティを参照する。
var message = await queueClient.PeekMessageAsync(); log.LogInformation(message.Value.MessageId + ":" + message.Value.MessageText); var messages = await queueClient.PeekMessagesAsync(maxMessages:5); foreach (var msg in messages.Value) { log.LogInformation(msg.MessageId + ":" + msg.MessageText); }
メッセージの更新
キューは積み直しになる。
ReceiveMessageAsync
ではなく SendMessageAsync
の戻り値を使って更新しても同じ。
var receipt = await queueClient.ReceiveMessageAsync();
await queueClient.UpdateMessageAsync(receipt.Value.MessageId, receipt.Value.PopReceipt, "Updated");
メッセージの受信
受信するとキューからは削除される。
Azure.Response
でラップされてるので Value
プロパティを参照する。
var message = await queueClient.ReceiveMessageAsync();
log.LogInformation(message.Value.MessageId + ":" + message.Value.MessageText);
複数件受信する場合。
var messages = await queueClient.ReceiveMessagesAsync(maxMessages: 5); foreach (var msg in messages.Value) { log.LogInformation(msg.MessageId + ":" + msg.MessageText); }
メッセージの削除
ReceiveMessageAsync
で消えてしまうので、PeekedMessage
で PopReceipt
が取れないので使いみちあるのか謎。
SendMessageAsync
時に取り消すくらいには使えるかもしれない。
var message = await queueClient.ReceiveMessageAsync(); await queueClient.DeleteMessageAsync(message.Value.MessageId, message.Value.PopReceipt);
キューの削除
// キューが存在しない場合は例外発生 await queueClient.DeleteAsync(); // キューが存在しない場合に例外が出ない await queueClient.DeleteIfExistsAsync();
その他
メッセージのエンコード
Azure Functions のキュートリガーが文字列を受け取る場合、Base64 でエンコードされた値が想定されている。エンコードされていない値だと例外が発生する。 そのためキューに追加する時に、Base64 でエンコードした文字列を設定する必要がある。
SDK を使って文字列を追加する場合、SDK の v12 と v11 以前では動作が異なるので注意が必要。 v11 以前では自動的にエンコードされていたが、v12 ではエンコードされなくなったため明示的にエンコードする。
関連記事
- Azure Functions で Azure Cosmos DB (Table) を操作する
- Azure Functions で Azure Table Storage を操作する
- Azure Functions で Azure Blob Storage にファイルを保存する
- Azure Functions で Azure Blob Storage からファイルを取得する
- Azure Functions で Azure Storage への接続情報
- Azure Functions で Azure Key Valut から設定を読み込む
- Azure Functions で Startup クラスを定義して DI を利用する
- Azure Managed ID を利用する