ASP.NET Core中的TagHelper及其用法

TagHelper

标记帮助程序(TagHelper)是ASP.NET Core中的新增功能。

​ 首先通过一个例子来理解TagHelper及其用途。

​ TagHelper是服务器端组件。它们在服务器上运行,并在Razor文件中创建和渲染HTML元素。如果对以前版本的ASP.NET Core MVC有一定了解,那么读者可能也知道HTML TagHelper。TagHelper类似于HTML TagHelper,ASP.NET Core有许多内置的TagHelper用于常见任务,比如生成链接、创建表单和加载数据等。TagHelper的出现可帮助提高生产效率,并生成更稳定的 、可靠和可维护的代码。

导入内置的TagHelper

​ 要在整个应用程序中的所有视图使用内置TagHelper,需要在_ViewImports.cshtml文件导入TagHelper。要导入TagHelper,我们使用@addTagHelper指令。

@addTagHelper *.Microsoft.AspNetCore.Mvc.TagHelpers

​ 通配符*表示我们要导入MVC中所有的TagHelper,而Microsoft.AspNetCore.Mvc.TagHelpers则是内置TagHelper的组件位置。

使用TagHelper生成Link链接🔗

​ 假设要查看指定学生的详细信息,则要生成以下超链接。数字5是我们要查看其详细信息的学生的ID。

/home/details/5

​ 我们可以通过多种方式在Razor视图中实现该效果。

  1. 手动生成链接
@foreach (var student in Model)
{
    <a href="/home/details/@student.ID">查看</a>
}
  1. 使用HTML TagHelper
@Html.ActionLink("查看","details",new {ID = student.ID})
    生成结果Link元素<a href="/home/details/5">查看</a>或者@Url.Action("details","home",new{ID=student.Id})

​ 生成的结果:/home/details/5。👀

  1. 使用TagHelper
<a asp-controller="home" asp-action="details" asp-route-id="@student.ID" >查看</a>,
生成结果<a href="/Home/details/5">查看</a>

TagHelper中的Link标签🗒

​ TagHelper中的Link标签通过添加新属性来增强标准的HTML标签,以下TagHelper均可以增强Link标签的href属性值。

asp-controller
asp-action
asp-route-{value}

​ 正如名称所表示的那样,asp-controller指定控制器名称,而asp-action指定要包含在生成的href属性值中的操作方法名称asp-route-{value}属性用于在生成的href中包含路由数据属性值。{value}可以替换为路由参数,比如id。参考以下代码:

<a asp-controller="home" asp-action="details" asp-route-id="@student.ID">查看</a>

​ 生成结果: <a href="/home/details/5">查看</a>

​ 从下面的代码中可以看出,手动生成的链接比使用HTMLHelper或TagHelper要容易得多。

<a href="/home/details/@student.ID">查看</a>

​ 读者可能产生一个疑问:为什么我们要使用TagHelper或HTML Helper来生成这些链接,而不是手动生成?我们将在下文回答这个问题。

为什么要使用TagHelper

​ 让我们通过一个简单的例子来理解TagHelper的优势。

​ 假设我们想要查看特定的学生的详细信息,则需要生成超链接,比如学生ID为5的详细信息。

/home/details/5

​ 我们可以通过手动编写,如下:

<a href="/home/details/@student.ID">查看</a>

​ 也可以使用Link链接的TagHelper,代码如下:

<a asp-controller="home" asp-action="details" asp-route-id="@student.ID">查看</a>

使用TagHelper的优势

​ TagHelper是根据应用程序的路由模板生成的链接,这意味着如果我们更改路由模板,则TagHelper生成的链接会针对路由模板所做的更改自动修改和适配,让生成的链接正常工作。

​ 而如果我们手动硬编码了URL,则当应用程序路由模块发生变化时,就必须在很多地方更改代码,这样效率并不高。

​ 可以通过一个例子来理解这一点。

app.UseEndpoints(endpoints=>
                 {
                     endpoints.MapControllerRoute(
                         name:"default",
                         pattern:"{controller=Home}/{action=Index}/{id?}"
                     );
                 });

​ 以下代码没有用TagHelper,而是对URL路径进行硬编码。

<a href="/home/details/@student.ID">查看</a>

以下代码是使用<a>元素的TagHelper完成的。

<a asp-controller="home" asp-action="details" asp-route-id="@student.ID">查看</a>

