Azure Functions と Blob Storage を連携させたファイルアップロード機能の実装

はじめに

サーバーレスアーキテクチャ(Serverless)は、インフラの管理を意識せずにコードを実行できる強力なソリューションです。Azure におけるサーバーレスの代表格である Azure Functions と、スケーラブルなストレージサービスである Azure Blob Storage を組み合わせることで、効率的なファイル処理パイプラインを構築できます。

本記事では、外部URLから画像を取得し、Azure Blob Storage へ保存する機能を Azure Functions で実装する手順を解説します。

Azure リソースの準備

実装の前に、Azure ポータルで必要なリソースを作成します。

1. Function App の作成

  • リソースグループ: 任意の名前(例:func-storage-rg)
  • 関数アプリ名: 一意の名前(例:img-processor-func)
  • 公開: コード
  • ランタイムスタック: .NET
  • バージョン: 6 以上の LTS 推奨
  • 地域: East Asia など
  • プラン: 従量課金(サーバーレス)

2. ストレージコンテナの作成

Function App に紐付けたストレージアカウント、または新規作成したアカウント内に、ファイルを保存するためのコンテナを作成します。

  • コンテナ名: web-images
  • パブリックアクセスレベル: 私的(匿名アクセスなし)

プロジェクトの実装

必要な NuGet パッケージの導入

Azure Functions で依存関係注入(DI)と Blob 操作を行うため、以下のパッケージをインストールします。

dotnet add package Azure.Storage.Blobs
dotnet add package Microsoft.Azure.Functions.Extensions
dotnet add package Microsoft.Extensions.DependencyInjection

サービスレイヤーの実装

Blob Storage への操作を抽象化するためのインターフェースとクラスを定義します。

public interface IImageStorageService
{
    Task SaveImageStreamAsync(string sourceUrl, string targetName);
    Task SaveContentAsync(string data, string fileName);
}

public class BlobStorageService : IImageStorageService
{
    private readonly BlobServiceClient _client;
    private const string ContainerName = "web-images";

    public BlobStorageService(BlobServiceClient client)
    {
        _client = client;
    }

    public async Task SaveImageStreamAsync(string sourceUrl, string targetName)
    {
        var container = _client.GetBlobContainerClient(ContainerName);
        var blob = container.GetBlobClient(targetName);

        using var httpClient = new HttpClient();
        var stream = await httpClient.GetStreamAsync(sourceUrl);

        await blob.UploadAsync(stream, new BlobHttpHeaders { ContentType = "image/jpeg" });
    }

    public async Task SaveContentAsync(string data, string fileName)
    {
        var container = _client.GetBlobContainerClient(ContainerName);
        var blob = container.GetBlobClient(fileName);
        
        using var ms = new MemoryStream(Encoding.UTF8.GetBytes(data));
        await blob.UploadAsync(ms, new BlobHttpHeaders { ContentType = "text/plain" });
    }
}

HTTP トリガーの実装

HTTP リクエストを受け取り、サービスを呼び出す関数を作成します。

public class UploadEndpoint
{
    private readonly IImageStorageService _storageService;

    public UploadEndpoint(IImageStorageService storageService)
    {
        _storageService = storageService;
    }

    [FunctionName("UploadImageFromUrl")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        string jsonBody = await new StreamReader(req.Body).ReadToEndAsync();
        var data = JsonConvert.DeserializeObject<UploadRequest>(jsonBody);

        if (string.IsNullOrEmpty(data?.Url) || string.IsNullOrEmpty(data?.FileName))
        {
            return new BadRequestObjectResult("Invalid parameters.");
        }

        await _storageService.SaveImageStreamAsync(data.Url, data.FileName);
        
        return new OkObjectResult(new { message = "Successfully uploaded." });
    }
}

public class UploadRequest
{
    public string Url { get; set; }
    public string FileName { get; set; }
}

依存関係注入の設定 (Startup)

FunctionsStartup を使用して、BlobServiceClient と独自サービスをコンテナに登録します。

[assembly: FunctionsStartup(typeof(MyFunctionApp.Startup))]

namespace MyFunctionApp
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            var connectionString = Environment.GetEnvironmentVariable("AzureWebJobsStorage");
            builder.Services.AddSingleton(x => new BlobServiceClient(connectionString));
            builder.Services.AddTransient<IImageStorageService, BlobStorageService>();
        }
    }
}

動作確認

ローカル環境またはデプロイ後に Postman などのツールを使用してテストを行います。

  1. エンドポイントに対して POST リクエストを送信します。
  2. リクエストボディに以下の JSON を含めます。
{
    "Url": "https://example.com/sample-image.jpg",
    "FileName": "stored-image.jpg"
}

実行後、Azure ポータルのストレージコンテナを確認し、指定したファイル名で画像が保存されていれば成功です。

まとめ

Azure Functions を使用することで、ファイルアップロードや画像処理といった特定のタスクを軽量なコードで実装できます。従量課金モデルを利用すれば、実行時間分のみのコストで運用できるため、バッチ処理や API 連携に非常に適しています。

タグ: Azure Functions Azure Blob Storage .NET Serverless Dependency Injection

10月25日 11:49 投稿