将代码添加到 Blazor 静态 SSR 页面
在网页的 HTML 标记中,Razor 语法由 @ 符号表示。Blazor 静态 SSR 页面可以描述如下:
- Blazor 静态 SSR 页面需要在文件顶部添加 @page 指令,并指定一个字符串值作为路由,例如 "/" 或 "/customers" 。
警告!Blazor 静态 SSR 页面与 Razor 页面和 Razor 视图(用于 ASP.NET Core MVC)不同,但它们共享相同的 Razor 语法。Blazor 组件的文件扩展名为 .razor 。Razor 页面和 Razor 视图的文件扩展名为 .cshtml 。Razor 页面必须具有 @page 指令。Razor 视图不得使用 @page 指令。
- Blazor 静态 SSR 页面可以选择性地具有一个 @code 部分,该部分定义了用于存储数据值的属性,类似于类定义。然后,您可以在 HTML 中获取属性值。
- Blazor 静态 SSR 页面标记可以使用 @* 和 *@ 添加注释,如以下代码所示: @* This is a comment. *@ 。
现在让我们使用 @code 块向 Blazor 静态 SSR 页面添加一些动态内容:
- 在 Components/Pages 文件夹中,在 Index.cshtml ,在 @page 指令之后,添加一个 @code 语句块以定义一个属性,用于存储当前日期的名称作为 string 值,如以下代码所示:
@page "/"
@code
{
public string? DayName { get; set; }
= DateTime.Now.ToString("dddd");
}
在第二个 HTML 段落中, <p> ,渲染日期名称,如以下标记中突出显示的那样:
<p>It's @DayName! Our customers include restaurants, hotels, and cruise lines.</p>
- 使用 https 配置文件启动网站项目。
- 在 Chrome 中,如有必要,输入 https://localhost:5131/ ,并注意当前的日期名称在页面上输出,如图 13.5 所示:
- 在 Chrome 中,输入 https://localhost:5131/index.xhtml ,这正好与静态文件名匹配,并注意它返回的静态 HTML 页面与之前相同。
- 在 Chrome 中,输入 https://localhost:5131/env ,这正好匹配返回纯文本的端点路由,并注意它返回的纯文本与之前相同。
- 关闭 Chrome 并关闭网络服务器。
使用共享布局与 Blazor 静态 SSR 页面
大多数网站都有多个页面。当前在 Index.razor 中的网页主体的基本标记是最小的。通常,主体中会有需要在每个页面上可见的公共标记。如果每个页面都必须重复该标记,那么管理起来就会变得很麻烦。因此,ASP.NET Core 有一个名为布局的功能。
要使用布局,我们必须创建一个 Razor 文件来定义所有 Blazor 组件的默认布局,并在 Routes 组件中指定它。根据惯例,我们将其存储在 Layout 文件夹中。这个文件的名称可以是任何名称,因为我们将指定它,但 MainLayout.razor 是一个良好的实践。
通常,您的主布局将包括一个导航菜单,其中包含指向所有其他 Blazor 页面组件的链接。此文件的命名约定为 NavMenu.razor 。
让我们看看布局的实际应用:
- 在 Components 文件夹中,添加一个名为 Layout 的新文件夹。
- 在 Layout 文件夹中,添加一个名为 NavMenu.razor 的文件。
- 在 NavMenu.razor 中,修改内容,如下标记所示:
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="#">Northwind Web</a>
<button class="navbar-toggler" type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarNavAltMarkup"
aria-controls="navbarNavAltMarkup"
aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse"
id="navbarNavAltMarkup">
<div class="navbar-nav">
<NavLink class="nav-link" href="/">
Home
</NavLink>
<NavLink class="nav-link" href="suppliers">
Suppliers
</NavLink>
</div>
</div>
</div>
</nav>
更多信息:此标记使用了一个名为 navbar 的 Bootstrap 特性,您可以在以下链接中阅读相关内容:https://getbootstrap.com/docs/5.3/components/navbar/.
- 在 Layout 文件夹中,添加一个名为 MainLayout.razor 的文件。
- 在 MainLayout.razor 中,修改内容,如下标记所示:
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<article class="content px-4">
@Body
</article>
</main>
<!-- JavaScript to enable features like carousel -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
</div>
在审查前面的标记时,请注意以下事项:
- @Body 标记了请求的 Blazor 页面组件的插入点。
- 在布局的底部有一个脚本,用于实现一些我们可以稍后使用的 Bootstrap 酷炫功能,例如图像轮播。
- 在 Routes.razor 中,添加一个属性以设置默认布局的类名,如以下标记中突出显示的那样:
<Router AppAssembly="typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="routeData"
DefaultLayout="typeof(Layout.MainLayout)" />
</Found>
</Router>
- 使用 https 启动配置文件启动网站。
- 使用 Chrome 访问它,并注意到现在每个页面的顶部都有一个导航菜单,如图 13.6 所示:
警告!点击供应商的导航菜单将出现 404 Not Found 错误,因为我们尚未创建该 Blazor 页面组件。
- 关闭 Chrome 并关闭网络服务器。
创建供应商页面
您现在将创建一个 Blazor 静态 SSR 页面组件,显示供应商列表。在下一个主题中,我们将从数据库加载供应商列表,但现在我们将用一个硬编码的 string 值数组来模拟这一点:
- 在 Pages 文件夹中,添加一个名为 Suppliers.razor 的新 Blazor 页面组件。如果您使用的是 Visual Studio 或 Rider,则项目项模板名为 Razor 组件。
- 在 Suppliers.razor 中,用标记替换现有内容,以呈现包含供应商公司名称的 HTML 表格,如以下标记所示:
@page "/suppliers"
@code {
public IEnumerable<string>? Companies { get; set; }
= new[] { "Alpha Co", "Beta Limited", "Gamma Corp" };
}
<div class="row">
<h1 class="display-2">Suppliers</h1>
<table class="table">
<thead class="thead-inverse">
<tr>
<th>Company Name</th>
</tr>
</thead>
<tbody>
@if (Companies is not null)
{
@foreach(string name in Companies)
{
<tr>
<td>@name</td>
</tr>
}
}
</tbody>
</table>
</div>
在审查前面的标记时,请注意以下事项:
- Suppliers 属性被填充了一些来自 string 值数组的示例供应商公司名称。稍后,我们将从 Northwind 数据库中填充此内容。
- 该页面输出一个带有 Bootstrap 样式的 HTML 表格。
- 该页面使用 Razor 语法 @if 和 @for 语句将 C#代码嵌入 HTML 中。
- 表格中的数据行是通过循环遍历 Suppliers 属性生成的,如果它不是 null 。
- 使用 https 启动配置启动网站,并使用 Chrome 访问它。
- 点击按钮以了解更多关于供应商的信息,并注意供应商表,如图 13.7 所示:
配置 ASP.NET Core 项目中包含的文件
到目前为止,我们的大多数项目都是简单的控制台应用程序和类库,包含一些 C# 类文件。默认情况下,当我们编译这些项目时,项目文件夹或子文件夹中的所有 .cs 文件在编译时会自动包含在构建中。
ASP.NET Core 项目变得更加复杂。文件类型增多;其中一些可以在运行时编译而不是编译时编译,还有一些只是内容,不需要编译,但需要与已编译的程序集一起部署。
您可以通过在项目文件中放置元素来控制在构建过程中如何处理文件,以及哪些文件包含或排除在部署中。这些文件在构建和部署过程中由 MS Build 和其他工具处理。
您在项目文件中将项目声明为 <ItemGroup> 元素的子元素。例如:
<--Include the greet.proto file in the build process.-->
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
<--Remove the stylecop.json file from the build process.-->
<ItemGroup>
<None Remove="stylecop.json" />
</ItemGroup>
<--Include the stylecop.json file in the deployment.-->
<ItemGroup>
<AdditionalFiles Include="stylecop.json" />
</ItemGroup>
您可以根据需要拥有任意数量的 <ItemGroup> 元素,因此使用它们按类型逻辑地划分元素是一个好习惯。它们会被构建工具自动合并。
通常,当您知道需要使用这些元素时,您会手动添加它们,但不幸的是,Visual Studio 和其他代码编辑器有时会通过试图提供帮助而搞砸事情。
在一种情况下,您可能在 Components\Pages 文件夹中添加了一个名为 Customers.razor 的新 Blazor 组件。您启动了 web 服务器,但页面没有出现。或者,您正在开发一个 GraphQL 服务,并添加了一个名为 seafoodProducts.graphql 的文件,但当您运行 GraphQL 工具以自动生成客户端代理时,它失败了。
这两种情况都是您代码编辑器决定新文件不应成为项目的一部分的常见指示。它已自动向项目文件添加了一个元素,以在未告知您的情况下将该文件从构建过程中移除。
要解决此类问题,请检查项目文件中是否有以下意外条目,并将其删除:
<ItemGroup>
<Content Remove="Components\Pages\Customers.razor" />
</ItemGroup>
<ItemGroup>
<GraphQL Remove="seafoodProducts.graphql" />
</ItemGroup>
良好实践:在使用自动“修复”问题的工具时,当出现意外结果时,请检查您的项目文件以查找意外元素。
更多信息:您可以通过以下链接阅读有关管理 MS Build 项目的更多信息:https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-items。
项目文件构建操作
正如我们刚刚看到的,ASP.NET Core 开发人员理解项目构建操作如何影响编译是很重要的。
.NET SDK 项目中的所有文件都有一个构建操作。大多数是根据文件扩展名隐式设置的。您可以通过显式设置构建操作来覆盖默认行为。您可以通过直接编辑 .csproj 项目文件或使用代码编辑器的属性窗口来执行此操作。
ASP.NET Core 项目文件的常见构建操作如表 13.2 所示:
生成操作 | 描述 |
编译或 C#编译器 | 作为源文件传递给编译器。 |
内容 | 作为网站部署的一部分包含在内。 |
嵌入式资源 | 作为资源传递给编译器,以嵌入到程序集中的。 |
翻译文本:无 | 不属于构建的一部分。此值可用于文档和其他不应与网站一起部署的文件。 |
表 13.2:ASP.NET Core 项目文件的常见构建操作
更多信息:您可以通过以下链接了解有关构建操作和 .csproj 条目的更多信息:https://learn.microsoft.com/en-us/visualstudio/ide/build-actions。
使用 Entity Framework Core 和 ASP.NET Core
实体框架核心是将真实数据引入网站的自然方式。在第 12 章《使用 .NET 介绍现代 Web 开发》中,您创建了一对类库(一个用于实体模型,一个用于 Northwind 数据库上下文),使用 SQLite 作为数据提供程序(或 SQL Server)。您现在将在您的网站项目中使用它们。
将实体框架核心配置为服务
在网站启动期间,ASP.NET Core 项目所需的功能,例如 Entity Framework Core 数据库上下文,应作为依赖服务进行注册。GitHub 仓库解决方案中的代码以及下面的代码使用 SQLite,但如果您更喜欢,可以轻松使用 SQL Server。
让我们看看如何:
- 在 Northwind.Web 项目中,为 Northwind.DataContext 项目添加对 SQLite 或 SQL Server 的项目引用,如下所示:
<!-- Change Sqlite to SqlServer if you prefer. -->
<ItemGroup>
<ProjectReference Include="..\Northwind.DataContext.Sqlite\
Northwind.DataContext.Sqlite.csproj" />
</ItemGroup>
警告!项目引用必须全部在一行内,不能换行。
- 构建 Northwind.Web 项目。
- 在 Program.cs 中,导入命名空间以处理您的实体模型类型,如以下代码所示:
using Northwind.EntityModels; // To use AddNorthwindContext method.
在 Program.cs 中,在添加 Razor 组件到注册服务的语句之后,添加一条语句以注册 Northwind 数据库上下文类,如下代码所示:
builder.Services.AddNorthwindContext();
在 Components 文件夹中,在 _Imports.razor 中,导入我们数据库上下文的命名空间,如下代码所示:
@using Northwind.EntityModels @* To use NorthwindContext. *@
在 Components\Pages 文件夹中,在 Suppliers.razor 中,注入 Northwind 上下文服务的实例,如以下代码所示:
@inject NorthwindContext _db
将 Companies 属性声明为一系列 Supplier 对象,而不是 string 值,如以下代码中突出显示的那样:
public IEnumerable<Supplier>? Companies { get; set; }
定义一个 OnInitialized 方法,以使用来自 Northwind Suppliers 表的数据设置 Companies 属性,如以下代码所示:
protected override void OnInitialized()
{
Companies = _db.Suppliers
.OrderBy(c => c.Country)
.ThenBy(c => c.CompanyName);
}
修改标记以为每个供应商呈现多个列,如以下标记中突出显示的内容所示:
<table class="table">
<thead class="thead-inverse">
<tr>
<th>Company Name</th>
<th>Country</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
@if (Model.Suppliers is not null)
{
@foreach(Supplier s in Companies)
{
<tr>
<td>@s.CompanyName</td>
<td>@s.Country</td>
<td>@s.Phone</td>
</tr>
}
}
</tbody>
</table>
</div>
- 使用 https 启动配置文件启动网站并访问网站主页。
- 点击了解更多关于我们的供应商,并注意到 Suppliers 表现在从数据库加载,数据首先按国家排序,然后按公司名称排序,如图 13.8 所示:
在下一章中,我们将实现一个具有交互性的 Blazor 网站,以便我们可以轻松修改数据并显示它。