【ASP.NET Core 基础知识】--MVC框架--Views和Razor语法

一、Views和Razor语法基础

1.1 Views概述

在ASP.NET Core的MVC(Model-View-Controller)框架中,View 扮演着呈现用户界面的角色。View负责展示应用程序的数据给用户,并接收用户的输入。它与Model和Controller协同工作,通过模型绑定从Controller获取数据,然后使用Razor语法或其他视图引擎将数据呈现为用户可见的HTML。

  1. 视图的作用

    • 数据呈现: 主要职责是将数据从Controller层传递到用户界面,展示给用户。这包括显示数据库查询结果、业务逻辑计算的输出等。
    • 用户交互: Views能够接收用户的输入,并将用户的请求传递给Controller层进行处理。这使得用户能够与应用程序进行交互,例如填写表单、点击按钮等。
  2. Razor语法
    在ASP.NET Core中,主要使用Razor作为默认的视图引擎。Razor语法是一种简洁且强大的语法,它允许在HTML中嵌入C#代码,使得在视图中能够方便地处理数据和逻辑。以下是Razor语法的一些基本特征:

    • 代码块: 使用 @ 符号表示C#代码块,可以在HTML中嵌入C#逻辑。
      <p>Total items: @Model.Items.Countp>
      
    • 变量和表达式: 使用 @ 符号表示C#表达式,可以直接在HTML中输出变量的值。
      <p>Welcome, @User.Name!p>
      
    • 循环和条件语句: 使用C#的循环和条件语句来实现动态的HTML生成。
      @foreach (var item in Model.Items)
      {
          <li>@item.Nameli>
      }
      
  3. 视图文件结构
    在ASP.NET Core中,Views通常存放在项目的特定文件夹中(例如Views文件夹),并按照Controller的结构进行组织。每个Controller都有一个对应的文件夹,其中包含该Controller的所有视图。

  4. 视图布局
    Views支持布局,可以使用主布局文件(_Layout.cshtml)定义整个应用程序的共同结构。通过使用布局,可以实现页面的一致性和重用。

DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title - My ASP.NET Core Apptitle>
head>
<body>
    <div id="header">
        
    div>

    <div id="main">
        @RenderBody()
    div>

    <div id="footer">
        
    div>
