> 技术文档 > 使用 ASP.NET Core 进行现代全栈 Web 开发: 13 Angular 与 ASP.NET Core 集成_现代 angular 13 高级课程

使用 ASP.NET Core 进行现代全栈 Web 开发: 13 Angular 与 ASP.NET Core 集成_现代 angular 13 高级课程

将 Angular 与 ASP.NET Core 集成,为开发可扩展的全栈应用提供了强大的工具包。 Angular 能与 ASP.NET Core 无缝协作,构建动态 Web 应用程序。 本章将逐步讲解如何配置 Angular 与 ASP.NET Core,助力创建高性能、高效率的全栈应用。 我们将学习如何在 Angular 和 ASP.NET Core 应用之间进行 API 调用, 实现这两个强大框架间安全高效的通信。

通过本章学习,您将扎实掌握如何开发一个与 ASP.NET Core 后端交互的 Angular 应用程序,同时遵循良好的软件开发实践。 您还将学习如何优化前后端性能,确保流畅的用户体验。 这些技能对于希望使用市场上最现代技术栈来创建和设计可扩展应用程序的软件工程师至关重要。

本章我们将涵盖以下 主要主题:

  • 搭建 Angular 与 ASP.NET Core 的开发环境
  • 构建 示例应用程序

这种结构将帮助您以实践方式掌握关键概念,为理解 Angular 与 ASP.NET Core 的集成方面奠定坚实基础。

20年工作经验,承接微信小程序,App,网站,网站后端开发。有意向私聊我哈。微信:akluse

Angular 与 ASP.NET Core 环境搭建

在本节中,我们 将搭建一个用于集成 Angular 与 ASP.NET Core 的开发环境,配置 ASP.NET Core 以托管 Angular 应用程序,并创建 Angular 项目的基础结构来 开始开发。

假设您已根据前一章的实践练习在机器上安装了 Node.js 和 npm ,要使用 Angular,您还必须安装 Angular CLI。 这提供了一套强大的工具来管理开发过程中的 Angular 应用程序。 要全局安装它,您可以使用 常规的 命令 提示符 CMD )运行以下命令:

npm install -g @angular/cli

现在,所有内容都已正确安装,我们可以继续在 下一节中创建 ASP.NET Core Web API 项目。

创建 ASP.NET Core Web API 项目

要创建 ASP.NET Core Web API 项目,请按照 以下步骤操作:

  1. 打开 Visual Studio,通过选择 ASP.NET Core Web API 模板创建新项目,如图 13.1 所示 :

图 13.1:ASP.NET Core Web API 模板

  1. 选择完 ASP.NET Core Web API 模板后,请确保选择.NET 9 版本,并在最终屏幕中选择不使用顶级语句的控制器,如图 13.2 所示 :

图 13.2:ASP.NET Core Web API 配置

创建 ASP.NET Core Web API 项目后,需要安装 SPAServices.Extensions 包,该包将用于配置 ASP.NET Core 项目以托管 Angular 应用程序

  1. 要安装此包,请在 解决方案资源管理器 中右键单击新创建的项目,选择 管理 NuGet 程序包… 选项,如 图 13 .3 所示 :

图 13.3:管理 NuGet 程序包…选项

  1. 在 NuGet 包管理器 窗口中,选择 浏览 选项,搜索 Microsoft.AspNetCore.SpaServices.Extensions 包并确认安装,如 图 13 .4 所示 :