​ 请注意,我们没有针对URL路径进行硬编码,只指定控制器和操作方法的名称,以及路由参数及其值。在服务器上执行TagHelper时,它们会查看路由模板并自动生成正确的URL。

​ 上述两种方法都会生成正确的URL路径(/home/details/5),它适用于当前路由模板({controller=Home}/{action=Index}/{id?})。

​ 现在让我们改变路由模板,代码如下。请注意,在URL中有字符串pragim

app.UseEndpoints(endpoints=>
                 {
                     endpoint.MapControllerRoute(
                     	name:"deafault",
                         pattern:"pragim/{controller=Home}/{action=Index}/{id?}"
                     );
                 });

​ 请注意,不要忘记删除HomeController中属性路由的属性,否则项目还是会正常进入Home/Index的路径中。当读者运行项目发生404错误的时候,记得添加pragim域信息和正确的URL访问路径http://localhost:2051/pragim。编译并运行项目,使用TagHelper生成的代码是正确的链接。

<a href="/pragim/home/details/1">查看</a>。 
//其中未使用TagHelper的代码则没有变化,缺少URL路径“/pragim”
<a href="/home/details/1">查看</a>

​ 我们还有其他TagHelper,它可以生成表单。将此表单发回服务器时,将自动处理发布的值并显示相关的验证信息。如果没有这些TagHelper,我们将不得不编写大量自定义代码来实现相同的功能。

​ 如果此时读者觉得没有多大意义,请耐下心来。我们会在后面创建学生信息的时候讨论表单的TagHelper。

Image TagHelper

​ 在开始说Image标记帮助程序的好处之前,我们先验证一下普通元素的问题。

​ 准备好两个图片文件,一个名为noimage.png,另一个名为noimage1.png,把它们存储在wwwroot/images文件夹中。现在正常运行项目,如图所示。

在这里插入图片描述

​ 接下来回到项目中,将noimage.png重命名为noimage2.png。然后将noimage1.png重命名为noimage.png。再次刷新页面会发现没有变化,打开开发者工具可以发现,返回的HTTP Code:200 OK(from memmory cache)是从缓存中得到的,如图所示。

在这里插入图片描述

​ 这样带来的问题是用户会认为我们的程序出问题了,那么怎么解决?

浏览器缓存

​ 当访问网页时,大多数浏览器会缓存该网页的图片,这样再次访问该页面时,浏览器就不用从Web服务器下载相同的图片,而是从缓存中提取。在大多数情况下,这不是问题,因为图片不会经常发生改变,但是这对开发人员来说相当不友好。

禁用浏览器缓存

​ 由于某种原因,如果读者不希望浏览使用器缓存,则可以禁用它。比如,要在Google Chrome中禁用缓存,步骤如下:

  • 按F12,启动Browser Developer Tools
  • 单击NetWork选项卡。
  • 选中DIsable cache复选框。如图所示。

在这里插入图片描述

​ 禁用浏览器缓存后,会带来一个明显的问题,那就是每次访问该页面时都必须从服务器下载图片,要记得平时关闭禁用缓存。

​ 现在刷新浏览器,新的图片就会加载出来了。

HTTP状态码的200与302

​ HTTP状态码是用于表示网页服务器HTTP响应状态的3位数字代码。状态码的第一个数字代表响应的5中状态之一,这里我们只介绍涉及的3xx2xx系列。

2xx系列代表请求已成功被服务器接收、理解并接受,这系列中常见的200状态码和201状态码。

  • 200状态码:表示请求已成功,请求所希望的响应头或数据体将随此响应返回。
  • 201状态码:表示请求成功,服务器创建了新的资源,并且其URI已经随Location请求头信息返回。假如需要的资源无法及时建立的话,应当返回202Accepted。

3xxx系列代表需要客户端采取进一步的操作才能完成请求,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的Location域中指明。这系列中常见的有301状态码和302状态码。

  • 301状态码:被请求的资源已永久移动到新位置。服务器返回此响应(对GET请求或HEAD请求的响应)时,会自动将请求者转到新位置。
  • 302状态码:请求的资源临时从不同URI响应请求,但请求者应继续使用原有位置来进行以后的请求。

简单来说:3xx系列表示请求的是客户端,而2xx系列表示请求的是服务器端。

ASP.NET Core中的Image TagHelper

​ 从性能角度来看,只有在服务器上更改了图片才能对其进行下载。如果图片未更改,请使用浏览器中缓存的照片。这意味着我们将拥有两全其美的优势。