body>
html>
1.2 Razor语法简介
  1. Razor语法的优势
    Razor语法在ASP.NET Core中被广泛采用,并具有多个优势,使其成为一种强大且受欢迎的视图引擎。以下是Razor语法的一些主要优势:

    • 简洁性和可读性: Razor语法以简洁的方式嵌入在HTML中,使得视图代码更加清晰易读。与传统的ASP.NET Web Forms相比,Razor语法减少了视图文件中的冗余标记,提高了可维护性。
    	   <p>Welcome, @User.Name!p>
    
    • 混编性: Razor语法允许在HTML中嵌入C#代码,实现了前端与后端逻辑的混编。这使得在视图中可以直接访问后端的数据和逻辑,简化了数据呈现和处理的流程。
       <p>Total items: @Model.Items.Countp>
    
    • 强大的代码块支持: Razor语法支持C#代码块,包括条件语句、循环语句等。这使得在视图中可以轻松实现动态内容的生成。
       @if (User.IsAuthenticated)
       {
           <p>Welcome back, @User.Name!p>
       }
    
    • 自动HTML编码: Razor自动对输出进行HTML编码,防止了常见的跨站脚本攻击(XSS)。这意味着在视图中输出的内容默认会被转义,提高了安全性。
       <p>@Model.HtmlContentp>
       
    
    • 强大的模型绑定: Razor语法与MVC框架深度集成,支持强大的模型绑定功能。这使得在视图中能够方便地访问Controller传递的数据。
       <p>Total items: @Model.Items.Countp>
    
    • 良好的扩展性: Razor语法是可扩展的,可以通过自定义标签助手(Tag Helpers)等方式扩展其功能。这使得开发者能够根据需要进行定制,以适应特定的项目要求。
       <my-custom-tag helper-attribute="value">Contentmy-custom-tag>
    
  2. Razor语法的基本结构
    Razor语法是在HTML中嵌入C#代码的一种方式,具有简洁且直观的语法结构。以下是Razor语法的基本结构:

    • 输出表达式:使用 @ 符号,后跟C#表达式,将其输出到HTML页面。
    <p>Welcome, @User.Name!p>
    

    这里 User.Name 是一个C#表达式,它的值会被自动输出到HTML中。

    • 代码块:使用 @{ } 包裹C#代码块,可以在其中编写多行代码。
    @if (User.IsAuthenticated)
    {
        <p>Welcome back, @User.Name!p>
    }
    else
    {
        <p>Please log in.p>
    }
    
    • 循环和条件语句:Razor支持常见的C#循环和条件语句,可以在HTML中嵌套使用。
    @foreach (var item in Model.Items)
    {
        <li>@item.Nameli>
    }
    
    @if (Model.Items.Count == 0)
    {
        <p>No items available.p>
    }
    
    • 注释:Razor支持单行和多行注释,使用 @**@
    
    
    @* 这是Razor注释 *@
    
    • 嵌套:在Razor中,可以嵌套HTML和C#代码,创建动态的HTML结构。
    <div>
        <h2>@Model.Titleh2>
        <ul>
            @foreach (var item in Model.Items)
            {
                <li>@item.Nameli>
            }
        ul>
    div>
    
    • 部分视图:使用 @RenderSection@section 可以在布局文件中定义和渲染部分视图。
      • 布局文件(_Layout.cshtml):
      DOCTYPE html>
      <html>
      <head>
          <title>@ViewBag.Title - My ASP.NET Core Apptitle>
      head>
      <body>
          <div id="main">
              @RenderBody()
              @RenderSection("scripts", required: false)
          div>
      body>
      html>
      
      • 页面文件:
      @section scripts {
          <script>
              // JavaScript code specific to this view
          script>
      }
      

这样,部分视图中定义的内容将被嵌入到布局文件中相应的位置。

二、Razor语法深入理解

2.1 Razor中的代码块
  1. 代码注释
    在Razor中,你可以使用两种方式进行注释:单行注释和多行注释。以下是它们的示例:
    • 单行注释:使用 @**@ 将代码行或代码块注释掉。
    @* 这是单行注释 *@
    <p>Welcome, @User.Name!p>
    
    • 多行注释:使用 进行多行注释,类似于HTML注释:
    
    <p>Welcome, @User.Name!p>
    

在Razor中,这两种注释方式都是有效的,并根据需要选择适当的注释形式。注释对于在代码中添加解释或标记暂时不需要的代码块是很有用的。

  1. 变量和表达式
    在Razor中,你可以使用 @ 符号来嵌入C#变量和表达式,将它们输出到HTML中。以下是变量和表达式的基本用法:
    • 变量:使用 @ 符号后跟变量名,将其输出到HTML中:
    <p>Welcome, @User.Name!p>
    
    在这个例子中,User.Name 是一个C#变量,其值将被嵌入到HTML中。
    • 表达式:使用 @ 符号后跟C#表达式,将其输出到HTML中。
    <p>Total items: @Model.Items.Countp>
    
    在这个例子中,Model.Items.Count 是一个C#表达式,它的值会被输出到HTML中。
    • 字符串拼接:你也可以在HTML中使用 + 来连接字符串:
    <p>@("Hello, " + User.Name + "!")p>
    
    • HTML编码:Razor默认对输出进行HTML编码,防止跨站脚本攻击(XSS)。这意味着特殊字符将被转义,确保安全性。
    <p>@Model.HtmlContentp>
    
    

