練習 - 將 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 應用程式之後,輸出會顯示含有網站 URL 的 App_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. 使用程式碼編輯器來開啟 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 入口網站。

  8. 在 Azure 入口網站功能表上,選取 [SQL 資料庫],然後選取資料庫。 coursedatabaseNNNSQL 資料庫隨即出現。

  9. 在左側功能表窗格的 [設定] 下,選取 [連接字串]。 將 ADO.NET 連接字串複製到剪貼簿。

    The connection string pane in the Azure portal.

  10. 返回程式碼編輯器。 將 connectionString 變數的值取代為剪貼簿的值。 在連接字串中,看到值為 azuresql 的文字 User ID。 將文字 {your_password} 換成此帳戶的密碼。

    private string connectionString = "Server=tcp:<server-name>.database.windows.net,1433;Initial Catalog=<database-name>;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 物件來一次一列擷取結果。

  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:<server-name>.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. 儲存檔案並關閉 Code 編輯器。

將程式碼新增至 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.