🎼

Azure SQL Database をバックエンドにした自前の Web API を作るまで

2021/08/29に公開

Azure で Web API を実装する方法について、ありもののチュートリアル以上のことをしたかったので自分でお題を作ってやってみました。

お題は「自分のブログのエントリを DB にエクスポートしておき、Web API 経由で取得する」という感じです。

環境

手順

  1. 元ネタから CSV ファイルを生成
  2. CSV ファイルから Azure SQL Database へインポート
  3. Web API プロジェクトの作成
  4. DB 連携の実装 (Entity Framework Scaffolding)

1. 元ネタから CSV ファイルを生成

一行目に列名、二行目以降にデータが格納されている CSV ファイルを用意します。今回の整形は、下記のようなスクリプトで実施しました。

2. CSV ファイルから Azure SQL Database へインポート

まず、Azure SQL Database を作成します。

この段階で、接続文字列を控えておきます。後ほどプログラム中で利用します。

次に、SSMS を使用して先ほど作成した CSV ファイルをテーブルにインポートします。

3. Web API プロジェクトの作成

Visual Studio にて、Web API プロジェクトを作成します。

  1. [ファイル] メニューで、 [新規作成] > [プロジェクト] の順に選択
  2. [ASP.NET Core Web API] テンプレートを選択し、 [次へ] をクリック
  3. プロジェクトに名前を付け、 [作成] をクリック
  4. ターゲット フレームワークにて [.NET 5.0] を選択し、「OpenAPI サポートを有効にする」にチェックが入っていることを確認し、[作成] をクリック

参考 : チュートリアル: ASP.NET Core で Web API を作成する | Microsoft Docs

4. DB 連携の実装 (Entity Framework Scaffolding)

NuGet パッケージのインストール

まず、NuGet パッケージの管理などから、プロジェクトに下記の NuGet パッケージをインストールします。

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.EntityFrameworkCore.Design

Scaffolding

Visual Studio から PowerShell コンソールを起動し、下記のコマンドを実行します。

cd <プロジェクトフォルダ名>
dotnet ef dbcontext scaffold "<接続文字列>" Microsoft.EntityFrameworkCore.SqlServer -o Models

時々エラーが出ることがありますが、その際は [ビルド] メニューからソリューションのリビルドを実行すると解消されることが多いです。

無事に実行が完了すると、Models フォルダにテーブル名のクラスと接続コンテキストのクラスが作成されます。このうち、接続コンテキストのクラス名をコピーしておきます。

Controller ページの作成

ソリューションエクスプローラーにてプロジェクトを右クリックし、[追加] > [新規スキャフォールディング アイテムの追加] の順にクリックします。

「Entity Framework を使用したアクションがある API コントローラー」を選択し、「モデル クラス」にスキャフォールディングで作成されたテーブル名のクラスを、「データ コンテキスト クラス」に同じく作成された接続コンテキストのクラスを選択し、[追加] をクリックします。

ここでも時々エラーが出ることがありますが、その際は [ビルド] メニューからソリューションのリビルドを実行すると解消されることが多いです。

無事に実行が完了すると、上記「コントローラー名」で指定した名前のクラスが作成されます。個人的には、Controllers フォルダに移動した方が分かりやすいかと思います。

DB 接続に必要なコードの追記

この段階では、まだ実行して Web API を叩いても 500 エラーが発生します(後述の [参考] を参照)。

Startup.cs に下記のコードを追記し、接続コンテキストが追加されるように実装します。

  1. 冒頭の using 句のブロックに、作成した Models フォルダへの参照を追記
using System.<プロジェクト名>.Models
  1. ConfigureServices メソッドの中 (36行目あたり) に、DB 接続コンテキストを追加するように追記
public void ConfigureServices(IServiceCollection services)
{

services.AddControllers();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "MyBlogWebApi", Version = "v1" });
    });

    // ★下記に追記
    services.AddDbContext<ndsoututopoc1sqlsrvContext>();
}

動作確認

実行すると、ブラウザにて Swagger の画面が起動するので、テストしたい使い方をクリックして展開し、[Try it out] をクリックし必要に応じて条件を入れて [Execute] にて実行してみましょう。

こんな感じで、無事 DB から読み込んだデータを返してくれていれば、成功です🤗

参考 : DB 接続コンテキストの実装が無い時のエラー

「DB 接続に必要なコードの追記」での実装が抜けている場合、サーバー側で下記のようなエラーが発生します。

System.InvalidOperationException: Unable to resolve service for type 'MyBlogWebApi.Models.ndsoututopoc1sqlsrvContext' while attempting to activate 'MyBlogWebApi.BlogsController'.
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
   at lambda_method9(Closure , IServiceProvider , Object[] )
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass4_0.<CreateActivator>b__0(ControllerContext controllerContext)
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

最初、このエラーに悩まされたのですが、下記の StackOverflow の記事を見つけて解決 (納得) しました。そのあたりの追記まで自動でやってくれるのかと思い込んでいました…

終わりに

今回はここまでです。「Azure SQL Database をバックエンドとして Web API を作ってみたい!」といった方の参考になればと思います。

今後は、これらの資材を使って CI/CD なんかも実践してみようと思っています。

Discussion