Tip:默认情况下Razor会进行HTML编码,确保输出的内容不会引起安全问题。

  1. 控制流语句
    在Razor中,你可以使用C#的控制流语句,如条件语句 (if, else if, else) 和循环语句 (for, foreach, while),以便在视图中根据不同的条件生成不同的HTML内容。以下是一些示例:
    • 条件语句

      • if 语句
      @if (User.IsAuthenticated)
      {
          <p>Welcome back, @User.Name!p>
      }
      else
      {
          <p>Please log in.p>
      }
      
      • else if 语句
      @if (Model.Status == "Active")
      {
          <p>The account is active.p>
      }
      else if (Model.Status == "Inactive")
      {
          <p>The account is inactive.p>
      }
      else
      {
          <p>The account status is unknown.p>
      }
      
    • 循环语句

      • foreach 语句
      <ul>
          @foreach (var item in Model.Items)
          {
              <li>@item.Nameli>
          }
      ul>
      
      • for 语句
      	<ul>
      	    @for (int i = 0; i < Model.Items.Count; i++)
      	    {
      	        <li>@Model.Items[i].Nameli>
      	    }
      	ul>
      	```
      
      
    • 其他控制流语句

      • switch 语句
      @switch (Model.Status)
      {
          case "Active":
              <p>The account is active.p>
              break;
          case "Inactive":
              <p>The account is inactive.p>
              break;
          default:
              <p>The account status is unknown.p>
              break;
      }
      
      • while 语句
      @{
          int i = 0;
          while (i < 5)
          {
              <p>Iteration @ip>
              i++;
          }
      }
      

这些控制流语句使得在Razor视图中可以根据不同的条件生成不同的HTML内容,从而实现动态的页面呈现。

2.2 Razor中的HTML辅助方法

在ASP.NET Core中,Razor视图引擎提供了一些内置的HTML辅助方法(HTML Helpers),这些方法简化了在视图中生成HTML元素的过程。HTML辅助方法使得在Razor视图中以更简洁的方式生成常见的HTML元素和表单控件。以下是一些常用的HTML辅助方法:

  1. Html.ActionLink
    ActionLink 用于生成超链接,链接到指定的Controller和Action。
@Html.ActionLink("Click me", "About", "Home")
  1. Html.DisplayNameForHtml.DisplayFor
    这对方法用于显示模型的属性名和属性值。
@Html.DisplayNameFor(model => model.Name)
@Html.DisplayFor(model => model.Name)
  1. Html.EditorForHtml.TextBoxFor
    用于生成文本框,EditorFor 会根据模型类型选择适当的编辑器。
@Html.EditorFor(model => model.UserName)
@Html.TextBoxFor(model => model.UserName)
  1. Html.DropDownListFor
    生成下拉列表。
@Html.DropDownListFor(model => model.Country, new SelectList(Model.Countries, "Value", "Text"), "Select Country")
  1. Html.CheckBoxForHtml.CheckBox
    生成复选框。
@Html.CheckBoxFor(model => model.IsAdmin)
@Html.CheckBox("isAdmin", true)
  1. Html.RadioButtonForHtml.RadioButton
    生成单选按钮。
@Html.RadioButtonFor(model => model.Gender, "Male") Male
@Html.RadioButton("gender", "Female", true) Female
  1. Html.TextAreaFor
    生成文本区域。
@Html.TextAreaFor(model => model.Comments, new { rows = 4, cols = 40 })
  1. Html.ValidationMessageFor
    显示模型属性的验证消息。
@Html.ValidationMessageFor(model => model.UserName)

这些HTML辅助方法使得在Razor视图中生成HTML元素更为方便和可维护。通过利用这些方法,可以减少手动编写HTML元素的工作,同时提高代码的可读性和可重用性。

三、Views的创建和布局

3.1 创建Views文件

在ASP.NET Core中,创建Views文件通常是在MVC(Model-View-Controller)模式中的Views文件夹下的特定位置。以下是一般的步骤:

  1. 确保存在Views文件夹: 在ASP.NET Core项目中,确保在项目的根目录下有一个名为Views的文件夹。如果没有,你可以手动创建。
  2. 按Controller组织Views: Views文件夹中通常包含与Controller对应的文件夹,每个Controller文件夹中包含该Controller相关的视图文件。例如,如果有一个名为HomeController的Controller,那么在Views文件夹下应该有一个名为Home的文件夹。
  3. 创建具体的视图文件: 在Controller对应的文件夹中,你可以创建具体的视图文件,这些文件的命名通常与Controller的Action方法对应。例如,如果有一个名为Index的Action方法,那么在Views/Home文件夹下就可以创建一个名为Index.cshtml的文件。
    下面是一个示例:
    假设有一个名为HomeController的Controller,其中有一个名为Index的Action方法。
  4. Views文件夹下创建Home文件夹:
    /Views
    /Home
    
  5. Home文件夹下创建Index.cshtml
    /Views
       /Home
          /Index.cshtml
    

Index.cshtml中,你可以编写HTML和Razor代码来构建具体的页面内容。

这样,当访问HomeControllerIndex方法时,MVC框架会自动查找并渲染Views/Home/Index.cshtml文件中的内容。这种组织结构使得视图文件与Controller的关系更加清晰,方便了项目的维护和扩展。

3.2 Views的布局
  1. 主布局文件
    在ASP.NET Core中,主布局文件通常是整个应用程序中的顶层布局,它定义了整个站点的基本结构和外观。这个主布局文件在项目中被称为 _Layout.cshtml,位于Views/Shared文件夹下。以下是一个简单的 _Layout.cshtml 的示例:
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewBag.Title - My ASP.NET Core Apptitle>

    
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    
head>
<body>
    <div class="container">
        <header>
            <h1>My ASP.NET Core Apph1>
            <nav>
                <ul>
                    <li><a asp-area="" asp-controller="Home" asp-action="Index">Homea>li>
                    <li><a asp-area="" asp-controller="Home" asp-action="About">Abouta>li>
                    
                ul>
            nav>
        header>

        <main>
            @RenderBody()
        main>

        <footer>
            
        footer>
    div>

    
    <script src="~/lib/jquery/dist/jquery.min.js">script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js">script>
    
body>
html>

在这个示例中:

  • @ViewBag.Title 用于动态设置页面的标题,具体的标题信息会在每个视图中进行设置。
  • @RenderBody() 是一个占位符,用于渲染具体视图的内容。
  • 使用了 asp-* 属性,这是ASP.NET Core Tag Helpers 的一种形式,用于生成URL。
  • 引入了一些外部的CSS和JavaScript文件,通常是通过使用 lib 目录下的包管理工具(例如,NuGet或NPM)安装的第三方库。
  • 用于包裹主要内容,这是 Bootstrap 中的一个样式类,用于创建一个固定宽度的容器。

这个主布局文件定义了网站的整体结构,包括头部、导航栏、主要内容区域和页脚。每个具体的视图可以选择性地使用这个布局,确保整个应用程序的一致性。在视图中,可以使用 @{ Layout = "_Layout"; } 来指定使用的布局文件。

  1. 部分视图
    部分视图(Partial View)是在ASP.NET Core中可重用的、可以被其他视图或部分视图包含的组件。它允许你将页面中的一部分提取出来,以便在多个地方共享相同的代码或 UI 元素。以下是如何创建和使用部分视图的基本步骤:
  • 创建部分视图
    • Views文件夹中创建一个名为Shared的文件夹:
     /Views
        /Shared
    
    • Shared文件夹中创建部分视图文件,例如_MyPartialView.cshtml
    
    <div>
        <h3>This is a partial view contenth3>
        
    div>
    
  • 使用部分视图
    在其他视图或布局中使用 Html.PartialHtml.RenderPartial 方法引入部分视图:

@Html.Partial("_MyPartialView")


@{
    await Html.RenderPartialAsync("_MyPartialView");
}

或者,在布局中引入部分视图:


@Html.Partial("_MyPartialView")
  • 传递模型给部分视图
    如果你希望在部分视图中使用模型数据,可以将模型数据传递给部分视图:

@Html.Partial("_MyPartialView", model: new MyModel())
  • 使用 @model 声明部分视图的模型
    在部分视图文件的顶部使用 @model 声明视图模型,以便在部分视图中直接访问模型数据:
@model MyNamespace.MyModel

<div>
    <h3>@Model.Titleh3>
    
div>
  • 注意事项
    • 部分视图的文件名通常以下划线 _ 开头,这是一种常见的约定,用于表示这是一个局部组件而非完整的视图。
    • 部分视图通常用于渲染重复的 UI 元素,例如导航栏、页脚、模态框等。
    • 在部分视图中,可以包含 HTML、Razor 代码和 C# 代码,类似于完整的视图。

使用部分视图有助于提高代码的可维护性,避免在多个地方重复编写相同的代码,同时使得对 UI 元素的修改更为方便。

四、数据传递和模型绑定

4.1 模型绑定概述

模型绑定是ASP.NET Core中一种重要的特性,它负责将HTTP请求的数据(如表单数据、查询字符串、路由数据等)与应用程序中的模型进行关联。这使得在控制器中处理请求时,可以方便地使用和操作模型数据。

  1. 工作原理
    模型绑定工作的基本原理是通过将HTTP请求中的数据(键值对)映射到应用程序中的模型对象。这个映射过程是自动进行的,ASP.NET Core框架根据请求中的数据类型、名称和模型对象的属性进行匹配。
  2. 支持的数据源
    模型绑定可以从多个数据源中获取数据,包括:
    • 查询字符串(Query String): 通过URL中的查询参数传递的数据。
      public IActionResult MyAction([FromQuery] string parameter)
      {
          // 从查询字符串中获取参数值
      }
      
    • 表单数据: 通过HTML表单提交的数据。
      [HttpPost]
      public IActionResult MyAction([FromForm] string parameter)
      {
          // 从表单数据中获取参数值
      }
      
    • 路由数据: 从URL中的路由参数中获取数据。
      [HttpGet("/myroute/{parameter}")]
      public IActionResult MyAction([FromRoute] string parameter)
      {
          // 从路由数据中获取参数值
      }
      
    • 请求体数据(Body): 通常用于接收JSON格式的数据。
      [HttpPost]
      public IActionResult MyAction([FromBody] MyModel model)
      {
          // 从请求体中获取模型数据
      }
      
  3. 模型验证
    模型绑定的一部分是模型验证,这是一个在模型绑定后执行的步骤。模型验证用于确保绑定到模型的数据符合模型的定义规则。如果验证失败,可以通过检查 ModelState.IsValid 属性来获取错误信息。
  4. 自定义模型绑定器
    在某些情况下,可能需要自定义模型绑定的行为。这可以通过创建自定义的模型绑定器来实现。模型绑定器是实现 IModelBinder 接口的类,允许你完全掌控数据绑定的过程。
  5. 特性和注解
    通过在模型属性上使用特性和注解,可以对模型的绑定行为进行更精确的控制。例如,可以使用 Required 特性指定某个属性为必填项。
public class MyModel
{
    [Required]
    public string Name { get; set; }
}

模型绑定是ASP.NET Core MVC中处理用户请求和数据输入的关键机制之一。了解如何有效地使用模型绑定可以简化控制器的代码,并使数据传递更为方便和可靠。

4.2 常见的模型绑定技巧

在ASP.NET Core MVC中,有一些常见的模型绑定技巧,可以帮助你更灵活、高效地处理用户请求和数据输入。以下是一些常见的技巧:

  1. 模型绑定前缀
    在处理复杂的数据结构(例如嵌套的对象或集合)时,可以使用模型绑定前缀来指定数据应该绑定到模型的哪个属性。这在处理表单数组或嵌套对象时非常有用。
public IActionResult MyAction([Bind(Prefix = "User")] UserModel user)
{
    // 会将请求中以 "User" 为前缀的数据绑定到 UserModel 对象的相应属性
}
  1. [FromBody] 特性
    使用 [FromBody] 特性将请求体中的数据绑定到模型对象。这在处理 JSON 格式的请求时非常有用。
[HttpPost]
public IActionResult MyAction([FromBody] MyModel model)
{
    // 从请求体中获取 JSON 数据并绑定到 MyModel 对象
}
  1. [FromForm], [FromQuery], [FromRoute]
    使用 [FromForm], [FromQuery], [FromRoute] 特性明确指定模型绑定的数据来源。
[HttpPost]
public IActionResult MyAction([FromForm] string name, [FromQuery] int age, [FromRoute] int id)
{
    // 分别从表单、查询字符串和路由数据中获取数据
}
  1. 默认值
    在模型的属性上设置默认值,可以确保即使没有提供相应的数据,模型属性也有一个合理的初始值。
public class MyModel
{
    public string Name { get; set; } = "Default Name";
}
  1. 复杂类型的绑定
    处理复杂类型(如集合、数组)时,可以使用 [Bind] 特性来指定绑定的属性。
public IActionResult MyAction([Bind("Id,Name")] List<ItemModel> items)
{
    // 只绑定 Id 和 Name 属性,而忽略其他属性
}
  1. 手动验证
    在模型绑定后,可以手动执行验证并检查 ModelState.IsValid 属性。
[HttpPost]
public IActionResult MyAction([FromBody] MyModel model)
{
    if (ModelState.IsValid)
    {
        // 执行逻辑
    }
    else
    {
        // 处理验证失败的情况
    }
}
  1. 自定义模型绑定器
    对于特殊的绑定需求,可以创建自定义的模型绑定器。
public class CustomModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        // 自定义绑定逻辑
    }
}

然后在控制器的方法中使用 [ModelBinder] 特性应用自定义的模型绑定器。

public IActionResult MyAction([ModelBinder(typeof(CustomModelBinder))] MyModel model)
{
    // 使用自定义模型绑定器
}

这些技巧可以帮助你更好地利用ASP.NET Core MVC的模型绑定功能,使代码更加灵活、可维护。选择适当的技巧取决于你的具体需求和场景。

五、Views中的表单处理

5.1 HTML表单基础

HTML表单是一种用于收集用户输入的元素,它允许用户通过输入框、下拉菜单、单选按钮等方式向服务器提交数据。以下是HTML表单的基础概念和元素:

  1. 元素
    表单通常使用 元素进行定义,它包裹了表单中的所有输入元素。 元素有以下常见属性:
    • action: 指定表单数据提交到的服务器端URL。
    • method: 指定用于发送表单数据的HTTP方法,常见的有 “GET” 和 “POST”。
    • enctype: 指定在发送表单数据时使用的编码类型,常见的有 “application/x-www-form-urlencoded” 和 “multipart/form-data”。
    <form action="/submit" method="post">
      
    form>
    
  2. 输入元素
    在表单中,可以使用多种输入元素,根据用户需要收集的数据类型选择合适的元素。
    • 文本框
    <label for="username">Username:label>
    <input type="text" id="username" name="username">
    
    • 密码框
    <label for="password">Password:label>
    <input type="password" id="password" name="password">
    
    • 单选按钮
    <input type="radio" id="male" name="gender" value="male">
    <label for="male">Malelabel>
    
    <input type="radio" id="female" name="gender" value="female">
    <label for="female">Femalelabel>
    
    • 复选框
    <input type="checkbox" id="subscribe" name="subscribe" value="true">
    <label for="subscribe">Subscribe to newsletterlabel>
    
    • 下拉菜单