Visual Studio 2017によるAzure Functionsの開発

## Visual Studio 2017 の Functions 対応
Visual Studio 2017では、バージョン15.3よりようやくAzure Functions の開発に対応しました。
今回はその導入方法と開発の流れを簡単にまとめます。

## 準備
### Visual Studio 2017（15.3以降）をインストール
エディションはどれでも構いません（今回はCommunityエディションを使いました）。
インストール方法は割愛しますが、Azureと連携するので「Azureの開発」ワークロードを選択することが必須となります。
（あとからでもVisual Studio Installerの「変更」から追加可能です）

15.3以降では、Azure Functionsのテンプレートが選べるようになる…と思ったのですが、個別にアップデートが必要でした。

![個別にアップデート](https://qiita-image-store.s3.amazonaws.com/0/194664/1ef38a02-6de0-8d22-c275-55671b700429.png)

そうすると、無事にFunctionsのテンプレートが選べるようになりました。

## 開発
### コードを書く
今回はC#でコードを書いていきます。
Azure FunctionsでC#を使う場合、いままでは「.csx」という拡張子のスクリプトでプログラムを書いていましたが、Visual Studio上でFunctionsの関数を作成することで、通常の「.cs」を使うことができ、普段のC#開発の感覚で関数をつくることができます。
※Azureのポータルから関数を作成した際は、「run.csx」の編集画面になるようです。
※C#スクリプト「.csx」の仕組みについては下記のドキュメントを参照
[Azure Functions C# スクリプト開発者向けリファレンス](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference-csharp)

まずはVisual Studio 2017より、Azure Functionsのプロジェクトを作成します。
メニューからファイル→新規作成→プロジェクトと選択し、Visual C#のCloudを選択すると「Azure Functions」が出てくるので、これを選択してプロジェクトを作成します。

![Azure Functionsを選択](https://qiita-image-store.s3.amazonaws.com/0/194664/6d480e59-438d-491d-90ff-7a87c9a7c2e7.png)

プロジェクトが出来上がったら、Functionsの処理を記述するためのcsファイルを作成します。
プロジェクトを右クリックし、追加→新しい項目と選択し、「Azure Functions」を選びます。

![csファイル作成](https://qiita-image-store.s3.amazonaws.com/0/194664/69894918-e9b2-7e30-a3a5-4961c83baf00.png)

今回はWebhookの関数を作るので、「Generic Webhook」を選択します。
![webhook作成](https://qiita-image-store.s3.amazonaws.com/0/194664/90fef204-5ff5-8878-a7d9-6fb537232db3.png)

すると、以下のようなコードが書かれたファイルが作られます。

```c#:Function1.cs
using System.Net;
using Newtonsoft.Json;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

namespace FunctionApp1
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<object> Run([HttpTrigger(WebHookType = "genericJson")]HttpRequestMessage req, TraceWriter log)
        {
            log.Info($"Webhook was triggered!");

            string jsonContent = await req.Content.ReadAsStringAsync();
            dynamic data = JsonConvert.DeserializeObject(jsonContent);

            if (data.first == null || data.last == null)
            {
                return req.CreateResponse(HttpStatusCode.BadRequest, new
                {
                    error = "Please pass first/last properties in the input object"
                });
            }

            return req.CreateResponse(HttpStatusCode.OK, new
            {
                greeting = $"Hello {data.first} {data.last}!"
            });
        }
    }
}
```
Webhookでよく使う、JSONのライブラリなどが最初からusingに書かれていて、いい感じです。
パッケージ自体もSDKに最初から含まれています。このあたり、「.csx」をAzure上で書く方法をとると結構面倒なので、このようなお膳立てをしてくれるのはとてもうれしいです。

この最初に生成されたコードは、「first」「last」というキーのデータ（ファーストネームとラストネームのことでしょう）をもつJSONを受け取って、その名前に挨拶する文字列を含むレスポンスを返す、という関数になっています。
JSONをdynamicで受け取ってそれを処理する、という処理はそのまま流用できそうなので、参考になりますね。
その他async/awaitなどを見ても、C#らしく簡潔なコードとなっていて、これによってもAzure Functionsの手軽さが際立ちます。

### ローカルでデバッグする
では、このコードをローカルで実行・デバッグしてみたいと思います。
これも通常のVisual Studioでの開発と同じく、実行（デバッグの開始）ボタンを押すだけ。
<img alt="ローカルで実行" src="https://qiita-image-store.s3.amazonaws.com/0/194664/d58c2313-8166-3efb-fb31-34914047c1bf.png" width="80%">

これを押すと、以下のようなコンソール画面が立ち上がり、ローカルで起動した関数のURLが表示されます。
![コンソール](https://qiita-image-store.s3.amazonaws.com/0/194664/167062f0-cb7a-62f4-625c-14e05c1272ba.png)


このURLに対してJSONを投げると、レスポンスが返ってくることになります。
PowerShellを使って、コマンドでリクエストを投げてみます。

```ps1
$data = @{
    first='Jane'
    last='Doe'
}
$json = $data | ConvertTo-Json
Invoke-RestMethod 'http://localhost:7071/api/Function1' -Method POST -Body $json -ContentType 'application/json'
```

実行結果はこのようになりました。
![実行結果](https://qiita-image-store.s3.amazonaws.com/0/194664/99257ece-6045-52c2-8ef0-8aeaff030448.png)

無事、「Hello Jane Doe!」とあいさつしてくれました！
このように、ローカルでも手軽に関数の動作確認を行うことができます。
（ローカルでの実行なので当然、ブレークポイントをつけてデバッグすることなどもできます）


### Azureへのデプロイ
ローカルでの動作確認ができたら、いよいよAzureにデプロイです。
プロジェクトのコンテキストメニューに「発行」があるので、それをクリックします。

<img alt="Azureへの発行1" src="https://qiita-image-store.s3.amazonaws.com/0/194664/571fb1a7-5ad1-7912-e629-72cddab3d5db.png" width="80%">


「Azure 関数アプリ」を選択し、AzureにFunction Appを新規作成するか既存のものを使うかを選び「発行」をクリックします。今回は、新規作成を選択します。

<img alt="Azureへの発行2" src="https://qiita-image-store.s3.amazonaws.com/0/194664/5c5999de-31e5-05f0-b9f7-27fa1d18681a.png" width="80%">

各情報を入力・選択（必要に応じて新規作成）をし、「作成」をクリックします。
<img alt="Azureへの発行3" src="https://qiita-image-store.s3.amazonaws.com/0/194664/5809dcda-f081-1618-3dfc-2b78ccaf5c22.png" width="80%">

今回試したときは一度「発行が失敗しました」というエラーが出てしまいましたが、再度「発行」を押したら無事成功しました。
<img alt="発行成功" src="https://qiita-image-store.s3.amazonaws.com/0/194664/c6aafe4c-767d-82a6-d7ca-b8db1ff12a07.png" width="80%">

### Azure上の関数の実行
デプロイできたら、実行してみます。
まずは、Azure上の関数のURLを取得するため、管理ポータルを開きます。
Visual Studioのサーバーエクスプローラーから、さきほどデプロイした関数を探し、右クリック→「管理ポータルで開く」をクリックします。
<img alt="管理ポータルで開く" src="https://qiita-image-store.s3.amazonaws.com/0/194664/2f70dab1-c0af-513c-9dd2-5ba006fe21fd.png" width="80%">

するとブラウザが起動し、ポータルでデプロイした関数が開かれるので、Function1をクリックし、「関数URLの取得」をクリックします。
![URL取得](https://qiita-image-store.s3.amazonaws.com/0/194664/82112f72-0498-da2c-6f37-416ed1800491.png)

すると、リクエストを投げる先のURLが表示される（キー情報などを含んだURLになっています）ので、これをコピーして、ローカルでの確認時と同じようにPowerShellでリクエストを投げてみます。

![Azureでの実行](https://qiita-image-store.s3.amazonaws.com/0/194664/6a78e82d-6405-ee37-84bb-9da5d51189f4.png)

無事、あいさつしてくれました！

### Azure上の関数のリモートデバッグ
Azure上の関数にアタッチしてのリモートデバッグもできます。
リモートデバッグをするには、Visual Studio側の設定で「マイコードのみ」の設定を無効にしておく必要があります。

メニューの「デバッグ」→「オプション」より、以下の「マイコードのみを有効にする」のチェックを外します。

<img alt="マイコードのみを無効" src="https://qiita-image-store.s3.amazonaws.com/0/194664/9a3c0499-fa5b-0531-d04a-2769bbb70588.png" width="80%">

この状態で、サーバーエクスプローラーの関数を右クリックし、「デバッガーのアタッチ」をクリックします。
<img alt="デバッガーのアタッチ" src="https://qiita-image-store.s3.amazonaws.com/0/194664/4ebf3ba8-bb48-b660-f03e-d622c75c43ec.png" width="80%">

すると、（アタッチに多少時間がかかりますが）ブレークポイントがヒットするようになり、ステップ実行できるようになります。変数の中身などもちゃんと見ることができます。
<img alt="ブレークポイント" src="https://qiita-image-store.s3.amazonaws.com/0/194664/95002797-19a4-2233-85fc-40dc4d4c0447.png" width="80%">

実際にWebサービスを連携させたあとに、うまく値が渡っているかなど確認するのに便利そうです。

## まとめ
Visual Studio 2017でのAzure Functions開発は、作成からデプロイ、実行確認までトータルにサポートされているうえ、慣れ親しんだC#の開発と同じ感覚でできる点が非常に快適です。