​ Image TagHelper可以帮助我们实现这一效果。要使用Image TagHelper,请包含asp-append-version属性并将其设置为true

​ 现在我们回到项目中,打开Index.cshtmlDetails.cshtml并对它们进行修改,代码如下。

<img src="~/images/noimgage.png" asp-append-verison="true"/>

​ Image TagHelper增强了img标签属性,为静态图像文件提供了缓存清楚行为,通过散列计算生成唯一的散列值并将其附加到图片的URL中。唯一的散列值会提示客户端(或某些代理)从服务器重新加载图片,而不是从浏览器的缓存中重新加载。以下是生成的代码。

在这里插入图片描述

​ 只有当每次服务器上的图片更改时,才会计算并缓存新的散列值。如果图片未更改,则不会重新计算散列值。使用此散列值,浏览器会跟踪服务器上的图片内容是否已更改。使用Image TagHelper可以帮助我们解决很多由潜在因素造成的问题。

ASP.NET Core中的Environment TagHelper

​ 我们在ASP.NET Core应用程序开发过程中使用了Bootstrap。为了便于调试,希望在本地开发计算机(在开发环境中)通过应用程序加载没有压缩的Bootstrap的CSS文件(bootstrap.css)。而在Staging、Production或除Development环境以外的任何其他环境中,希望应用程序能从CDN(内容分发网络)加载压缩后的Bootstrap的CSS文件(bootstrap.min.css)以获得更好的性能。

​ 但是,如果CDN出现故障或者出于某种原因,当应用程序无法访问CDN的时候,我们希望应用程序不要访问CDN,并从应用程序Web服务器加载压缩后的Bootstrap文件。

​ 很多开发框架都有这种功能,现在我们可以使用ASP.NET Core Environment TagHelper轻松实现这一点。在我们理解Environment TagHelper之前,我们先来了解如何设置应用程序环境的名称。

设置应用程序环境的名称

​ Environment TagHelper支持根据应用程序环境呈现不同的内容,它使用ASPNETCORE_ENVIRONMENT变量的值作为环境的名称。

​ 如果应用程序时Development ,则此示例加载没有压缩的bootstrap.css文件,代码如下:

<environment include="Development">
    	<link href="~/lib/bootstrap/css/bootstrap.css" rel="stylesheet"/>
</environment>

​ 如果应用程序环境是Staging或者Production,则此示例从CDN加载压缩后的bootstrap.min.css文件,代码如下。

<environment include="Staging,Production">
   <!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
</environment>

​ include属性接受将单个环境名称以逗号分隔的形式生成列表。在Environment TagHelper中还有exclude属性,当托管环境与exclude属性值中列出的环境名称不匹配时,将呈现标签中的内容。

​ 如果应用程序不是Development,则从此示例从CDN加载压缩后的bootstrap.min.css文件,代码如下:

<environment exclude="Development">
        <!-- CSS only -->
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"/>
    </environment>

​ <link>元素中的integrity属性用于检查子资源完整性。Subresource Integrity(SRI)是一种安全功能,允许浏览器检查被检索的文件是否被恶意更改。当浏览器下载文件时,它会重新计算散列值并将其与完整性属性散列值进行比较。如果散列值匹配,则浏览器允许下载文件,否则将被阻止。

如果CDN“挂了”,怎么办

​ 如果CDN出现故障或出于某种原因应用程序无法访问CDN,则希望应用程序从应用程序Web服务求加载压缩后的Bootstrap文件,代码如下。

 <environment include="Development">
        <link href="~/lib/twitter-bootstrap/css/bootstrap.css" rel="stylesheet" />
    </environment>

    <environment exclude="Development">
        <!-- CSS only -->
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" asp-fallback-href="~/lib/twitter-bootstrap/css/bootstrap.css" asp-fallback-test-class="sr-only" asp-fallback-test-property="positon" asp-fallback-test-value="absolute" asp-suppress-fallback-integrity="true" />
    </environment>

​ 如果应用程序环境是Development,则从应用程序Web服务器加载没有压缩的bootstrap.css文件;如果应用程序环境不是Development,则从CDN加载缩小的bootstrap.min.css文件。

​ 使用asp-fallback-href属性指定回退源。这意味着,如果CDN关闭,则应用程序将回退并从应用程序Web服务器加载缩小的Bootstrap文件。

