演習 - ASP.NET アプリケーションを Azure SQL Database に接続する

完了

データベースが作成されます。 これで、教育アドバイザーが学生と学習のコースと計画について話し合うために使用できる Web アプリケーションを構成してデプロイできるようになりました。 このアプリは System.Data.SqlClient ライブラリを使用して、コースの詳細とコースを修了するために学生が合格する必要があるモジュールを取得して表示します。

時間を節約するため、既存の Web アプリケーションを使用し、このアプリをデータベースに接続するコードを追加する方法を示します。 次の図では、このアプリの主要コンポーネントが示されています。

High-level view of the application structure.

Web アプリケーションを構成するには、次のことを実行します。

  • コース名、モジュールのタイトル、および各モジュールのシーケンスをデータベース内に保持する "クラス" を作成します。
  • データベースから情報を取得する "データ アクセス コントローラー クラス" を作成します。
  • Web アプリのインデックス ページの背後にあるコードを編集し、"データ アクセス コントローラー オブジェクト" を作成して、データをフェッチします。
  • データが表示されるようにインデックス ページを編集します。

既存の Web アプリをデプロイして実行する

  1. 作業ディレクトリを education フォルダーに変更します。

    cd ~/education
    
  2. 次のコマンドを実行して、初期の Web アプリをビルドしてデプロイします。

    WEBAPPNAME=educationapp-$RANDOM
    az webapp up \
        --resource-group <rgn>[Sandbox resource group]</rgn> \
        --location centralus \
        --sku F1 \
        --name $WEBAPPNAME
    
  3. Web アプリケーションがデプロイされると、出力に App_url と Web サイトの URL が表示されます。 新しいタブでこのサイトを開きます。

    The education web app running. Currently, no data is displayed.

    あなたは、Web アプリでコースと各コースを構成するモジュールの一覧を表示したいと考えています。 現在、アプリではこのデータは取得も表示もされていません。 そのため、データベースからデータを取得して表示するには、コードを更新する必要があります。

データを取得するコードを Web アプリに追加する

