Azure Functions 内に含まれるファイルを .NET から読み込む検証をやってみた

Azure Functions の環境変数に外出しでも良いのですが、情報量が多い場合プログラム本体とは別ファイルにしておきたくなります。そこで今回は、Azure Functions 内に含まれるファイルを .NET から読み込む検証をやってみました。

## 検証用 Azure Functions を作成

```bash:bash
func init test --dotnet

cd test

func new --name test --template HttpTrigger --authlevel anonymous

func start
```

## Azure Functions にテキストファイルを含める

```bash:bash
echo sometext > test.txt

code test.csproj
```

```xml:変更前の test.csproj
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.1" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>
```

```xml:変更後の test.csproj
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.1" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
    <None Update="test.txt">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>
```

## ファイルが含まれる事を確認

```bash:bash
func start

cat bin/output/test.txt
```

## Azure Functions コードを変更

```cs:変更前の test.cs
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 test
{
    public static class test
    {
        [FunctionName("test")]
        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);
        }
    }
}
```

```cs:変更後の test.cs
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 test
{
    public static class test
    {
        [FunctionName("test")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log, ExecutionContext context)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string test = File.ReadAllTextAsync(Path.Combine(context.FunctionAppDirectory, "test.txt")).Result;
            string responseMessage = $"test\n{test}";

            return new OkObjectResult(responseMessage);
        }
    }
}
```

## ローカルで動作確認

```bash:bash
func start
```

## Azure に検証環境を構築

```bash:bash
prefix=mnrdn
region=japaneast

az group create \
  --name ${prefix}-rg \
  --location $region

az storage account create \
  --name ${prefix}stor \
  --resource-group ${prefix}-rg \
  --sku Standard_LRS

az functionapp create \
  --name ${prefix} \
  --resource-group ${prefix}-rg \
  --consumption-plan-location $region \
  --runtime dotnet \
  --runtime-version 6 \
  --functions-version 4 \
  --storage-account ${prefix}stor \
  --disable-app-insights \
  --https-only \
  --os-type Linux

func azure functionapp publish ${prefix}
```

## Azure で動作検証

```bash:bash
curl https://${prefix}.azurewebsites.net/api/test
```

## 後片付け

```bash:bash
az group delete \
  --name ${prefix}-rg \
  --yes
```

## 参考

https://github.com/Azure/azure-functions-host/wiki/Retrieving-information-about-the-currently-running-function