图 13.4:SPAServices.Extensions 安装过程

  1. 之后,您需要修改 Program.cs 文件,配置 ASP.NET Core 以托管 Angular 应用。 按如下方式修改 Program.cs 文件:
    namespace Chapter13{ public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddSpaStaticFiles( configuration => { configuration.RootPath =  \"ClientApp/dist\"; }); var app = builder.Build(); app.UseStaticFiles(); app.UseSpaStaticFiles(); app.UseAuthorization(); app.MapControllers(); app.Run(); } }}

    在此配置中,AddSpaStaticFiles 用于提供 Angular 应用的静态文件。RootPath 被配置指向 ClientApp/dist 文件夹,该文件夹是 Angular 应用生产构建文件的存放位置。

ASP.NET Core 应用程序现已配置完成,可用于托管我们将要创建的 Angular 应用,本章后续将采用分步方式实现。 在下一节中,我们将通过扩展本节开发的 ASP.NET Core Web API 项目来构建一个示例应用。

构建示例应用

在本节中,我们将构建一个健身追踪器应用,这是一个让用户监控锻炼情况和健身目标的简单工具。 该应用将包含 CRUD 操作,使用户能够记录每日训练、追踪长期进度并设定具体健身目标。 应用的后端将使用上一节创建的 ASP.NET Core Web API 项目来定义前端调用的端点。 此外,我们将从零开始构建一个 Angular 应用,配置前后端之间的数据通信环节,包括必要的用户界面 (UI)元素。

从技术角度来看, 本应用将运用 RESTful API 开发(我们已在第 8 章第 9 章讨论过 RESTful API)以及内存数据库进行交互,这些仅用于演示目的。 此外,我们将使用 Angular 内置功能如路由和 HTTP 客户端,同时通过 TypeScript 接口来保持 Angular 应用与 ASP.NET Core Web API 项目之间的数据流一致性。 在本节结束时,您将按照循序渐进的方式掌握 Angular 与 ASP.NET Core 集成的基本原理。

下一节将详细介绍需要在后端为 Fitness Tracker 应用 创建的领域模型。

创建领域模型

本节中, 我们将定义健身追踪器应用程序的核心领域模型。 领域模型定义了封装应用程序业务逻辑和数据结构的关键实体。 在我们的应用中,主要实体是锻炼记录健身目标 .

我们将在 ASP.NET Core 后端将这些实体存储在内存中,这样无需实际数据库就能模拟数据存储。 这种配置非常适合快速开发和测试,使我们能够快速构建应用程序原型。 在实际生产环境中,您需要使用真实的数据库,并通过 Entity Framework Core 或其他框架处理后端与 数据库之间的交互。

不过,尽管我们将实体存储在内存中,在后端正确定义它们仍然至关重要,这样才能被我们的内存存储系统有效使用。 让我们开始 以下步骤:

  1. 在您的 ASP.NET Core Web API 项目中,使用 解决方案资源管理器 在项目根目录下创建一个名为 Models 的文件夹, 在 Visual Studio 中操作。
  2. 接着,创建一个 Workout.cs 文件,该文件将包含 Workout 模型的规范。 创建文件后,添加 以下代码:
    namespace Chapter13.Models{ public class Workout { public int Id { get; set; } public string Exercise { get; set; } public int Duration { get; set; } public DateTime Date { get; set; } public string Notes { get; set; } }}

    您可以将命名空间替换为您自己项目中的命名空间,这适用于本章所有 C#示例。 该模型包含了 Fitness Tracker 应用中记录常规锻炼会话的基本属性,例如 Id  Exercise  Duration  Date 、 以及 Notes .

  3. 接下来是 模型 FitnessGoal ,它同样包含基本属性。 可以通过在 Models 文件夹中创建 FitnessGoal.cs 文件来定义。 之后,你可以添加 以下代码:
    namespace Chapter13.Models{ public class FitnessGoal { public int Id { get; set; } public string GoalName { get; set; } public string Description { get; set; } public DateTime TargetDate { get; set; } }}

FitnessGoal 模型 允许用户设定与健身相关的目标,例如完成一定次数的锻炼或在目标日期前达成特定的健身里程碑。 该实体有助于长期追踪目标进度,并判断这些目标是否 已达成。

在模型已创建的基础上,下一节将重点介绍如何为 这些模型创建内存存储库。

创建后端服务

为了存储 Workout 和 FitnessGoal 实体到内存中,我们将在 ASP.NET Core 后端使用内存列表。 这种方法将模拟数据库,使我们能够执行 CRUD 操作,而无需在本地设置实际的数据库。

要配置内存存储,请在项目根目录下创建 Services 文件夹(与 Models 文件夹同级),并在 Services 文件夹中创建 WorkoutService.cs 文件,其中包含以下代码:

using Chapter13.Models;namespace Chapter13.Services{ public class WorkoutService { private readonly List _workouts = new List(); public IEnumerable GetWorkouts() => _workouts; public Workout GetWorkoutById(int id) => _workouts.FirstOrDefault(w => w.Id == id); public void AddWorkout(Workout workout) { workout.Id = _workouts.Count + 1; _workouts.Add(workout); } public void UpdateWorkout( int id, Workout updatedWorkout) { var workout = _workouts.FirstOrDefault(w => w.Id == id); if (workout != null) { workout.Exercise = updatedWorkout.Exercise; workout.Duration = updatedWorkout.Duration; workout.Date = updatedWorkout.Date; workout.Notes = updatedWorkout.Notes; } } public void DeleteWorkout(int id) { var workout = _workouts.FirstOrDefault(w => w.Id == id); if (workout != null) { _workouts.Remove(workout); } } }}

WorkoutService 类负责管理内存中的所有锻炼数据。 它提供了 创建、读取、更新和删除锻炼记录的方法,模拟了一个后续可替换为数据库的数据存储库。 以下是 各个方法的说明:

  • GetWorkouts :此方法可获取内存中存储的所有训练记录。 它返回 IEnumerable ,使调用函数能够访问 训练记录列表。
  • GetWorkoutById(int id) :此方法根据提供的 ID 返回特定训练记录。 它使用 LINQ 查询匹配 ID 的记录,若未找到对应 ID 的训练记录,则 返回 null .
  • AddWorkout(Workout workout) :此方法将新锻炼项目添加到内存列表中。 锻炼 ID 是通过简单递增列表中已有锻炼项目的计数自动生成的。 该方法模拟了 数据库中 自增主键的行为。
  • UpdateWorkout(int id, Workout updatedWorkout) :此方法更新现有锻炼项目的详细信息。 它首先通过 ID 检索锻炼项目,如果找到则更新其属性。 在实际应用中,这将涉及数据库中的更新查询或使用 Entity Framework 的更新操作。
  • DeleteWorkout(int id) :此方法从内存列表中移除一项锻炼记录。 它通过 ID 检索锻炼记录,若找到则从列表中移除。 在完整应用中,这将涉及对 DELETE 数据库表 的操作。

既然 您已完成 WorkoutService 类,现在需要为 FitnessGoal 实体创建服务类。 请在 Services 文件夹中新建名为 FitnessGoalService.cs 的文件,并在 新文件中添加以下代码:

using Chapter13.Models;namespace Chapter13.Services{ public class FitnessGoalService { private readonly List _goals = new List(); public IEnumerable GetGoals() => _goals; public FitnessGoal GetGoalById(int id) => _goals.FirstOrDefault(g => g.Id == id); public void AddGoal(FitnessGoal goal) { goal.Id = _goals.Count + 1; _goals.Add(goal); } public void UpdateGoal( int id, FitnessGoal updatedGoal) { var goal = _goals.FirstOrDefault(g => g.Id == id); if (goal != null) { goal.GoalName = updatedGoal.GoalName; goal.Description = updatedGoal.Description; goal.TargetDate = updatedGoal.TargetDate; } } public void DeleteGoal(int id) { var goal = _goals.FirstOrDefault(g => g.Id == id); if (goal != null) { _goals.Remove(goal); } } }}

FitnessGoalService 类负责管理内存中所有与健身目标相关的操作。 与 WorkoutService 类似,它提供了创建、读取、更新和删除健身目标的方法,模拟了持久化 数据库 中存储库的操作。 以下是该服务中每个方法的说明:

  • GetGoals() :此方法获取存储在内存中的所有健身目标。 它返回 IEnumerable ,即所有健身目标的集合。 在实际系统中,这将涉及查询数据库中的所有 目标记录。
  • GetGoalById(int id) :此方法通过 ID 获取特定的健身目标。 它使用 LINQ 在内存列表中搜索匹配 ID 的目标。 如果未找到目标,则 返回 null .
  • AddGoal(FitnessGoal goal) :此方法将新的健身目标添加到内存列表中。 与 AddWorkout 类似,它会通过递增现有目标数量来自动生成目标 ID。 此过程模拟了数据库如何为 新记录 自动递增主键。
  • UpdateGoal(int id, FitnessGoal updateGoal) :此方法更新现有健身目标的详细信息。 它通过 ID 检索目标并更新其属性。 在实际应用中,此方法对应于数据库中的 UPDATE 查询。
  • DeleteGoal(int id) :此方法从内存列表中移除一个健身目标。 它通过 ID 查找目标,若找到则从列表中移除。 在持久化存储系统中,这相当于数据库中的 DELETE 操作。

与 WorkoutService 类似, FitnessGoalService 也提供完整的 CRUD 功能,但将数据存储在内存中。 这种设置在快速原型设计和开发阶段非常有用,之后可再接入更复杂的 数据库集成方案。

下一节我们将为 Workout 和 FitnessGoal 实体创建控制器。

创建控制器

为实现我们 Fitness Tracker 应用中训练计划管理的后端 API,需要在 ASP.NET Core 项目中创建基础控制器以暴露相关 API 接口,这些接口后续将与 Angular 应用集成。 首个控制器是 WorkoutsController,负责暴露对训练计划数据执行 CRUD 操作所需的 API 端点。 通过 ASP.NET Core 的 Web API 功能,该控制器将作为前端与后端逻辑的中介,确保正确处理 GET POST PUT 和 DELETE 等 HTTP 请求。 通过创建此控制器,您将建立 API 路由,使用户能够与系统中的训练计划进行交互,同时利用底层服务层执行必要的操作。

在您的 ASP.NET Core 项目中,于 Controllers 文件夹内创建一个名为 WorkoutsController.cs 的文件,并指定 以下代码:

using Chapter13.Models;using Chapter13.Services;using Microsoft.AspNetCore.Mvc;namespace Chapter13.Controllers{ [Route(\"api/[controller]\")] [ApiController] public class WorkoutsController : ControllerBase { private readonly WorkoutService _workoutService; public WorkoutsController( WorkoutService workoutService) { _workoutService = workoutService; } [HttpGet] public ActionResult<IEnumerable> GetWorkouts() { return Ok(_workoutService.GetWorkouts()); } [HttpGet(\"{id}\")] public ActionResult GetWorkout(int id) { var workout = _workoutService.GetWorkoutById(id); if (workout == null) return NotFound(); return Ok(workout); } [HttpPost] public ActionResult CreateWorkout( Workout workout) { _workoutService.AddWorkout(workout); return NoContent(); } [HttpPut(\"{id}\")] public IActionResult UpdateWorkout( int id, Workout updatedWorkout) { var workout = _workoutService.GetWorkoutById(id); if (workout == null) return NotFound(); _workoutService.UpdateWorkout( id, updatedWorkout); return NoContent(); } [HttpDelete(\"{id}\")] public IActionResult DeleteWorkout(int id) { var workout = _workoutService.GetWorkoutById(id); if (workout == null) return NotFound(); _workoutService.DeleteWorkout(id); return NoContent(); } }}

在此控制器中, 构造函数通过依赖注入方式注入了 WorkoutService 的实例。 通过注入 WorkoutService,该控制器能够与内存中的锻炼列表进行交互。 这种方式提高了可测试性,并将控制器与服务解耦,便于在需要时替换为不同的服务实现。 以下是每个 API 端点:

  • GetWorkouts :该操作通过 GetWorkouts 方法从服务中获取所有训练数据。 返回结果附带 HTTP 200 OK 状态码,表示数据已成功获取。 Ok() 方法会自动将训练列表序列化为 JSON 格式,供 Angular 应用 使用。
  • GetWorkout(int id) :该操作根据提供的 ID 检索特定锻炼记录。 若找到对应记录,则返回 HTTP 200 OK 状态码及锻炼数据。 若未找到匹配 ID 的锻炼记录,该方法将返回 HTTP 404 Not Found 状态码,表示该资源 不存在。
  • CreateWorkout(Workout workout)  CreateWorkout 操作用于添加新的锻炼项目。 它接收一个 Workout 对象作为输入参数,该对象会被传递给服务中的 AddWorkout() 方法以存储到内存中。 该方法返回 HTTP 204 No Content 状态码,表示创建成功但 响应体 中不包含任何内容。
  • UpdateWorkout(int id, Workout updatedWorkout) :该操作用于更新现有训练项目。 首先通过 ID 检索训练项目,若找到则调用服务的 UpdateWorkout 方法来应用变更。 若未找到训练项目,则返回 HTTP 404 Not Found 。 若更新成功,则返回 HTTP 204 No Content .
  • DeleteWorkout(int id)  DeleteWorkout 操作通过 ID 处理训练记录的删除。 它首先检查该训练记录是否存在。 若存在,则调用服务中的 DeleteWorkout() 方法进行删除。 若训练记录不存在,该操作将返回 HTTP 404 Not Found 。 成功删除则返回 HTTP 204 No Content .

现在我们已经创建了 Workout 模型的控制器,接下来为 FitnessGoal 模型创建一个类似的控制器。 在 Controllers 文件夹中新建一个名为 FitnessGoalController.cs 的文件,并指定以下代码:

using Chapter13.Models;using Chapter13.Services;using Microsoft.AspNetCore.Mvc;namespace Chapter13.Controllers{ [Route(\"api/[controller]\")] [ApiController] public class FitnessGoalsController : ControllerBase { private readonly FitnessGoalService _fitnessGoalService; public FitnessGoalsController( FitnessGoalService fitnessGoalService) { _fitnessGoalService = fitnessGoalService; } [HttpGet] public ActionResult<IEnumerable> GetGoals() { return Ok(_fitnessGoalService.GetGoals()); } [HttpGet(\"{id}\")] public ActionResult GetGoal(int id) { var goal = _fitnessGoalService.GetGoalById(id); if (goal == null) return NotFound(); return Ok(goal); } [HttpPost] public ActionResult CreateGoal(FitnessGoal goal) { _fitnessGoalService.AddGoal(goal); return NoContent(); } [HttpPut(\"{id}\")] public IActionResult UpdateGoal( int id, FitnessGoal updatedGoal) { var goal = _fitnessGoalService.GetGoalById(id); if (goal == null) return NotFound(); _fitnessGoalService.UpdateGoal( id, updatedGoal); return NoContent(); } [HttpDelete(\"{id}\")] public IActionResult DeleteGoal(int id) { var goal = _fitnessGoalService.GetGoalById(id); if (goal == null) return NotFound(); _fitnessGoalService.DeleteGoal(id); return NoContent(); } }}

控制器的构造函数通过依赖注入接收一个 FitnessGoalService 的实例。 以下是在 FitnessGoalController 中每个控制器操作的详细说明 :

  • GetGoals :该操作处理 HTTP GET 请求,用于检索系统中存储的所有健身目标。 它会调用服务中的 GetGoals() 方法返回健身目标列表,并将结果封装在 HTTP 200 OK 响应中,该响应会将列表 序列化为 JSON 格式。
  • GetGoal(int id) :此方法根据提供的 ID 获取特定的健身目标。 若目标存在,将返回该目标并附带 HTTP 200 OK 响应。 若未找到目标,则返回 HTTP 404 Not Found .
  • CreateGoal(FitnessGoal goal) :该操作允许客户端通过发送包含目标数据的 POST 请求来创建新的健身目标。 该目标会通过服务中的 AddGoal() 方法被添加到内存列表。 成功创建将返回 HTTP 204 No Content 状态码,表示请求成功但 响应体 中不返回任何内容。
  • UpdateGoal(int id, FitnessGoal updatedGoal) :该 PUT 方法允许通过提供目标 ID 和更新数据来修改现有的健身目标。 若目标存在,则用新数据更新并返回 HTTP 204 No Content 状态码。 若目标不存在,则返回 HTTP 404 Not Found 状态码。
  • DeleteGoal(int id) :该操作根据 ID 从系统中删除健身目标。 首先通过 GetGoalById() 方法检查目标是否存在。 若找到目标则将其删除,并返回 HTTP 204 No Content 状态码。 若未找到目标则返回 HTTP 404 Not Found 状态码。 .

最后一步是使用单例作用域在应用程序中注册底层的 Workout 和 FitnessGoal 服务。 您可以通过将以下代码中高亮显示的行添加到 Program.cs 文件中来注册这些服务:

using Chapter13.Services;namespace Chapter13{ public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddSpaStaticFiles( configuration => { configuration.RootPath = \"ClientApp/dist\"; }); builder.Services.AddCors(options => { options.AddPolicy(\"AllowAllOrigins\",  policy => policy.AllowAnyOrigin()  .AllowAnyMethod()  .AllowAnyHeader()); }); builder.Services .AddSingleton(); builder.Services .AddSingleton(); var app = builder.Build(); app.UseStaticFiles(); app.UseSpaStaticFiles(); app.UseAuthorization(); app.UseCors(\"AllowAllOrigins\"); app.MapControllers(); app.Run(); } }}

FitnessGoalController 和 WorkoutsController 提供了完整的 CRUD 操作集, 用于管理 Fitness Tracker 应用中的训练计划和健身目标。 它们公开了必要的 API 端点,使前端能够与内存中存储的健身目标进行交互。 通过依赖注入,控制器与底层服务( WorkoutService 和 FitnessGoalService )进行通信以执行数据操作。 这种结构确保了职责的清晰分离,使控制器专注于处理 HTTP 请求,而服务则管理业务逻辑和数据存储。 这些 控制器遵循 RESTful 原则,便于与 Angular 等客户端应用集成。

下一节中,我们将创建用于消费 后端服务的 Angular 应用程序。

创建 Angular 应用程序

本节我们将重点为我们的 健身追踪器 应用设置 Angular 前端。 该应用将使用户能够与我们之前构建的后端进行交互,以管理他们的锻炼和健身目标。 在本节结束时,您将拥有一个功能完整的 Angular 应用程序,它能与后端服务通信,获取、显示、创建、更新和删除锻炼及健身 目标数据。

按照以下步骤创建 Angular 项目:

  1. 首先,在 Visual Studio 中打开一个新的开发者命令提示符窗口,目标指向你的 ASP.NET Core 项目根目录。
  2. 然后,通过执行 以下命令 创建一个名为 ClientApp 的新应用:
    ng new ClientApp
  3. 当提示时,选择 CSS 作为您要使用的样式表格式。 之后,通过执行 以下命令 导航到新创建应用的根目录:
    cd clientapp
  4. 为了增强用户界面,我们将使用 Bootstrap 来实现响应式设计和样式。 通过运行 以下命令 来安装 Bootstrap 及其依赖项:
    npm install bootstrap
  5. 安装完成后,您需要将 Bootstrap 的 CSS 文件添加到位于 Angular 项目根目录下 angular.json 配置文件中,该文件位于 ClientApp 文件夹内。 在此文件中,将以下代码中高亮显示的内容添加到 styles 数组:
    { „$schema\": „./node_modules/@angular/cli/lib/config/ schema.json\", \"version\": 1, \"newProjectRoot\": \"projects\", \"projects\": { \"ClientApp\": { \"projectType\": \"application\", \"schematics\": {}, \"root\": \"\", \"sourceRoot\": \"src\", \"prefix\": \"app\", \"architect\": { \"build\": { \"builder\": \"@angular-devkit/ build-angular:application\", \"options\": { \"outputPath\": \"dist/client-app\", \"index\": \"src/index.html\", \"browser\": \"src/main.ts\", \"polyfills\": [  \"zone.js\" ], \"tsConfig\": \"tsconfig.app.json\", \"assets\": [  { \"glob\": \"**/*\", \"input\": \"public\"  } ], \"styles\": [  \"src/styles.css\",  \"node_modules/bootstrap/dist/css/ bootstrap.min.css\" ], \"scripts\": [  \"node_modules/bootstrap/dist/js/  bootstrap.bundle.min.js\" ] }, \"configurations\": { \"production\": {  \"budgets\": [ {  \"type\": \"initial\",  \"maximumWarning\": \"500kB\",  \"maximumError\": \"1MB\" }, {  \"type\": \"anyComponentStyle\",  \"maximumWarning\": \"2kB\",  \"maximumError\": \"4kB\" }  ],  \"outputHashing\": \"all\" }, \"development\": {  \"optimization\": false,  \"extractLicenses\": false,  \"sourceMap\": true } }, \"defaultConfiguration\": \"production\" }, \"serve\": { \"builder\": \"@angular-devkit/ build-angular:dev-server\", \"configurations\": { \"production\": {  \"buildTarget\": \"ClientApp:build:production\" }, \"development\": {  \"buildTarget\": \"ClientApp:build:development\" } }, \"defaultConfiguration\": \"development\" }, \"extract-i18n\": { \"builder\": \"@angular-devkit/ build-angular:extract-i18n\" }, \"test\": { \"builder\": \"@angular-devkit/ build-angular:karma\", «options»: { «polyfills»: [  «zone.js»,  «zone.js/testing» ], «tsConfig»: «tsconfig.spec.json», «assets»: [  { «glob»: «**/*», «input»: «public»  } ], «styles»: [  «src/styles.css» ], «scripts»: [] } } } } }}

现在,Bootstrap 样式将在整个 Angular 项目中可用。 下一节中,我们将设置用于与后端服务集成的服务。

为 HTTP 请求创建服务

为了与 ASP.NET Core 后端进行 HTTP 请求交互,我们将创建两个服务:一个用于训练计划,一个用于健身目标。 这些服务将使用 HttpClient 与 API 端点通信。 让我们从 以下步骤开始:

  1. 首先,在 src/app 目录下创建一个名为 services 的文件夹,并创建文件 workout.service.ts ,该文件将包含向 Workout 端点发起后端 API 请求的必要逻辑。 创建文件后,添加 以下代码:
    import { Injectable } from \'@angular/core\';import { HttpClient } from \'@angular/common/http\';import { Observable } from \'rxjs\';export interface Workout { id: number; exercise: string; duration: number; date: Date; notes: string;}@Injectable({ providedIn: \'root\',})export class WorkoutService { private apiUrl = \'http://localhost:5124/api/workouts\'; constructor(private http: HttpClient) {} getWorkouts(): Observable { return this.http.get(this.apiUrl); } getWorkout(id: number): Observable { return this.http.get( `${this.apiUrl}/${id}` ); } createWorkout(workout: Workout): Observable { return this.http.post( this.apiUrl, workout ); } updateWorkout(id: number, workout: Workout): Observable { return this.http.put( `${this.apiUrl}/${id}`, workout ); } deleteWorkout(id: number): Observable { return this.http.delete( `${this.apiUrl}/${id}` ); }}

    上述代码定义了一个名为 WorkoutService 的 Angular 服务,用于管理 Angular 前端与后端 API 之间关于训练数据的通信。 该服务使用 HttpClient 向 API 发起 HTTP 请求。

    用于 HTTP 请求创建的 Workout 接口定义了锻炼对象的结构,其字段与后端 API 返回的字段相同。 这个 WorkoutService 类被 @Injectable({ providedIn: \'root\' }) 装饰器修饰,使其成为可在应用程序任何位置注入的单例服务。 以下是关于 WorkoutService 的进一步说明 :

    • apiUrl :后端 API 的 基础 URL
    • getWorkouts() :从 API 获取所有训练列表
    • getWorkout(id: number) :通过 ID 获取特定训练
    • createWorkout(workout: Workout) :发送 POST 请求以创建 新训练
    • updateWorkout(id: number, workout: Workout) :发送一个 PUT 请求,根据 其 ID 更新现有锻炼记录
    • deleteWorkout(id: number) :发送一个 DELETE 请求,通过 其 ID 删除锻炼记录

    该服务提供了通过 HTTP 请求 对锻炼记录执行 CRUD 操作的必要方法。

  2. 接下来,在同一个 services 文件夹中创建一个名为 goal.service.ts 的新文件,该文件将包含处理与健身目标操作相关的 API 请求的逻辑。 创建文件后,添加 以下代码:
    import { Injectable } from \'@angular/core\';import { HttpClient } from \'@angular/common/http\';import { Observable } from \'rxjs\';export interface FitnessGoal { id: number; goalName: string; description: string; targetDate: Date;}@Injectable({ providedIn: \'root\',})export class GoalService { private apiUrl = \'http://localhost:5124/api/fitnessgoals\'; constructor(private http: HttpClient) {} getGoals(): Observable { return this.http.get(this.apiUrl); } getGoal(id: number): Observable { return this.http.get( `${this.apiUrl}/${id}` ); } createGoal(goal: FitnessGoal): Observable { return this.http.post( this.apiUrl, goal ); } updateGoal(id: number, goal: FitnessGoal): Observable { return this.http.put( `${this.apiUrl}/${id}`, goal ); } deleteGoal(id: number): Observable { return this.http.delete( `${this.apiUrl}/${id}` ); }}

    前述代码 为 HTTP 请求创建的服务 GoalService 用于管理 Angular 前端与后端 API 之间的通信,以处理 FitnessGoal 数据。 类似于之前的 WorkoutService ,它使用 HttpClient 执行 HTTP 请求与 API 交互。 其中 FitnessGoal 接口定义了健身目标对象的结构,其属性与 后端规范 保持一致。

    以下是关于 GoalService 类的所有方法和属性的详细说明:

    • apiUrl :用于与健身 goals API 交互的基础 URL
    • getGoals() :从 API 获取所有健身目标
    • getGoal(id: number) : 根据 ID 获取特定健身目标
    • createGoal(goal: FitnessGoal) : 发送 POST 请求创建新的 健身目标
    • updateGoal(id: number, goal: FitnessGoal) : 发送 PUT 请求更新现有 健身目标
    • deleteGoal(id: number) : 发送 DELETE 请求通过 ID 删除健身目标

    该服务 为 HTTP 请求创建\"包含了通过 HTTP 请求对健身目标执行 CRUD 操作的所有必要方法,便于与 后端 API 进行交互。

下一节中,我们将了解需要为 健身 追踪器 应用程序创建哪些 Angular 组件

创建 Angular 组件

在本节中, 我们将重点创建 Fitness Tracker 健身追踪应用 的核心 Angular 组件。 通过为锻炼项目和健身目标创建独立组件,我们将把应用程序组织成可复用的模块。 这些组件将允许用户查看列表、添加新条目,以及编辑或删除现有的锻炼项目和健身目标。 在此过程中,我们还将集成 Bootstrap 以确保响应式 UI,首先从 下一节 中的目标表单组件开始。

创建目标表单组件

我们将首先 创建目标表单组件,该组件将通过提供带有标准表单字段的用户界面, 允许用户创建和更新健身目标。 要创建该组件,请执行 以下命令:

ng generate component components/goal-form

上述命令将在 src/app/components 目录下创建一个 goal-form 文件夹。在创建包含 Goal Form 组件默认文件的目录后,使用以下内容编辑 goal-form.component.ts 文件:

import { Component, OnInit } from \'@angular/core\';import { FormsModule } from \'@angular/forms\';import { FitnessGoal, GoalService} from \'../../services/goal.service\';import { ActivatedRoute, Router, RouterModule} from \'@angular/router\';@Component({ selector: \'app-goal-form\', standalone: true, templateUrl: \'./goal-form.component.html\', imports: [FormsModule, RouterModule]})export class GoalFormComponent implements OnInit { goal: FitnessGoal = { id: 0, goalName: \'\', description: \'\', targetDate: new Date() }; isEditMode: boolean = false; constructor( private goalService: GoalService, private router: Router, private route: ActivatedRoute ) {} ngOnInit(): void { const id = this.route.snapshot.paramMap.get(\'id\'); if (id) { this.isEditMode = true; this.goalService.getGoal(Number(id)).subscribe( data => { this.goal = data; }); } } saveGoal(): void { if (this.isEditMode) { this.goalService.updateGoal( this.goal.id, this.goal).subscribe(() => { this.router.navigate([\'/goals\']); }); } else { this.goalService.createGoal(this.goal).subscribe( () => { this.router.navigate([\'/goals\']); }); } }}

这段代码定义了 GoalFormComponent,这是一个负责处理健身目标创建与编辑的 Angular 组件。 它使用 FormsModule 来管理用户输入,并通过 RouterModule 处理路由间的导航 。

该组件被声明为独立组件,意味着它不依赖于 Angular 的 NgModule 系统。 它同时导入了 FormsModule (用于处理表单输入)和 RouterModule ( 用于导航)。

关于组件属性, goal 表示一个健身目标,已用默认值初始化。 而 isEditMode 属性是一个布尔标志,用于区分创建新目标和编辑 现有目标。

在依赖注入方面,该组件注入了 GoalService (用于处理后端通信)、 Router (用于表单提交后导航)以及 ActivatedRoute (用于获取路由参数 如 ID)。

在 ngOnInit 阶段,当组件初始化时,会检查路由参数中是否存在 ID。 如果存在,组件将切换到编辑模式并从服务中获取对应目标。 否则,保持 创建模式。

saveGoal 方法 负责处理目标的保存操作。 它会根据情况调用 updateGoal (编辑模式下)或 createGoal (创建模式)。 成功保存目标后,用户将被导航回 健身目标 列表页面。

该组件允许用户创建新的健身目标或编辑现有目标,是 应用程序 中目标管理功能的核心部分。

既然组件的逻辑已经创建完成,现在需要定义组件的 HTML 部分,以便在用户界面中显示必要的字段。 为此,请编辑 goal-form.component.html 文件,添加 以下代码:

{{ isEditMode ? \'Edit Goal\' : \'Add New Goal\' }}


Cancel

这段 HTML 代码定义了 Fitness Tracker 应用中创建和编辑健身目标表单的结构。 表单会根据 isEditMode 标志的值动态调整,该标志决定用户是添加新目标还是编辑现有目标。 表单包含目标名称、描述和截止日期字段,这些字段都通过 ngModel 与 Angular 组件中的相应属性进行双向数据绑定。 这确保用户所做的任何更改都会立即反映到组件的 goal 对象中。

当表单提交时,saveGoal() 这个 Angular 组件中的函数会被触发,根据当前模式处理目标的创建或更新。 表单还包含一个 Cancel 按钮,点击后会返回健身目标列表而不提交任何更改。Bootstrap 类用于表单样式设计,确保布局简洁且响应式,同时 ngSubmit 指令用于捕获表单提交事件。 该表单是应用程序中目标管理功能的核心部分,为用户提供了与健身目标交互的友好界面。

目标表单组件创建完成后,接下来需要在 以下部分创建用于列出健身目标的组件。

创建目标列表组件

我们将创建目标列表组件,该组件允许用户查看已注册的目标列表,并具备编辑或删除目标的功能。 要创建该组件,请执行以下命令:

ng generate component components/goal-list

此命令将在 src/app/components 目录下创建 goal-list 文件夹。 当目录创建完成并生成目标列表组件的默认文件后,请使用以下内容编辑 goal-list.component.ts 文件:

import { Component, OnInit } from \'@angular/core\';import { CommonModule } from \'@angular/common\';import { Router } from \'@angular/router\';import { GoalService, FitnessGoal} from \'../../services/goal.service\';@Component({ selector: \'app-goal-list\', standalone: true, templateUrl: \'./goal-list.component.html\', imports: [CommonModule],})export class GoalListComponent implements OnInit { goals: FitnessGoal[] = []; constructor(private goalService: GoalService, private router: Router) {} ngOnInit(): void { this.loadGoals(); } loadGoals(): void { this.goalService.getGoals().subscribe(data => { this.goals = data; }); } goToAddGoal(): void { this.router.navigate([\'/add-goal\']); } goToEditGoal(id: number): void { this.router.navigate([`/edit-goal/${id}`]); } deleteGoal(id: number): void { if (confirm( \'Are you sure you want to delete this goal?\')) { this.goalService.deleteGoal(id).subscribe(() => { this.loadGoals(); }); } }}

上述代码定义了 GoalListComponent,这是一个 Angular 组件,负责显示健身目标列表并提供添加、编辑或删除目标的操作功能。 该组件被设置为独立组件,意味着它直接导入依赖项而非通过 Angular 模块。 它使用 GoalService 来获取和操作数据,并通过 Router 处理不同页面间的导航。

在 ngOnInit() 生命周期方法中,会调用 loadGoals() 函数,该函数订阅服务的 getGoals() 方法来获取健身目标列表。 该组件包含用于导航至添加或编辑目标表单的方法(goToAddGoal() 和 goToEditGoal()),以及一个 deleteGoal() 函数,该函数会在调用服务删除目标前向用户确认操作。 删除操作完成后,目标列表会重新加载以反映变更。 该组件为 FitnessTracker 应用程序提供了管理健身目标的主要界面。

既然已完成目标列表组件的逻辑部分,现在可以定义该组件的展示部分来显示目标列表。 请编辑 goal-list.component.html 文件,使用以下代码:

Fitness Goals

Goal Name Description Target Date Actions
{{ goal.goalName }} {{ goal.description }} {{ goal.targetDate | date }}

上述 HTML 模板用于在目标列表组件中显示健身目标列表。 它采用 Bootstrap 进行样式设计,这有助于实现用户界面的响应式布局。 容器以标题( 健身目标 )和标有添加新目标的按钮开头,该按钮会触发 goToAddGoal() 方法,导航至创建新目标的表单页面。

表格结构 通过目标名称、描述、截止日期和可用操作( 编辑 和 删除 )的标题来组织数据。 模板使用 Angular 的 *ngFor 指令遍历目标列表,在相应的表格行中显示每个目标的详细信息。 编辑 按钮调用 goToEditGoal() 允许用户修改所选目标,而 删除 按钮触发 deleteGoal() 从列表中移除目标。 截止日期使用 Angular 的日期管道进行格式化,以便用户友好地显示。 该模板为用户提供了一种清晰且互动的方式来管理他们的 健身目标。

随着 目标列表 组件的创建完成,现在需要创建允许用户添加和编辑 训练数据 的组件。

创建 Workout Form 组件

在本节中,我们将创建 Workout Form 组件,该组件将通过提供包含标准表单字段的用户界面,允许用户创建和更新训练计划。 要创建该组件,请执行以下命令:

ng generate component components/workout-form

上述命令将在 src/app/components 目录中创建一个 workout-form 文件夹。 当目录创建完成并包含 Workout Form 组件的默认文件后,请使用以下内容编辑 workout-form.component.ts 文件:

import { Component, OnInit } from \'@angular/core\';import { FormsModule } from \'@angular/forms\';import { WorkoutService, Workout} from \'../../services/workout.service\'import { ActivatedRoute, Router, RouterModule} from \'@angular/router\'; // Import RouterModule@Component({ selector: \'app-workout-form\', standalone: true, templateUrl: \'./workout-form.component.html\', imports: [FormsModule, RouterModule], // Add  // RouterModule to  // imports})export class WorkoutFormComponent implements OnInit { workout: Workout = { id: 0, exercise: \'\', duration: 0, date: new Date(), notes: \'\' }; isEditMode: boolean = false; constructor( private workoutService: WorkoutService, private router: Router, private route: ActivatedRoute ) {} ngOnInit(): void { const id = this.route.snapshot.paramMap.get(\'id\'); if (id) { this.isEditMode = true; this.workoutService.getWorkout(Number(id)).subscribe( data => { this.workout = data; }); } } saveWorkout(): void { if (this.isEditMode) { this.workoutService.updateWorkout( this.workout.id, this.workout).subscribe(() => { this.router.navigate([\'/workouts\']); }); } else { this.workoutService.createWorkout(this.workout) .subscribe(() => { this.router.navigate([\'/workouts\']); }); } }}

上述代码定义了 WorkoutFormComponent,这是一个 Angular 组件,负责在 Fitness Tracker 应用中创建和编辑锻炼记录。 该组件是独立式的,意味着它直接导入所需模块(如用于处理表单输入的 FormsModule 和用于管理路由的 RouterModule),而非依赖于模块声明 。

该组件初始化时会使用默认的 Workout 对象,该对象包含以下字段:idexercisedurationdate 和 notes。 在 ngOnInit 生命周期方法中,会检查路由参数中是否存在 ID。 如果找到 ID,组件将切换到编辑模式,并从 WorkoutService 获取对应的训练详情。 若不存在 ID,组件则处于创建模式,允许用户添加新的训练记录。 saveWorkout() 方法根据当前模式处理创建和更新操作,通过与服务交互将数据发送至后端,并在操作 完成后将用户重定向至训练列表。

既然 Workout Form 组件的逻辑部分已完成,现在可以定义组件的展示部分来显示目标列表。 编辑 workout-form.component.html 文件,使用以下代码:

{{ isEditMode ? \'Edit Workout\' : \'Add New Workout\' }}


Cancel

上述代码在 Fitness Tracker 应用的 WorkoutFormComponent 中定义了一个用于添加或编辑锻炼详情的表单。 该表单会根据 isEditMode 标志动态调整,显示 Edit Workout 或 Add New Workout 作为标题,并相应地在提交按钮上切换显示 Update 和 Add。 该表单包含运动名称、持续时间(分钟)、日期和备注等字段,所有这些字段都通过 Angular 的双向数据绑定 Workout 对象绑定到组件中的通过 ngModel .

表单提交时会触发 saveWorkout() 方法,根据当前模式创建新训练计划或更新现有计划。 同时包含一个 Cancel 按钮,该按钮通过 routerLink 指令将用户导航回训练列表而不提交表单。 使用了 Bootstrap 类如 form-controlbtn-success 和 btn-secondary 来设计表单元素和按钮样式,确保用户界面简洁且响应式。

随着 训练表单 组件的创建完成,现在需要创建允许用户查看 已注册训练列表 的组件。

创建训练列表组件

我们将 创建 训练列表 组件,该组件允许用户查看已注册训练列表,并提供编辑或删除训练的功能。 要创建该组件,请执行 以下命令:

ng generate component components/workout-list

该命令将在 src/app/components 目录下创建一个 workout-list 文件夹。 当目录创建完成并包含 Workout List 组件的默认文件后,请编辑 workout-list.component.ts 文件,添加 以下内容:

import { Component, OnInit } from \'@angular/core\';import { CommonModule } from \'@angular/common\';import { Router } from \'@angular/router\';import { WorkoutService, Workout} from \'../../services/workout.service\';@Component({ selector: \'app-workout-list\', standalone: true, templateUrl: \'./workout-list.component.html\', imports: [CommonModule], // Add HttpClientModule here})export class WorkoutListComponent implements OnInit { workouts: Workout[] = []; constructor(private workoutService: WorkoutService, private router: Router) {} ngOnInit(): void { this.loadWorkouts(); } loadWorkouts(): void { this.workoutService.getWorkouts().subscribe(data => { this.workouts = data; }); } goToAddWorkout(): void { this.router.navigate([\'/add-workout\']); } goToEditWorkout(id: number): void { this.router.navigate([`/edit-workout/${id}`]); } deleteWorkout(id: number): void { if (confirm( \'Are you sure you want to delete this workout?\')) { this.workoutService.deleteWorkout(id).subscribe(() => { this.loadWorkouts(); }); } }}

上述代码定义了 WorkoutListComponent,这是一个 Angular 组件,负责在 Fitness Tracker 应用程序中显示训练列表并提供添加、编辑或删除训练的操作。 该组件是独立式的,意味着它直接导入所需的依赖项,例如用于基本 Angular 指令的 CommonModule。 该组件通过与 WorkoutService 交互来获取训练列表,并使用 Router 实现页面间导航。

在 ngOnInit() 生命周期方法中,调用 loadWorkouts() 函数通过 WorkoutService 从后端获取训练数据。 获取的训练数据存储在 workouts 数组中并显示在关联模板中。 该组件提供了导航至添加(goToAddWorkout())或编辑(goToEditWorkout())训练表单的方法。 其中 deleteWorkout() 方法会在调用服务删除选定训练前要求用户确认,并在删除成功后重新加载列表。 该组件为 Fitness Tracker 中的锻炼管理提供核心功能 .

随着 Workout List 组件逻辑部分的完成,我们现在可以定义组件的展示部分来显示目标列表。 使用 以下代码更新 workout-list.component.html 文件:

Workout List

Exercise Duration (minutes) Date Notes Actions
{{ workout.exercise }} {{ workout.duration }} {{ workout.date | date }} {{ workout.notes }}

上述 HTML 模板定义了 WorkoutListComponent 中用于显示锻炼列表的结构,该组件属于 Fitness Tracker 应用程序。 模板以一个容器开始,其中包含标题( Workout List )和一个标记为 Add New Workout 的按钮,该按钮会触发 goToAddWorkout() 方法,使用户能够导航至 添加 新锻炼项目 的表单页面。

组件中的表格用于组织训练数据,包含运动名称、时长、日期、备注和操作等表头。 通过 *ngFor 指令遍历 workouts 数组,将每条训练数据显示在独立的表格行中。 点击 Edit 按钮会触发 goToEditWorkout() 方法,允许用户跳转至编辑选定训练的表单页面;而 Delete 按钮则调用 deleteWorkout() 方法,在确认后从列表中移除对应训练记录。 训练日期通过 Angular 的日期管道进行格式化,确保用户友好的显示效果。 应用 Bootstrap 类来保证训练列表具有响应式且整洁的布局。

考虑到我们目前已创建了实现锻炼和健身目标所需的所有组件,下一节将展示如何调整主 App 组件以包含新页面的链接,并根据路由配置来显示相应组件。

适配应用组件

要实现 所有已创建的锻炼和健身目标组件之间的导航,需要定义一个包含这些组件链接并显示所选组件详情的容器组件。 为此,您可以修改项目 app.component.html 文件,该文件位于 src/app 目录下,并添加 以下代码:

 body, html { margin: 0; padding: 0; font-family: Arial, sans-serif; background-color: #f4f4f9; } .container { text-align: center; padding: 2rem; } h1 { font-size: 2.5rem; color: #333; } p { color: #666; font-size: 1.2rem; margin-bottom: 2rem; } .nav-links { display: flex; justify-content: center; gap: 2rem; } .nav-link { display: inline-block; padding: 1rem 2rem; background-color: #4a90e2; color: white; border-radius: 50px; text-decoration: none; font-size: 1.1rem; transition: background-color 0.3s ease; } .nav-link:hover { background-color: #357ab8; } .footer { margin-top: 3rem; color: #aaa; }

Fitness Tracker App - Packt Book

Track your workouts and fitness goals to stay on top of your progress!

上述代码为 Fitness Tracker 应用程序的主页提供了样式和布局。CSS 定义了页面的外观,确保采用响应式布局实现简洁现代的设计。 其中 body 和 html 元素去除了默认的边距和内边距以消除浏览器默认间距,并统一使用 Arial 字体保证可读性。 页面背景色设置为浅灰色(#f4f4f9),形成柔和的中性背景。 .container 类使页面内容居中显示,而 h1 和 元素则定义了应用的标题和介绍文本,并通过合适的字体大小和颜色进行样式设计 以实现对比效果。

导航部分采用 .nav-links 类样式,显示两个按钮: Workouts 和 Fitness Goals ,它们通过 flexbox 居中排列。 每个按钮都设置了内边距、蓝色背景、白色文字和圆角,呈现出精致的按钮外观。 当用户悬停在链接上时, .nav-link 类的悬停效果会使背景颜色变暗, 从而增强交互性。

考虑到主页面已配置完成,现在该配置应用程序的实际路由并在 下一节中测试应用了。

配置路由

在本节中, 我们将为 Fitness Tracker 应用程序配置路由,以实现不同组件间的导航。Angular 的 RouterModule 允许我们将 URL 映射到组件,当用户在训练列表、训练表单、目标列表和目标表单等视图间切换时,能获得流畅的体验。

要设置路由,我们需要在 app.routes.ts 文件中定义路由,该文件位于 src/app 目录下。 每个路由都关联一个组件,当用户导航到相应 URL 时将渲染该组件。 例如,我们将有用于显示锻炼列表、添加新锻炼和编辑现有锻炼的路由,以及类似的健身目标路由。 以下是需要在 app.routes.ts 文件中配置的路由:

import { Routes } from \'@angular/router\';import { WorkoutListComponent} from \'./components/workout-list/workout-list.component\';import { WorkoutFormComponent} from \'./components/workout-form/workout-form.component\';import { GoalListComponent} from \'./components/goal-list/goal-list.component\';import { GoalFormComponent} from \'./components/goal-form/goal-form.component\';export const routes: Routes = [ { path: \'workouts\', component: WorkoutListComponent }, { path: \'add-workout\', component: WorkoutFormComponent }, { path: \'edit-workout/:id\', component: WorkoutFormComponent }, { path: \'goals\', component: GoalListComponent }, { path: \'add-goal\', component: GoalFormComponent }, { path: \'edit-goal/:id\', component: GoalFormComponent }, { path: \'\', redirectTo: \'/workouts\', pathMatch: \'full\' },];

每条路由都由路径及其对应的组件定义。 例如,当用户导航至 /workouts 路径时,会渲染 WorkoutListComponent 组件来显示训练列表。 同理,/add-workout 路径会显示 WorkoutFormComponent 组件,允许用户创建新训练。 动态路由 /edit-workout/:id 包含一个参数(:id),用于指定待编辑训练的唯一标识。 健身目标也遵循这一模式,路径包括 /goals 用于列出目标, /add-goal 用于添加新目标,以及 /edit-goal/:id 用于编辑 现有目标。

数组中的最后一条路由是重定向路由。 当应用程序通过基础 URL(\'\')访问时,它会自动将用户重定向至 /workouts,默认显示训练列表。 这确保了用户在打开应用时拥有明确的入口点。 总体而言,该路由配置为用户管理训练和健身目标提供了核心导航结构。

所有配置完成后,现在需要同时运行 Angular 和 ASP.NET Core Web API 应用程序。

运行演示应用程序

在本节中,我们将逐步讲解如何使用 Visual Studio 运行 Fitness Tracker 应用程序的 ASP.NET Core 后端和 Angular 前端。 由于这是一个全栈解决方案,您需要同时运行两个部分才能完整测试应用程序。 让我们从以下步骤开始:

  1. 首先,点击 Visual Studio 中的运行按钮(或按 F5 键)。 这将启动后端服务,默认情况下通常运行在 http://localhost:5124。 您可以通过在浏览器中访问该 URL 来验证 API 是否正常运行。
  2. 之后,您需要同时运行前端和后端。 为此,请在 Visual Studio 中打开一个新的终端或 CMD 窗口,导航至 Angular 项目的根目录(即 ClientApp 文件夹),然后执行 以下命令:
    ng serve

    这将启动 Angular 开发服务器,通常 运行在 http://localhost:4200 .

  3. 打开你的浏览器,访问 http://localhost:4200 以查看应用程序。Angular 前端将与运行在 http://localhost:5124 的后端 API 通信。当后端和前端都运行时,你应该能在浏览器中看到健身追踪应用程序的初始页面,如图 13.5 所示。

图13.5:健身追踪器应用的主页

首页 底部显示一个表格,列出已注册的锻炼项目,顶部则有链接指向 锻炼 和 健身目标 页面。 WorkoutListComponent 之所以显示,是因为路由配置为当访问应用程序根路径时展示该组件。

如果点击 添加新锻炼 按钮,系统将跳转至 锻炼表单 页面,如 图 13 .6 所示。

 

图13.6:锻炼表单

填写完表单并输入任意测试数据后,您可以通过点击添加训练按钮进行保存。 随后系统将跳转至训练列表页面,显示新创建的训练记录,其配置与之前在 WorkoutFormComponent 中设置的完全一致。 具体效果如图 13.7 所示。

 

图13.7:训练列表

如您在训练列表页面所见,新增的训练项目已显示在表格中,并提供编辑删除选项。 您也可以尝试健身目标相关功能并查看结果。

通过同时运行后端和前端,您可以看到 Fitness Tracker 应用程序的全部潜力。 我们整合了 Angular 和 ASP.NET Core 中的核心工具与功能,通过路由、双向数据绑定、HTTP 客户端、Bootstrap 以及独立的 Angular 组件,提供了功能完善且视觉吸引的解决方案。 我们还创建了控制器来定义处理 HTTP 请求的 API 端点,并利用 ASP.NET Core 内置的依赖注入功能,将 WorkoutService 和 FitnessGoalService 等服务注入到控制器中。

您已掌握如何将 Angular 与 ASP.NET Core 集成,并配置好日常 全栈应用程序所需的一切。

摘要

在本章中,我们构建了一个全栈的 健身追踪器 应用,结合了后端的 ASP.NET Core 和前端的 Angular。 我们首先使用 ASP.NET Core 开发了一个健壮的 API,包含控制器和服务来管理锻炼和健身目标数据。 在前端,我们创建了 Angular 组件,使用户能够与 API 交互,运用了路由、双向数据绑定和 HTTP 客户端服务等功能来管理条目。 此外,我们还探索了使用 Bootstrap 进行样式设计,并通过 Angular 的 RouterModule 实现无缝导航。 .

这些技能是开发现代全栈应用程序的关键,使开发者能够在提供流畅用户体验的同时保持可靠的后端服务。 理解如何将 Angular 等前端框架与 ASP.NET Core 后端连接起来,构成了可扩展、可维护应用程序的基础,这些应用程序能够高效地管理 数据。

接下来,我们将运用目前所学的技能将 React 与 ASP.NET Core 集成,继续探索不同 JavaScript 框架在全栈开发中的应用。 下一章将扩展你现有的知识,引入 React 特有的概念,并增强你在 前后端集成方面的能力。