​ 以下3个属性及其相关值用于检查CDN是否关闭。

  • asp-fallback-test-calss="sr-only"
  • asp-fallback-test-propery="position"
  • asp-fallback-test-value="absolute"

当然,这会设计计算散列值,并将其与文件的完整性属性散列值进行比较。对于大多数应用程序,CDN失效的时候都是回退到它们自己的服务器,方法是将asp-suppress-fallback-integrity属性设置为true,当然读者也可以选择关闭从本地服务器下载的文件完整性检查。

使用Bootstrap给项目添加导航菜单

​ ❗请注意,Bootstrap的所有Javascript插件都依赖于jQuery,因此jQuery必须在Bootstrap之前引入。读者可以使用Libman管理工具下载jQuery,也可前去jQuery官网下载。

布局页面_Layout.cshtml的代码

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <environment include="Development">
        <link href="~/lib/twitter-bootstrap/css/bootstrap.css" rel="stylesheet" />
        <script src="~/lib/jquery/jquery.js"></script>
        <script src="~/lib/twitter-bootstrap/js/bootstrap.js"></script>
    </environment>

    <environment exclude="Development">
        <!-- CSS only -->
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" asp-fallback-href="~/lib/twitter-bootstrap/css/bootstrap.css" asp-fallback-test-class="sr-only" asp-fallback-test-property="positon" asp-fallback-test-value="absolute" asp-suppress-fallback-integrity="true" />
    </environment>

    <link href="~/css/site.css" rel="stylesheet" />
    <title>@ViewBag.Title</title>
</head>
<body>
    <div class="container">
        <nav class="navbar navbar-expand-sm bg-dark navbar-dark">
            <a class="navbar-brand" asp-controller="home" asp-action="index">
                <img src="~/images/student.png" width="30" height="30" />
            </a>
            <button class="navbar-toggler"
                    type="button"
                    data-toggle="collapse"
                    data-target="#collapsibleNavbar">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="collapsibleNavbar">
                <ul class="navbar-nav">
                    <li class="nav-item">
                        <a class="nav-link" asp-controller="home" asp-action="index">列表</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" asp-controller="home" asp-action="create">创建</a>
                    </li>
                </ul>
            </div>
        </nav>
        @RenderBody()
    </div>

   
    @if (IsSectionDefined("Scripts"))
    {@RenderSection("Scripts", required: false)}
</body>
</html>

​ 注意,对于非开发环境(Staging 、Production等),我们没有使用所需的<link>元素来从CDN加载所需的Jquery和Bootstrap Javascript文件。

​ 请注意,按钮(查看、编辑、删除)是相互连接在一起的,我们要在这些按钮之间包含边框,需使用Bootstrap提供的边距类(m-1、m-2等)。在类名中,m代表边距,数字1、2等代表所需空间的大小。

​ 在Index.cshtml修改\<a>元素,使其包含m-1

在这里插入图片描述

Form TagHelpers 提交学生信息

场景描述

我们在ASP.NET Core中使用以下常用的TagHelpers创建表单。

  • Form TagHelper。
  • Label TagHelper。
  • Input TagHelper。
  • Selece TagHelper。
  • Textarea TagHelper。
  • Validation TagHelper。

我们希望使用Form TagHelpers创建表单,并使用Bootstrap对其进行样式设置,完成创建学生信息。

​ 我们在HomeController中添加如下代码。

 public IActionResult  Create()
        {
            return View();
        }

然后在路径为Views/Homes/的文件夹中添加视图Create.cshtml

Form TagHelper

​ 要创建表单可以使用Form TagHelper。需要注意的是,我们实际是使用asp-controllerasp-action TagHelper。这两个TagHelper指定控制器并在提交表单时将表单数据发布到指定的操作方法上。我们希望在提交表单时发出POST请求,因此将method属性设置为post。

<form asp-controller="home" asp-action="create" method="post">
</form>

​ 从客户端浏览器上呈现表单时,上面的代码会生成以下HTML代码。正如读者在提交表单时从生成的HTML代码中看到的那样,它将被发布到HomeController的Index()方法中,编译后打开源代码可以看到渲染出来的HTML代码。

<form method="post" action="/home/create">
    
</form>

​ 请注意,默认情况下在提交表单时,它将被发布到当前页面表单的控制器的操作方法中。这意味着,即使我们没有使用asp-controllerasp-action TagHelper指定对应的控制器和操作方法,表单仍然被发布到HomeController的Index()方法中,但是建议写的时候还是显示声明。

Input TagHelper

