练习 - 将 ASP.NET 应用程序连接到 Azure SQL 数据库
已创建一个数据库。 现在你可以配置和部署一个 Web 应用,学术顾问可以用它与学生讨论课程和学习计划。 该应用使用 System.Data.SqlClient
库来检索和显示课程的详细信息,以及学生完成课程必须通过的模块。
为了节省时间,我们使用预先存在的 Web 应用程序,并演示如何添加将此应用连接到数据库的代码。 下图显示了此应用程序的主要组件:
要配置 Web 应用程序,请执行以下操作:
- 创建一个类,其中包含数据库中每个模块的课程名称、模块标题和顺序。
- 创建一个数据访问控制器类,用于从数据库中检索信息。
- 编辑 Web 应用程序中索引页面背后的代码来创建数据访问控制器对象并获取数据。
- 编辑索引页以显示数据。
部署并运行现成的 Web 应用
将工作目录更改为
education
文件夹。cd ~/education
运行以下命令以构建和部署初始 Web 应用程序。
WEBAPPNAME=educationapp-$RANDOM az webapp up \ --resource-group <rgn>[Sandbox resource group]</rgn> \ --location centralus \ --sku F1 \ --name $WEBAPPNAME
部署 Web 应用程序后,输出会显示带有网站 URL 的 App_url。 在新标签页中打开此网站。
你希望 Web 应用显示课程列表和组成每个课程的模块。 目前,该应用不会检索或显示此数据。 因此,需要更新代码,以便从数据库中获取数据并显示数据。
向 Web 应用添加代码以检索数据
现在向应用程序添加代码以检索数据库中的课程数据。
在 Cloud Shell 中,转到
education/Models
文件夹。cd ~/education/Models
此文件夹包含两个文件:
CoursesAndModules.cs
和DataAccessController.cs
。使用代码编辑器打开
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 } }
使用以下代码替换
// TODO: Define the CourseName, ModuleTitle, and Sequence read-only properties
注释。public string CourseName { get; } public string ModuleTitle { get; } public int Sequence { get; }
此代码定义了一组只读字段,它们包含 Web 应用显示的每一行的数据。
使用以下构造函数替换
// 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; } } }
按 Ctrl+S 保存文件,并按 Ctrl+Q 关闭代码编辑器。
使用代码编辑器打开
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; } } }
使代码编辑器保持打开状态,然后切换到 Azure 门户。
在 Azure 门户菜单上,选择“SQL 数据库”,然后选择你的数据库。 此时将显示“coursedatabaseNNN”的“SQL 数据库”。
在左侧菜单窗格的“设置”下,选择“连接字符串”。 将 ADO.NET 连接字符串复制到剪贴板。
返回到代码编辑器。 使用剪贴板中的值替换 connectionString 变量的值。 在连接字符串中,使用值
azuresql
替换文本User ID
。 将文本{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;";
在注释
//TODO: Connect to the database
之后,使用以下代码替换注释掉的using
语句。using (SqlConnection con = new SqlConnection(connectionString))
此代码创建一个新的
SqlConnection
对象,它使用连接字符串连接到数据库。使用下面的语句替换
// 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
表中的信息将它们联结起来。使用以下代码替换
// TODO: Execute the query
注释。con.Open(); SqlDataReader rdr = cmd.ExecuteReader();
这些语句开启与数据库的连接并运行 T-SQL 语句。 可以使用
SqlDataReader
对象一次提取一行结果。使用下面的代码块替换
// 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
对象。 然后将此对象添加到列表中。使用下面的语句替换
// 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; } } }
保存文件并关闭“代码”编辑器。
向 Web 应用添加代码以显示数据
现在,应用程序可以检索课程数据。 此时,请更新应用程序以向用户显示数据。
在 Cloud Shell 中,转到
education/Pages
文件夹。cd ~/education/Pages
此文件夹包含 Web 应用用于显示信息的 .cshtml 页面和代码文件。
使用代码编辑器打开
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 } } }
在
Index.cshtml.cs
中,用以下代码替换注释// TODO: Create a DataAccessController object
以创建新的DataAccessController
对象。DataAccessController dac = new DataAccessController();
使用以下代码替换
// TODO: Create a collection for holding CoursesAndModules object
注释。public List<CoursesAndModules> CoursesAndModules;
在
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(); } } }
保存文件并关闭代码编辑器。
使用代码编辑器打开
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>
使用以下标记替换
<!-- 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>
保存文件并关闭代码编辑器。
部署和测试更新的 Web 应用
完整配置应用程序以检索课程数据并向用户显示后,可部署更新的版本。
在 Cloud Shell 中,返回
education
文件夹。cd ~/education
运行以下命令以生成和部署更新的 Web 应用。
az webapp up \ --resource-group <rgn>[Sandbox resource group]</rgn> \ --name $WEBAPPNAME
部署新的 Web 应用后,选择应用的链接。 现在应会显示一个课程和模块列表,其中包含存储在数据库中的数据。