LoginSignup
2
2

More than 1 year has passed since last update.

Azure Functions を Visual Studio 2022で作成してみた

Last updated at Posted at 2022-07-17

Azure Functions とは?

こちらの記事にも書いたように、WebAPIなサービスを簡単に作成することが出来る Microsoft のサーバーレス機能である。

試しにサービスを作ってみる

環境

Windows 10
Visual Studio Community 2022 (64bit) Version 17.2.5
Azureアカウント(従量課金)

プロジェクト作成

  1. 事前準備
    Visual Studio Installer にて、「Azureの開発」をインストールしておく
    image.png

  2. プロジェクトの作成
    テンプレートで、Azure Functionsを選択する。
    image.png

プロジェクトの追加情報は、この記事ではクライアントからのHTTP要求で起動する Http trigger で作る。
image.png

Authorization levelについては、
Function が、事前発行のAPIキーをクライアントからHTTPヘッダに設定して呼び出さないと弾くタイプなので、ここでは認証無しのAnonymousにしておく。

生成されたソースコードは既に実行可能なものになっている。
(プロジェクト作成直後は自動生成されたソースコードに赤線が引かれたりしているので、まずはビルドしておく)

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace FunctionApp1
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "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);
        }
    }
}

デバッグ実行

作成したプロジェクトをデバッグ実行(F5)してみると、コンソールが立ち上がってアクセス先のアドレスが表示される。

image.png

クライアント側のテストツールとして、ここでは VSCodeの拡張機能、REST Clientを使ってみる。
image.png

GETもしくはPOSTの Send Request をクリックすると、以下の応答が帰ってくる。
image.png

機能拡張

応答でJSONを返す

先ほどのPOSTではクライアントからの送信のみJSONだったのを、応答でもJSONを返すようにしてみる。

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace FunctionApp1
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "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.";

            ResponseData response = new ResponseData(name, responseMessage);

            return new OkObjectResult(response);
        }
    }


    class ResponseData
    {
        public string Name { get; }
        public string ResponseMessage { get; }

        public ResponseData(string name, string responseMessage)
        {
            Name = name ?? throw new ArgumentNullException(nameof(name));
            ResponseMessage = responseMessage ?? throw new ArgumentNullException(nameof(responseMessage));
        }
    }
}

返すデータを表現するResponseDataを作って、そこにクライアントから来た name と、これまで応答で返していた文字列を格納し、return の OkObjectResult()の引数に渡すように変更する。

これで、先ほどのテストクライアントから送ってみると、ResponseDataがJSONに変換されていることが分かる。
image.png

応答データを Azure Storage の Blobに保存する

今度は、ResponseDataをクライアントに返すだけでなく、StorageのBlobにも保存してみる。

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Azure.Storage.Blobs;
using System.Text;

namespace FunctionApp1
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            [Blob("myblob", FileAccess.Write)] BlobContainerClient blobContainer,
            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.";

            ResponseData response = new ResponseData(name, responseMessage);

            await blobContainer.CreateIfNotExistsAsync();
            await blobContainer.DeleteBlobIfExistsAsync("Test1Dir/ResponseData.json");
            var store = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(response)));
            await blobContainer.UploadBlobAsync("Test1Dir/ResponseData.json", store);

            return new OkObjectResult(response);
        }
    }


    class ResponseData
    {
        public string Name { get; }
        public string ResponseMessage { get; }

        public ResponseData(string name, string responseMessage)
        {
            Name = name ?? throw new ArgumentNullException(nameof(name));
            ResponseMessage = responseMessage ?? throw new ArgumentNullException(nameof(responseMessage));
        }
    }
}

必要に応じて拡張機能を追加する。
image.png

本関数 Run() の引数にBlobへのアクセスオブジェクトを追加し、

[Blob("myblob", FileAccess.Write)] BlobContainerClient blobContainer,

Blobへの書き込み処理を追加している。

await blobContainer.CreateIfNotExistsAsync();
await blobContainer.DeleteBlobIfExistsAsync("Test1Dir/ResponseData.json");
var store = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(response)));
await blobContainer.UploadBlobAsync("Test1Dir/ResponseData.json", store);

これで、先ほどはクライアントに返していたJSONが本関数に紐づくStorageのBlobにも出力されることになる。

Microsoft Azure Storage Explorer にて
image.png

今はローカルのエミュレータで動作させているので、そのBlob Containersに、
コンテナ名:myblob
ファイルパス:Test1Dir/ResponseData.json
で保存されている。

Azureの本番サーバーに上げてみる

発行

プロジェクト右クリックから「発行」を選択する。
image.png
Azureを選択
image.png
Windowsを選択
image.png
Azure関数を作成
image.png
例)
image.png
これで関数アプリの入れ物となるリソースグループなどがAzure上に作成される。
次に、「発行」ボタンを押して作成したアプリをアップロードする。
image.png

動作確認

Azureのポータルにアクセスして、作成したリソースグループ内の「関数アプリ」を開く。
image.png

さらに「関数」を選択し、作成したアプリ(ここでは「Function1」)を開く。
image.png
「関数のURLの取得」から本関数のURLを取得する。
image.png

上でlocalhostで実行したように、VSCodeのREST Clientで動かしてみる。
image.png
出力
image.png
Azure上のストレージアカウントにもファイルが保存されている。
image.png

追加情報

Visual Studio 2017などの旧開発環境でも開発可能。
ただし、拡張機能で入っている Microsoft.NET.Sdk.Functionsとかをバージョンアップすると動作しなくなるので注意。
また、ストレージエミュレータは最新への更新が必要。(標準インストール版ではエラーが出て動作しなかった)
https://docs.microsoft.com/ja-jp/azure/storage/common/storage-use-emulator
確か、Blob関連の使用クラスも違ったはず。(CloudBlobContainerとか)

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2