​ Input TagHelper将HTML中的<input>元素绑定到Razor视图中的模型表达式。

​ 在我们的例子中想要设计一个表单来创建新学生信息。因此,Create.cshtml视图的模型是Student类,需要使用@model 指令,即@model Student

​ 为了获取学生姓名,我们需要一个文本框并将其绑定到Student模型类的Name属性。我们使用asp-for TagHelper将input的属性值设置为Student模型类的name属性。

​ 请注意,Visual Studio会提供智能提示。如果在Student类上将属性名称Name更改为FullName,但不更改分配给的TagHelper的值,则会出现编译器错误。

<input asp-for="Name" />

​ 上面的代码会生成一个带有id和name属性的<input>元素。请注意,它们的值均为Name。

<input type="text" id="Name" name="Name" value="" />

​ name属性是必须的,它用于在提交表单时将输入元素的值映射到模型类的对应属性。这是通过ASP.NET Core中称为模型绑定的过程完成的。

Label TagHelper

​ Label TagHelper会生成带有for属性的标签。属性链接与和它相关的输入元素的标签进行绑定,代码如下。

<label asp-for="Name"></label>    <input asp-for="Name" />

上面的代码生成以下HTML代码:

<label for="Name">Name</label>
<input type="text" id="Name" name="Name" value="" />

​ Label标签链接到input标签,因为这两种标签的属性和input标签的id属性具有相同的值(Name)。

​ 同样,以下代码生成<label>和<input>元素以获取学生的电子邮箱。

<label asp-for="Email"></label>		<input asp-for="Email" />

Select TagHelper

​ Select TagHelper会生成select标签及其关联的元素。在我们的例子中需要通过select显示主修科目列表。最后,我们需要一个select标签和一个带有主修科目选项列表的元素,如下所示。

<label for="Major">主修科目</label>
<select id="Major" name="Major">
    <option value="0">计科</option>
    <option value="1">信安</option>
    <option value="2">网工</option>
</select>

​ 主修科目的元素的选项内容可以像上面的示例中那样进行硬编码,也可以来自枚举或数据库表。我们还没有连接数据库,因此,对于我们的示例可以从枚举中获取选项。

​ 我们在Models/EnumTypes的文件夹中创建一个MajorEnum.cs枚举类。

 public enum EnumTypes
    {
        None,
        FirstGrade,
        SecondGrade,
        GradeThree
    }

​ 修改Models文件夹中Student.cs文件的代码,将Major属性数据类型改为MajorEnum。在Create.cshtml视图中添加以下代码。

<label asp-for="Major"></label>
<select asp-for="Major" asp-items="Html.GetEnumSelectList<MajorEnum>()">
</select>

​ 请注意,我们使用asp-items属性值帮助程序和Html.GetEnumsSelectList<MajorEnum>()获取<select>元素的选项。

​ 上面的代码生成以下HTML代码。

<label for="Major">Major</label>
<select data-val="true" data-val-required="The Major field is required." id="Major" name="Major">
    <option value="0">None</option>
    <option value="1">FirstGrade</option>
    <option value="2">SecondGrade</option>
    <option value="3">GradeThree</option>
</select>

Create.cshtml中基本的HTML代码

@model Student
@{ ViewBag.Title = "创建学生信息"; }

<form asp-controller="home" asp-action="create" method="post" >

    <div>
        <label asp-for="Name" ></label>       
        <input asp-for="Name"/>
    </div>
    
    <div>
        <label asp-for="Email"></label>
        <input asp-for="Email"/>
    </div>

    
    <div>
        <label asp-for="Major"></label>
            <select asp-for="Major"
                    asp-items="Html.GetEnumSelectList<MajorEnum>()">
                <option value="">请选择</option>
            </select>
    </div>

   
       <button type="submit">创建</button>
</form>

​ 以上的代码会生成以下的HTML代码。

<form method="post"  action="/home/create">
    

    <div>
        <label  for="Name">Name</label>
        
            <input type="text" id="Name" name="Name" value="" />
    </div>
    
    <div>
        <label for="Email">Email</label>
        <input  type="text" id="Email" name="Email" value="" />           
    </div>

    <div>
        <label for="Major">Major</label>
        <select data-val="true" data-val-required="The Major field is required." id="Major" name="Major">
             <option value="">请选择</option>
            <option value="0">None</option>
			<option value="1">FirstGrade</option>
			<option value="2">SecondGrade</option>
			<option value="3">GradeThree</option>
