【Docker】ASP.NET MVC Core+SQLServer(MSSQL)で画面表示

前回SQLSERVERを使って画面上にデータの中身を表示する事ができました。このデータをそのままDockerに持って行った場合、docker環境を構築するために必要なdocker-compose.ymlは以下のようになっています。

docker-compose.yml

version: '3.4'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      ConnectionStrings__DefaultConnection: "Server=sqlexpress;Database=master;User ID=sa;Password=P@ssw0rd;initial catalog=dotnetcorewebsample;MultipleActiveResultSets=True;App=EntityFramework;"
    expose:
      - 5000
    depends_on:
      - sqlexpress

  sqlexpress:
    build:
      context: ./docker/sqlexpress
      dockerfile: Dockerfile
    environment:
      MSSQL_PID: "Express"
      ACCEPT_EULA: "Y"
      SA_PASSWORD: "P@ssw0rd"
      MSSQL_AGENT_ENABLED: "true"
    ports:
      - 1433:1433

  web:
    build:
      context: ./docker/nginx
    environment:
      BACKEND_HOST: "app:5000"
    ports:
      - 80:80

ここに書いてある、ConnectionStrings__DefaultConnectiongがDocker上に作るSQLServerの接続文字列なのでこの文字列をappsettings.jsonの”Dbcontext”に上書きします。

{
  "ConnectionStrings": {
    "DbContext": "Server=sqlexpress;Database=master;User ID=sa;Password=P@ssw0rd;initial catalog=dotnetcorewebsample;MultipleActiveResultSets=True;App=EntityFramework;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

ここまで用意できたらいつものように docker-compose up –build(-は二つ)を打てばDocker環境が構築されます。・・・されるのですが実行後、Webを起動したら下記のような画面が表示されました。

An error occurred while processing your request.

Development Mode

Swapping to Development environment will display more detailed information about the error that occurred.

The Development environment shouldn’t be enabled for deployed applications. It can result in displaying sensitive information from exceptions to end users. For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development and restarting the app.

レイヤ部分(Aspnet_test2、 Home、Privacy)部分は見えてるのに中の部分がエラーでこのエラーは直訳すると、本番モードになっていないから動きません。という内容に見えます。

なので最初にこの権限周りを見直してみますが launchSettings.json は別におかしくない・・・。では次にDockerログをチェックしてみました。すると以下の表示が出ていました。

Login failed for user ‘sa’. Reason: Failed to open the explicitly specified database

2021-08-01 07:21:21.83 Logon       Error: 18456, Severity: 14, State: 38.
2021-08-01 07:21:21.83 Logon       Login failed for user 'sa'. Reason: Failed to open the explicitly specified database 'dotnetcorewebsample'. [CLIENT: 172.20.0.4]
app_1         | fail: Microsoft.EntityFrameworkCore.Database.Connection[20004]
app_1         |       An error occurred using the connection to database 'dotnetcorewebsample' on server 'sqlexpress'.
app_1         | fail: Microsoft.EntityFrameworkCore.Query[10100]
app_1         |       An exception occurred while iterating over the results of a query for context type 'Aspnet_test2.Models.ApplicationDbContext'.
app_1         |       Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot open database "dotnetcorewebsample" requested by the login. The login failed.
app_1         |       Login failed for user 'sa'.

内容をチェックするとsaのユーザログインに失敗している模様。最初はこの database ‘dotnetcorewebsample’ を深く気にせず、下記2点を疑っていました。

  • Railsの時のようにdocker-compose.ymlにVolumesを入れていないから?
  • 単純にDBの作成がうまくいってないのか?

色々考えてまずはSSMSからDockerで作成したSQLSERVERにログインできないか試みてみました。

SSMSでDocker環境のSQLSERVERにアクセスするには?

上のdocker-compose.yml を見たらSQLSERVERのポートは1433で作られていて、パスワードはP@ssw0rdであることがわかります。自分のサーバなのでlocalhostのポート1433を指定すればいいわけです。

ただし、ローカルで接続した時のようなWindows認証ではなく、きちんとSQL Server認証にてログインしないと行けないので気を付けましょう。

  • サーバ名:localhost, 1433
  • 認証:SQL Server認証
  • ログイン:sa
  • パスワード:P@ssw0rd(docker-compose.ymlの設定)

これで無事ログインできたので、実はappsettings.jsonの接続文字列もServer=sqlexpressでなく、 Server=localhost,1433 または Server=localhost;1433 なのでは? と思って、やってみたのですがやはりうまくいきませんでした。

でもSSMSでログインしてみるとmasterというデータベースというものがあるのはわかりました。でもエラーメッセージを見ると dotnetcorewebsample というデータベースが存在しないからログインできない。という内容に見えます。

Database と initial catalog の関係とは?

最初の例だったdockercompose.ymlの接続文字列は“Server=sqlexpress;Database=master;User ID=sa;Password=P@ssw0rd;initial catalog=dotnetcorewebsample;MultipleActiveResultSets=True;App=EntityFramework;”

でした。Databaseには master が指定されているのに initial catalog の dotnetcorewebsampleが指定データベースとして認識されている?

以下の記事をを参考にしました。

SQL Server の既定のインスタンスまたは名前つきインスタンスに接続する場合の接続文字列(正確には SqlClient 接続文字列)の例として、Initail Catalog(もしくは Database)キーワードでデータベース名を指定するように書かれています。

接続文字列でのデータベース名の指定

つまり、定義はどちらかで良くて両方指定した場合は initial catalog で指定したデータベース名が優先される

以上により、appsettings.jsonを“Server=sqlexpress;Database=master;User ID=sa;Password=P@ssw0rd;MultipleActiveResultSets=True;App=EntityFramework;”

に変更して、SSMSを使ってデータを入れてみた所、、

Docker環境に構築したASP.NETとSQLSERVERでも無事にページと中のデータを表示することができました!

まとめ

今回は前回参考にしたサイト先のdocker-compose.ymlを丸コピーしてしまったため、起こった悲劇でしたが、ソロ学習でも実務でも大抵こういったエラーを乗り越えてプログラミング能力が培われるので勉強になってよかったと思います。

ちなみに今回はDocker環境を前提にした回でしたがDocker側の細かい動作は省略しました。Dockerに関する知識自体をある程度知りたい場合は過去記事をご覧ください。Dockerの場合RailsやLaravel環境も好きに作れてしまうのでそっちにはDocker側の操作もある程度書いてあります。

あと前回記事では「本番環境のデプロイではmigration使えばDBは作成できる」と書きましたが実際やるにはdotnetコマンドを打てるようにしたり準備がめんどそうだったので一旦割愛しました。SSMSを使えばとりあえずデータやテーブルは問題ないですしね^^;;

次回からはWebページ上でデータの更新ができるようになるまでをやりたいと思います。