当我们使用Visual Studio 2022去新建一个基于asp.net core Web项目的时候,一般有三种选择,一种是空项目,一种是基于MVC的项目、再有一种就是基于包含Razor Pages实例的web应用。如下图:
今天,我们打算选择基于MVC模式的web应用来详细介绍,详细到什么程度呢?逐句逐词的讲解,旨在给初学asp.net web应用的童鞋答疑解惑。
文章目录
- 一、项目文件结构介绍
- 1、项目结构目录图
- 2、项目文件组成
- 二、文件介绍
- 1、裸露在外的两个文件
- program.cs文件
- 关于WebApplication.CreateBuilder
- appsettings.json
- 2、Views文件夹
- (1) index.cshtml
- 关于数据传递ViewData
- (2)_layout.cshtml
- 关于导航栏
- 关于正文body
- 关于footer
- (3)privacy文件
- 3、Controller文件夹
- 关于路由的修改
- 4、Models文件夹
一、项目文件结构介绍
1、项目结构目录图
新建一个Asp.net Core Web应用(MVC)的项目之后,我们可以看到这样的结构:
2、项目文件组成
可以看到这个目录结构相当的有特点,一看就是MVC模式的,它自带了Models、Views、Controllers三个目录。
我们按照项目的文件运行的先后顺序来逐一介绍,或者按照文件的重要程度来介绍。首先是裸露在外的两个文件program和appsettings,其次是MVC的三个文件夹,然后是WWWROOT,然后才是Peroperties文件夹。
二、文件介绍
1、裸露在外的两个文件
program.cs文件
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
我们来逐句解释
以下是对这段代码的逐句解释:
var builder = WebApplication.CreateBuilder(args);
创建一个 WebApplicationBuilder
实例。args
通常是命令行参数,用于配置应用程序的构建过程。
// Add services to the container.
builder.Services.AddControllersWithViews();
向应用程序的服务容器中添加具有视图功能的控制器服务。这一步使得应用程序能够处理 HTTP 请求并返回带有视图的响应。所以,我们就可以在这里来配合Controller类来向视图返回需要展现在视图中的内容了。
var app = builder.Build();
使用之前创建的 WebApplicationBuilder
构建一个 WebApplication
实例。这个实例代表了整个应用程序,可以用来配置请求处理管道和启动应用程序。管道的只是在.net core中是一个很核心的概念,理解或不理解其实都没有关系,并不影响我们写一些简单的asp.net core的应用。
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
配置 HTTP 请求处理管道。如果应用程序不是在开发环境中运行,那么当发生异常时,将使用指定的路径(/Home/Error
)来处理异常。
app.UseStaticFiles();
启用静态文件服务,允许应用程序提供静态文件(如静态的html、 CSS、JavaScript 和图像文件)。
app.UseRouting();
启用路由中间件,用于将请求路由到相应的控制器和操作方法。这个就会依靠路由来访问控制器中提供的内容,而不是像静态页一样的实际文件。它只是某个控制器的方法的返回值。
app.UseAuthorization();
启用授权中间件,用于处理授权要求,确保只有经过授权的用户可以访问特定的资源。
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
定义一个默认的控制器路由。如果请求没有明确指定控制器、操作方法和参数,那么将使用默认值(控制器为 Home
,操作方法为 Index
,参数是可选的)。
app.Run();
启动应用程序,开始监听传入的 HTTP 请求。
关于WebApplication.CreateBuilder
WebApplication.CreateBuilder
是 ASP.NET Core 中用于创建应用程序构建器的方法,其工作原理如下:
a、初始化构建器
- 创建一个
WebApplicationBuilder
实例。这个构建器负责配置和组装应用程序的各个部分。- 它接受一个命令行参数数组
args
,这允许应用程序在启动时接收来自命令行的参数,以便进行灵活的配置。
- 它接受一个命令行参数数组
b、配置服务容器
- 构建器提供了一个服务集合,用于注册各种服务,这些服务在应用程序的生命周期中可以被注入到不同的组件中。
- 例如,可以使用
builder.Services.AddControllersWithViews()
向服务容器中添加具有视图功能的控制器服务。这使得应用程序能够处理 HTTP 请求并返回带有视图的响应。 - 可以添加数据库连接服务、日志服务、身份验证和授权服务等各种其他服务,以满足应用程序的特定需求。
- 例如,可以使用
c、配置应用程序的环境和其他属性
- 通过构建器,可以访问应用程序的运行环境信息,例如判断当前是否是开发环境。
- 可以根据不同的环境进行不同的配置,比如在开发环境中可能会启用更多的调试信息和开发工具,而在生产环境中可能会进行性能优化和安全加固。
d、构建应用程序实例
- 当完成了对构建器的配置后,可以调用
builder.Build()
方法来构建一个WebApplication
实例。- 这个实例代表了整个应用程序,包含了所有已配置的服务和中间件,以及请求处理管道。
总之,WebApplication.CreateBuilder
提供了一种方便的方式来初始化和配置 ASP.NET Core 应用程序,使得开发者可以轻松地管理应用程序的各个方面,从服务注册到环境配置,再到最终构建出可运行的应用程序实例。
appsettings.json
以下是对这段 appsettings 配置内容的逐句解释:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
"Logging"
:表示日志相关的配置部分。"LogLevel"
:指定日志级别。"Default": "Information"
:设置默认的日志级别为“Information”,这意味着只有信息级别及以上的日志会被记录下来。一般来说,信息级别包括一些重要的应用程序运行状态信息。"Microsoft.AspNetCore": "Warning"
:对于“Microsoft.AspNetCore”相关的日志,设置日志级别为“Warning”。这意味着只有警告级别及以上的与 ASP.NET Core 框架相关的日志会被记录下来,这样可以减少一些框架内部的详细日志输出,避免日志过多而难以查看重要信息。
"AllowedHosts": "*"
:表示允许的主机名。这里设置为“*”,意味着允许任何主机访问该应用程序。在实际生产环境中,通常会设置为具体的主机名或 IP 地址范围,以提高安全性。
2、Views文件夹
(1) index.cshtml
views文件夹里面的内容都是直接呈现在web页面上的,我们从index的实际运行效果上来看看,index中页面中的内容究竟有哪些,都来自于哪里?先看页面运行效果:
从效果图上看,显然index页面由三部分组成:导航栏Navbar、主内容content、底栏footer。我们来看看代码:
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
从上面的代码看来,貌似也没有导航栏和底栏的内容啊,这里肯定另有蹊跷,先按下不讲,后面再说。
@{… } 是 Razor 代码块的语法标记。
ViewData[“Title”] = “Home Page”;
这段代码的用意是在视图中设置名为 “Title” 的 ViewData 项的值为 “Home Page”。
在这个例子中,设置 “Title” 的值可以让视图在渲染页面时获取到页面的标题信息。通常,这个标题可以在页面的
关于数据传递ViewData
ViewData 是项目级别的全局字典类型的对象,无须声明拿来即可使用,也就是说在任何页面或者代码中都可以调用它,为它增加一组键值对,也可以覆盖或者删除一组键值对,它专用于在控制器和视图之间传递数据。我们讲到控制器的时候会再次发现它的身影。
(2)_layout.cshtml
这个文件,实际就是我们看到的首页或者说其他页面的布局文件,否则也不会叫做layout了。所有阿布局都归它管,包括导航栏navbar,正文内容body, 底栏footer.
关于导航栏
我们的确没有在index文件中发现导航栏,导航栏在哪里呢?在views/shared文件夹下,有一个叫做_Layout.cshtml的文件。我们来看看代码,我们会发现在这个文件的标签里面包含了这么一段以
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">WebApplicationDemo</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
很显然,我们在这里找到了navbar,这里的每一个nav-item很显然就是一个导航项,如下:
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
class=“nav-link text-dark”:
为这个链接元素添加了 CSS 类名。“nav-link” 通常用于表示导航链接的样式,“text-dark” 可能是一个自定义的类名,用于设置链接文本为深色。
asp-area=“”:
在 ASP.NET Core 中,“area”(区域)用于组织大型应用程序的不同功能模块。这里留空表示没有特定的区域。
asp-controller=“Home”:
指定了链接所指向的控制器名称为 “Home”。控制器负责处理特定类型的请求并返回响应。
asp-action=“Index”:
指定了要在 “Home” 控制器上执行的动作方法名称为 “Index”。动作方法是控制器中的方法,用于处理具体的请求逻辑并返回视图或其他响应类型。
总体来说,这段代码创建了一个导航链接,当用户点击这个链接时,会触发一个请求,由 “Home” 控制器的 “Index” 动作方法来处理,并将用户导航到相应的页面。通常在 ASP.NET Core 的应用程序中,这种方式用于构建导航菜单和页面之间的链接关系。
关于正文body
我们在layout文件的中部,可以看到下面的代码,它就是负责将每个正文视图包含进来,然后统一送去渲染的。
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
关于footer
底栏和导航栏语法上没有什么差别,只不过有个专门的footer标签而已,链接的语法和导航差不多,这里不赘述了。
<footer class="border-top footer text-muted">
<div class="container">
© 2024 - WebApplicationDemo - <a asp-area="" asp-controller="Home123" asp-action="Privacy">Privacy</a>
</div>
</footer>
(3)privacy文件
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
看到这个文件的内容,我们发现和index文件没有几乎差别,仅仅把title的值设置为了Privacy Policy而已,这里就不赘述了。
3、Controller文件夹
我们在controller和Models中寻找index的身影的时候,只有Controller下有一个homeController,很显然,它跟index有着紧密的联系,我们来看看它的代码内容:
namespace WebApplicationDemo.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
接下来,我们来逐句的解释上面的代码:
public class HomeController : Controller
声明了一个名为HomeController
的公共类,它继承自Controller
基类。这表明这个类是一个 ASP.NET Core 的控制器,用于处理 HTTP 请求。
private readonly ILogger<HomeController> _logger;
声明了一个私有的只读字段_logger
,类型为ILogger<HomeController>
。这是一个日志记录器,用于记录与这个控制器相关的日志信息。
public HomeController(ILogger<HomeController> logger)
定义了HomeController
类的构造函数,它接受一个ILogger<HomeController>
类型的参数。这是依赖注入的一种方式,ASP.NET Core 框架会在创建HomeController
实例时自动提供一个合适的日志记录器实例。
_logger = logger;
在构造函数中将传入的日志记录器参数赋值给_logger
字段,以便在控制器的方法中使用。
public IActionResult Index()
定义了一个名为Index
的公共方法,返回类型为IActionResult
。这个方法将处理指向“/Home/Index”的 HTTP 请求。这就和_layout中的navitem中的内容对应上了。
return View();
返回一个视图结果,表示调用这个方法时将渲染一个视图并返回给客户端。具体渲染哪个视图取决于方法名和约定,通常会查找与方法名相同的视图文件(例如“Index.cshtml”)。
public IActionResult Privacy()
类似地,定义了一个处理“/Home/Privacy”请求的方法。
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
定义了一个处理错误情况的方法Error
,并应用了ResponseCache
特性来禁用响应缓存。这意味着这个方法返回的错误页面不会被缓存。
return View(new ErrorViewModel { RequestId = Activity.Current?.Id?? HttpContext.TraceIdentifier });
返回一个包含错误信息的视图结果。这里创建了一个ErrorViewModel
的实例,并将请求 ID 设置为当前活动的 ID(如果存在),否则使用 HTTP 上下文的跟踪标识符。这个错误视图可能在_layout.cshtml
中通过某种方式被呈现,或者在特定的错误页面视图(例如“Error.cshtml”)中与_layout.cshtml
结合使用。
关于路由的修改
只要有Controller配合view就可以实现页面的路由访问了。如果我们有了自己的控制器和视图,需要修改项目默认的路由可以按照下面的方式修改:
a、在_layout.cshtml中的修改
假设你要将主页链接指向一个名为CustomPage的控制器的Index方法,那么可以在导航栏部分找到类似于以下的代码:
html
复制
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
将其修改为:
<a class="nav-link text-dark" asp-area="" asp-controller="CustomPage" asp-action="Index">Custom Home</a>
如果导航有多个部分,那就要逐一修改。
如果在整个布局中有对 “Home” 特定的引用,比如在面导航等地方,也需要相应地将其改为 “CustomPage” 相关的引用。
b、在Program.cs中的修改
在Program.cs中,通常在创建应用程序构建器和配置请求管道的部分不需要对主页的修改进行特定的更改。但是,如果你的自定义页面需要特定的服务注册或者中间件配置,可以在以下部分进行相应的修改controller:
app.MapControllerRoute(
name: "default",
pattern: "{controller=CustomPage}/{action=Index}/{id?}");
4、Models文件夹
Models文件夹中是所有文件夹中最简单的,因为里面默认情况下是没有文件的,如果我们有需要就可以建一个对应的模型。我们将这个内容放到下一篇博文来讲解。因为这篇文博实在有点长了。