</select> 
    </div>

    
            <button type="submit" class="btn btn-primary">创建</button>

   
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8IVmefmn13tElsuhIOlxBd9qxTAKjc5MLl_DnUHtxiZb-ztIjcXBKCtrVcKqrDEmn17EthiSYdJ8fxT6emkGJopOw5HrMAKYZOEg-4khyt_WLv8rEhhTqGLRm73T8eS1Lx8RcxZJ_jnEQEVwulC-eC4" />
</form>

运行后效果如图所示:

在这里插入图片描述

​ 这就是基本的HTML代码生成的效果,这里功能是有了,但是美化并不好,因此要对它进行优化。现在使用Bootstrap进行优化。

Bootstrap优化后的Create.cshtml的代码

@model Student
@{ ViewBag.Title = "创建学生信息"; }

<form asp-controller="home" asp-action="create" method="post" class="mt-3">
    <div asp-validation-summary="All" class="text-danger"></div>

    <div class="form-group row">
        <label asp-for="Name" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="Name" class="form-control" placeholder="请输入名字" />
            <span asp-validation-for="Name" class="text-danger"></span>

        </div>
    </div>
    <div class="form-group row">
        <label asp-for="Email" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="Email" class="form-control" placeholder="请注入邮箱地址" />
            <span asp-validation-for="Email" class="text-danger"></span>

        </div>
    </div>

    <div class="form-group row">
        <label asp-for="Major" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <select asp-for="Major"
                    class="custom-select mr-sm-2"
                    asp-items="Html.GetEnumSelectList<MajorEnum>()">
                <option value="">请选择</option>
            </select>
            <span asp-validation-for="Major" class="text-danger"></span>

        </div>
    </div>

    <div class="form-group row">
        <div class="col-sm-10">
            <button type="submit" class="btn btn-primary">创建</button>
        </div>
    </div>

 
</form>

运行后,效果如图所示:

在这里插入图片描述

​ 至此,我们的Create页面做完了。虽然是一个简单的页面,但我们用到的组件一点也不少。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ASP.NET Core 3.1是一个跨平台、高性能的开源框架,它可以帮助我们快速地构建Web应用程序。ASP.NET Core 3.1文教程可以为初学者提供一个快速上手的指南,帮助他们了解和掌握该框架的各种功能。 在学习ASP.NET Core 3.1教程之前,我们需要了解一些基本的编程概念和技能, 包括C#语言的基础知识、MVC(Model View Controller)等常见的编程模式、以及前端技术如HTML、CSS和JavaScript等。此外,我们还需要对.NET Core框架有一定的了解,如.NET Core的概念、架构和基础组件等。 学习ASP.NET Core 3.1的教程需要深入理解其设计方案和特点,例如跨平台、高性能、依赖注入、实时通信等。此外,我们还需要熟悉其主要组件,如ASP.NET Core间件、MVC框架、Entity Framework Core等。 在学习ASP.NET Core 3.1的教程时,我们需要通过实践才能更好地理解其所涉及的技术和概念。因此,我们需要通过编写各种实际的Web应用程序和示例,来实践和掌握所学的技巧和知识。 总之,学习ASP.NET Core 3.1的文教程需要较深的前置知识储备和实操经验,而且需要坚持不懈地学习和练习以提高自己的技能水平。 ### 回答2: ASP.NET Core 3.1是目前为止最新的ASP.NET Core版本,它是一个跨平台的Web应用程序开发框架。对于想要学习ASP.NET Core 3.1的开发者来说,文教程是非常重要的。 现在,有很多文教程可以帮助开发者快速入门ASP.NET Core 3.1。这些教程通常包括以下内容: 1. ASP.NET Core 3.1的基础知识:网页处理、路由、控制器等; 2. ASP.NET Core 3.1的模型、视图和控制器; 3. 动作过滤器和特性; 4. 实体框架和数据库相关操作; 5. API设计和测试等。 这些教程通常包含实例和练习,能够帮助开发者深入理解ASP.NET Core 3.1的开发原理。另外,一些知名的在线教育平台,如网易云课堂等,也提供了ASP.NET Core 3.1的文课程,有兴趣的开发者可以去尝试。 总的来说,学习ASP.NET Core 3.1需要投入时间和精力,但是文教程能够让初学者更加轻松地掌握ASP.NET Core 3.1的开发技能,更好地进行ASP.NET Core 3.1的开发工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值