では、データベースからコース データを取得するコードをアプリケーションに追加してみましょう。

  1. Cloud Shell で education/Models フォルダーに移動します。

    cd ~/education/Models
    

    このフォルダーには、CoursesAndModules.csDataAccessController.cs の 2 つのファイルが含まれています。

  2. コード エディターを使用して CoursesAndModules.cs ファイルを開きます。

    code CoursesAndModules.cs
    

    このファイルには、CoursesAndModules という名前の空のクラスが含まれています。

    namespace CoursesWebApp.Models
    {
        public class CoursesAndModules
        {
            // TODO: Define the CourseName, ModuleTitle, and Sequence read-only properties
    
            // TODO: Create a constructor that initializes the fields behind the properties
        }
    }
    
  3. コメント // TODO: Define the CourseName, ModuleTitle, and Sequence read-only properties を、次のコードに置き換えます。

    public string CourseName { get; }
    public string ModuleTitle { get; }
    public int Sequence { get; }
    

    このコードは、Web アプリによって表示される各行のデータを含む読み取り専用フィールドのセットを定義します。

  4. コメント // TODO: Create a constructor that initializes the fields behind the properties を、次のコンストラクターに置き換えます。

    public CoursesAndModules(string courseName, string moduleTitle, int sequence)
    {
        this.CourseName = courseName;
        this.ModuleTitle = moduleTitle;
        this.Sequence = sequence;
    }
    

    このコンストラクターでは、表示するデータがフィールドに入力されます。 完全なファイルには、次のコードを含める必要があります。

    namespace CoursesWebApp.Models
    {
        public class CoursesAndModules
        {
            public string CourseName { get; }
            public string ModuleTitle { get; }
            public int Sequence { get; }
    
            public CoursesAndModules(string courseName, string moduleTitle, int sequence)
            {
                this.CourseName = courseName;
                this.ModuleTitle = moduleTitle;
                this.Sequence = sequence;
            }
        }
    }
    
  5. Ctrl + S キーを押してファイルを保存し、Ctrl + Q キーを押してコード エディターを閉じます。

  6. コード エディターを使用して DataAccessController.cs ファイルを開きます。

    code DataAccessController.cs
    

    このファイルには、DataAccessController という名前のクラスが含まれています。 このクラスには、データベースに接続してコースとモジュールのデータを取得するためのデータ アクセス ロジックが含まれます。 これはこのデータを使用して CoursesAndModules オブジェクトのリストを設定します。

    using Microsoft.Extensions.Options;
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.SqlClient;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace CoursesWebApp.Models
    {
        public class DataAccessController
        {
            // TODO: Add your connection string in the following statements
            private string connectionString = "<Azure SQL Database Connection String>";
    
            // Retrieve all details of courses and their modules
            public IEnumerable<CoursesAndModules> GetAllCoursesAndModules()
            {
                List<CoursesAndModules> courseList = new List<CoursesAndModules>();
    
                // TODO: Connect to the database
                //using ()
                {
                    // TODO: Specify the Transact-SQL query to run
    
                    // TODO: Execute the query
    
                    // TODO: Read the data a row at a time
    
                    // TODO: Close the database connection
                }
                return courseList;
            }
        }
    }
    
  7. コード エディターを開いたまま、Azure portal に切り替えます。

  8. Azure portal のメニューで、[SQL データベース] を選択し、次にデータベースを選択します。 coursedatabaseNNNSQL データベースが表示されます。

  9. 左側のメニュー ペインの [設定][接続文字列] を選択します。 [ADO.NET] の接続文字列をクリップボードにコピーします。

    The connection string pane in the Azure portal.

  10. コード エディターに戻ります。 connectionString 変数の値をクリップボードの値に置き換えます。 接続文字列で、テキスト User ID を値 azuresql に設定します。 テキスト {your_password} をこのアカウントのパスワードに置き換えます。

    private string connectionString = "Server=tcp:courseservernnn.database.windows.net,1433;Initial Catalog=coursedatabasennn;Persist Security Info=False;User ID=azuresql;Password=<password>;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;";
    
  11. コメント //TODO: Connect to the database の後で、コメントアウトされた using ステートメントを次のコードに置き換えます。

    using (SqlConnection con = new SqlConnection(connectionString))
    

    このコードでは、接続文字列を使用してデータベースに接続する新しい SqlConnection オブジェクトが作成されます。

  12. コメント // TODO: Specify the Transact-SQL query to run を、次のステートメントに置き換えます。

    SqlCommand cmd = new SqlCommand(
        @"SELECT c.CourseName, m.ModuleTitle, s.ModuleSequence
        FROM dbo.Courses c JOIN dbo.StudyPlans s
        ON c.CourseID = s.CourseID
        JOIN dbo.Modules m
        ON m.ModuleCode = s.ModuleCode
        ORDER BY c.CourseName, s.ModuleSequence", con);
    cmd.CommandType = CommandType.Text;
    

    SqlCommand オブジェクトには、すべてのコースとモジュールのデータを取得する Transact-SQL (T-SQL) ステートメントが含まれています。 dbo.StudyPlan テーブル内の情報を使用してそれらを結合します。

  13. コメント // TODO: Execute the query を、次のコードに置き換えます。

    con.Open();
    SqlDataReader rdr = cmd.ExecuteReader();
    

    これらのステートメントでは、データベースへの接続が開かれて、T-SQL ステートメントが実行されます。 SqlDataReader オブジェクトを使用すると、結果を 1 行ずつフェッチできます。

  14. コメント // TODO: Read the data a row at a time を、次のコード ブロックに置き換えます。

    while (rdr.Read())
    {
        string courseName = rdr["CourseName"].ToString();
        string moduleTitle = rdr["ModuleTitle"].ToString();
        int moduleSequence = Convert.ToInt32(rdr["ModuleSequence"]);
        CoursesAndModules course = new CoursesAndModules(courseName, moduleTitle, moduleSequence);
        courseList.Add(course);
    }
    

    このブロックでは、SqlDataReader オブジェクトで返された行が反復処理されます。 そのコードでは、各行のフィールド内のデータが抽出され、それらを使用して新しい CoursesAndModules オブジェクトが設定されます。 このオブジェクトはその後、リストに追加されます。

  15. コメント // TODO: Close the database connection を、次のステートメントに置き換えます。

    con.Close();
    

    このステートメントでは、データベースへの接続が閉じられ、保持されているリソースが解放されます。

    完成したクラスには次のコードが含まれているはずで、それには自分のデータベースへの接続文字列が含まれます。

    using Microsoft.Extensions.Options;
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.SqlClient;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace CoursesWebApp.Models
    {
        public class DataAccessController
        {
            // Add your connection string in the following statements
            private string connectionString = "Server=tcp:courseserver101.database.windows.net,1433;Initial Catalog=coursedatabase101;Persist Security Info=False;User ID=azuresql;Password=<password>;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;";
    
            // Retrieve all details of courses and their modules    
            public IEnumerable<CoursesAndModules> GetAllCoursesAndModules()
            {
                List<CoursesAndModules> courseList = new List<CoursesAndModules>();
    
                // Connect to the database
                using (SqlConnection con = new SqlConnection(connectionString))
                {
                    // Specify the Transact-SQL query to run
                    SqlCommand cmd = new SqlCommand(
                        @"SELECT c.CourseName, m.ModuleTitle, s.ModuleSequence
                        FROM dbo.Courses c JOIN dbo.StudyPlans s
                        ON c.CourseID = s.CourseID
                        JOIN dbo.Modules m
                        ON m.ModuleCode = s.ModuleCode
                        ORDER BY c.CourseName, s.ModuleSequence", con);
                    cmd.CommandType = CommandType.Text;
    
                    // Execute the query
                    con.Open();
                    SqlDataReader rdr = cmd.ExecuteReader();
    
                    // Read the data a row at a time
                    while (rdr.Read())
                    {
                        string courseName = rdr["CourseName"].ToString();
                        string moduleTitle = rdr["ModuleTitle"].ToString();
                        int moduleSequence = Convert.ToInt32(rdr["ModuleSequence"]);
                        CoursesAndModules course = new CoursesAndModules(courseName, moduleTitle, moduleSequence);
                        courseList.Add(course);
                    }
    
                    // Close the database connection
                    con.Close();
                }
                return courseList;
            }
        }
    }
    
  16. ファイルを保存して、コード エディターを閉じます。

データを表示するためのコードを Web アプリに追加する

アプリケーションでコース データを取得できるようになりました。 ここでは、ユーザーにデータを表示するようにアプリを更新します。

  1. Cloud Shell で education/Pages フォルダーに移動します。

    cd ~/education/Pages
    

    このフォルダーには、情報を表示するために Web アプリで使用される .cshtml ページとコード ファイルが含まれています。

  2. コード エディターを使用して Index.cshtml.cs ファイルを開きます。

    code Index.cshtml.cs
    

    このファイルには、インデックス ページが表示されるときに実行されるコードが含まれています。 このコードでは、CoursesAndModulesModel クラスが定義されています。 インデックス ページはこのモデルを使用してコースとモジュールの詳細を表示します。 このファイルには、DataAccessController オブジェクトを使用してそのデータをフェッチするコードを追加する必要があります。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using CoursesWebApp.Models;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    
    namespace CoursesWebApp.Pages
    {
        public class CoursesAndModulesModel : PageModel
        {
            // TODO: Create a DataAccessController object
    
            // TODO: Create a collection for holding CoursesAndModules object
    
            public void OnGet()
            {
                // TODO: Retrieve the data using the DataAccessController object and populate the CoursesAndModules object
            }
        }
    }
    
  3. Index.cshtml.cs で、コメント // TODO: Create a DataAccessController object を次のコードに置き換えて、新しい DataAccessController オブジェクトを作成します。

    DataAccessController dac = new DataAccessController();
    
  4. コメント // TODO: Create a collection for holding CoursesAndModules object を、次のコードに置き換えます。

    public List<CoursesAndModules> CoursesAndModules;
    
  5. OnGet メソッドで、コメント // TODO: Retrieve the data using the DataAccessController object and populate the CoursesAndModules object を次のコードに置き換えます。 このコードは、DataAccessController オブジェクトを使用してデータベースのデータをリストに入力します。

    CoursesAndModules = dac.GetAllCoursesAndModules().ToList();
    

    完成したファイルには、次のコードを含める必要があります。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using CoursesWebApp.Models;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    
    namespace CoursesWebApp.Pages
    {
        public class CoursesAndModulesModel : PageModel
        {
            // Create a DataAccessController object
            DataAccessController dac = new DataAccessController();
    
            // Create a collection for holding CoursesAndModules object
            public List<CoursesAndModules> CoursesAndModules;
    
            public void OnGet()
            {
                // Retrieve the data using the DataAccessController object and populate the CoursesAndModules object
                CoursesAndModules = dac.GetAllCoursesAndModules().ToList();
            }
        }
    }
    
  6. ファイルを保存して、コード エディターを閉じます。

  7. コード エディターを使用して Index.cshtml ファイルを開きます。

    code Index.cshtml
    

    このファイルには、インデックス ページの表示ロジックが含まれています。 データ ソースとして CoursesAndModulesModel が指定されています。 追加したコードにより、このモデルが作成されて設定されます。

    そのページでは、HTML データを使用してモデルからデータが表示されます。 現時点では、ページにはテーブルの見出しだけが表示されます。 テーブルの本体 (<tbody>) は空です。

    <h2>Courses and Modules</h2>
    <div>
        <table class="table">
            <thead>
                <tr>
                    <th>
                        Course Name
                    </th>
                    <th>
                        Modules
                    </th>
                    <th>
                        Sequence
                    </th>
                </tr>
            </thead>
            <tbody>
                <!-- TODO: Display the data from the CoursesAndModules collection -->
            </tbody>
        </table>
    </div>
    
  8. コメント <!-- TODO: Display the data from the CoursesAndModules collection --\> を、次のマークアップに置き換えます。

    @foreach(var courseAndModule in Model.CoursesAndModules)
    {
    <tr>
        <td>
            @Html.DisplayFor(courseName => courseAndModule.CourseName)
        </td>
        <td>
            @Html.DisplayFor(moduleTitle => courseAndModule.ModuleTitle)
        </td>
        <td>
            @Html.DisplayFor(sequence => courseAndModule.Sequence)
        </td>
    </tr>
    }
    

    このコードでは、モデル内の行が反復処理されて、各フィールドのデータが出力されます。

    完成した Index.cshtml ファイルには、次のコードが含まれていなければなりません。

    @page
    @model CoursesAndModulesModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <h2>Courses and Modules</h2>
    <div>
        <table class="table">
            <thead>
                <tr>
                    <th>
                        Course Name
                    </th>
                    <th>
                        Modules
                    </th>
                    <th>
                        Sequence
                    </th>
                </tr>
            </thead>
            <tbody>
                @foreach(var courseAndModule in Model.CoursesAndModules)
                {
                <tr>
                    <td>
                        @Html.DisplayFor(courseName => courseAndModule.CourseName)
                    </td>
                    <td>
                        @Html.DisplayFor(moduleTitle => courseAndModule.ModuleTitle)
                    </td>
                    <td>
                        @Html.DisplayFor(sequence => courseAndModule.Sequence)
                    </td>
                </tr>
                }
            </tbody>
        </table>
    </div>
    
  9. ファイルを保存して、コード エディターを閉じます。

更新された Web アプリをデプロイしてテストする

アプリケーションの構成が完全に終わり、コース データが取得されてユーザーに表示されるようになったので、更新されたバージョンをデプロイすることができます。

  1. Cloud Shell で education フォルダーに戻ります。

    cd ~/education
    
  2. 次のコマンドを実行し、更新された Web アプリをビルドしてデプロイします。

    az webapp up \
        --resource-group <rgn>[Sandbox resource group]</rgn> \
        --name $WEBAPPNAME
    
  3. 新しい Web アプリがデプロイされた後、アプリに対するリンクを選択します。 データベースに格納されているデータを使用して、コースとモジュールの一覧が表示されるはずです。

    Screenshot of the education web app running, showing the data.