概述
ASP.NET Core 3.x 学习笔记(1)——从项目结构了解依赖注入、管道、路由
- ASP.NET Core 3.x 学习笔记(1)——从项目结构了解依赖注入、管道、路由
- 项目结构
- Program.cs
- Startup.cs
- 在 ASP.NET Core MVC 中简单实现
- 项目启动
- 环境变量
- 静态文件
- 包管理
- 静态文件合并
- 依赖注入 DI(Dependency Injection)
- DI 的优点
- ASP.NET Core 管道(pipeline)
- 配置中间件
- 路由
- ASP.NET Core 应用的多样性
- 端点 endpoint
本系列学习笔记均来源于B站UP主”软件工艺师“的学习视频,学习连接如下:
https://www.bilibili.com/video/BV1c441167KQ
ASP.NET Core 3.x 学习笔记(1)——从项目结构了解依赖注入、管道、路由
项目结构
创建一个 Empty 的 .NET Core 3.0 web 项目后,会生成如下结构的项目代码。
Program.cs
namespace ASPNETCore_Learning_Three
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
ASP.NET Core 应用本质上还是控制台应用,所以上面的 Main 方法还是和控制台应用的 Main 方法是一个概念。
ASP.NET Core 整个应用的配置是通过代码中的 CreateHostBuilder 方法来进行的。
在 Main 方法中调用 CreateHostBuilder(args).Build() 之后,程序从控制台应用变成了 ASP.NET Core 应用。
ConfigureWebHostDefaults 方法进行一些默认配置。
Startup.cs
namespace ASPNETCore_Learning_Three
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
//负责配置依赖注入相关的东西
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
}
Startup.cs 也是用于 ASP.NET Core 项目的配置,配置过程相对比较动态。而 Program.cs 则相对比较死板。
运行时通过约定对 ConfigureServices 和 Configure 方法进行调用。调用顺序是,先 ConfigureServices 后 Configure。
ConfigureServices 方法主要负责配置依赖注入相关的东西。
Configure 承担 ASP.NET Core 管道、路由的作用;
在 ASP.NET Core MVC 中简单实现
继续在上面项目结构的代码中,创建对应的 Services 和 Controllers。
其中,Services文件夹中 IClock 为一个 interface;ChinaClock 和 UtcClock 类实现 IClock 接口。HomeController 类实现 Microsoft.AspNetCore.Mvc 的 Controller 接口。
HomeController.cs
using ASPNETCore_Learning_Three.Services;
using Microsoft.AspNetCore.Mvc;
namespace ASPNETCore_Learning_Three.Controllers
{
public class HomeController : Controller
{
/// <summary>
/// 依赖注入。通过构造函数注入了一个实现了IClock接口的实例。
/// 因为Startup.cs中的services.AddSingleton<IClock, ChinaClock>();
/// 此处注入的即是 ChinaClock
/// </summary>
/// <param name="clock"></param>
public HomeController(IClock clock)
{
}
}
}
Startup.cs
using ASPNETCore_Learning_Three.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ASPNETCore_Learning_Three
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
//负责配置依赖注入相关的东西
services.AddControllersWithViews(); //使用 MVC 相关功能
//services.AddControllers(); //做 API 使用这个就可以
//services.AddMvc(); //这个有特别多完整的功能,此处不需要
services.AddSingleton<IClock, ChinaClock>(); //每当有一个类型请求了一个IClock服务,IoC容器则返回一个ChinaClock实例
//尽量使用 接口(IClock)的形式,使用接口可以使 Controller 与具体的服务类(ChinaClock、UtcClock)之间解耦
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
}
如上代码:
- services.AddControllersWithViews():使用 MVC 相关功能
- services.AddSingleton<IClock, ChinaClock>()
- 每当有一个类型请求了一个IClock服务,IoC容器则返回一个ChinaClock实例
- 尽量使用接口(IClock)的形式,使用接口可以使 Controller 与具体的服务类(ChinaClock、UtcClock)之间解耦
- public HomeController(IClock clock) :通过构造函数注入了一个实现了IClock接口的实例(依赖注入)
- 因为 Startup.cs 中的services.AddSingleton<IClock, ChinaClock>();此处注入的即是 ChinaClock。
项目启动
APS.NET Core Web 程序有两种启动方式,如下图:
- 一种是通过 IIS 来启动
- 一种是 APS.NET Core 自己运行。因为 APS.NET Core 本身是一个控制台应用,所以可以自己运行。而且 APS.NET Core 控制台应用里面内嵌了一个小巧的 web 服务器:Kestrel。
配置项目调试环境:
在项目的 ”属性“ => ”调试“ 选项中,可以配置项目启动时的调试环境。也可在项目路径下的 “Properties” 文件夹中的 “launchSettings.json” 进行更改。
环境变量
如上“项目启动”中的图片,可以通过项目环境变量 APSNETCORE_ENVIRONMENT 的值来判断当前是某个环境。
APSNETCORE_ENVIRONMENT 有三个内置的值,分布可以通过三个默认方法获取:
-
env.IsDevelopment():表示当前为”Development“,开发环境。
-
env.IsProduction():表示当前为”Production“,生产环境。
-
env.IsStaging():示当前为”Staging“,生产环境。
也可以自定义环境,比如可以将 APSNETCORE_ENVIRONMENT 的值设置为 ”OK“,则可以通过如下方法获取:
- env.IsEnvironment(“OK”);
如上环境变量也都是在 Configure 方法中配置,如下:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//env.IsProduction(); env.IsStaging(); env.IsDevelopment() //是三种内置的环境变量
//env.IsEnvironment("OK"); //也可以自定义环境变量,然后通过 env.IsEnvironment() 获得
if (env.IsDevelopment()) //判断当前是否为 开发模式
{
app.UseDeveloperExceptionPage(); //异常页中间件:展示当前程序没有处理和捕获的异常的详细信息到某个固定页面
}
}
ASP.NET Core 也可以针对不同的环境有不同的配置方法,比如可以对 Development 单独有一个 Configure 方法。如下,重新定义一个方法,方法名为在 Configure 后面加上 环境变量即可,如下:
public void ConfigureDevelopment(IApplicationBuilder app, IWebHostEnvironment env)
{
}
如此之后,若当前环境为 Development,则调用 ConfigureDevelopment 方法,否则调用 Configure 方法。
同理,对于其它环境变量,如 Production,或 ConfigureServices 方法均可以如此处理。
Startup.cs 类也可以针对不同环境设置不同方法,如 Development 环境下可使用 StartupDevelopment 类。若不同环境下使用不同的 Startup 类,则 Program.cs 中 CreateHostBuilder 方法需要做如下更改,以便获得正确的 Startup 类
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
//webBuilder.UseStartup<Startup>();
webBuilder.UseStartup((typeof(Program)));
});
静态文件
在 ASP.NET Core Web 应用程序中,静态文件(css/html/images)应该放在 wwwroot 文件夹下。
包管理
- 服务器端(后端):Nuget
- 前端:npm
前端包管理:
Visual Studio 中可以直接新建 npm 配置文件(package.json),在 ”添加项“ 中直接搜索 ”npm“ 即可。添加后生成 package.json 文件,可同正常 node 项目一样,在 package.json 中配置依赖性,然后通过 npm 安装。
也可使用 Visual Studio 自带的管理工具。选中项目,右键“添加”,选择“客户端库”
静态文件合并
Visual Studio 2019 中 ASP.NET Core 支持将静态文件,如 css 文件,合并并压缩到一个文件中;也可以移动 css 文件所在位置。
如下示例,在项目中有 bootstrap.css 和 site.css 两个 css 文件,现在需要将两个文件合并并且压缩空格。
在项目中新建 bundleconfig.json 文件,文件中代码如下:
[
{
//合并代码
"outputFileName": "wwwroot/css/all.min.css",
"inputFiles": [
"wwwroot/lib/bootstrap/dist/css/bootstrap.css",
"wwwroot/css/site.css"
]
},
{
//移动bootstrap.css文件,并压缩代码中的空格
"outputFileName": "wwwroot/css/bootstrap.css",
"inputFiles": [
"wwwroot/lib/bootstrap/dist/css/bootstrap.css"
],
"minify": {
"enabled": true
}
}
]
代码分别表示:
- 合并 css 文件到 “wwwroot/css/all.min.css”
- 移动bootstrap.css文件,并压缩代码中的空格
然后通过 Nuget 安装 BuildBundlerMinifier 到项目。安装好后重新生成项目,即可看见合并后的结果。
若需要具体了解 Bundle,可在 MSDN 查看,如下图。
依赖注入 DI(Dependency Injection)
依赖注入的机制依赖于 IoC 容器(Inversion of Control 控制反转)。
依赖注入典型原理的应用:ASP.NET Core Web 应用启动时
- 在 IoC 容器中注册服务(即某些类或类型)
- 其它类或类型可以向 IoC 容器请求注册的服务的实例
- 在注册的时候可以设置这些服务实例的生命周期(服务实例的生命周期是 IoC 容器来控制的)
生命周期:
- Transient:注册的服务在每次被请求的时候都会生成一个新的实例;
- Scoped:ASP.NET Core Web 中,每一次 Web 请求则生成一个实例;当 Web 请求被处理完成时,生命周期截至;
- Singleton:服务实例一旦被创建,之后每次请求这个服务的时候,都使用这个实例;实例会一致存活到应用程序停止;
DI 的优点
- 解耦,使 Controller 和 Service 之间没有强依赖,而是都依赖于一个抽象的接口(如上文中的 HomeController 和 ChianClock 之间依赖于 IClock)
- 利于单元测试(另外了解单元测试)
- 不需要了解具体的服务类(内部结构、细节之类的)
- 不需要管理服务类的生命周期(由 IoC 容器控制)
ASP.NET Core 管道(pipeline)
在上文项目结构中提到的 Startup.cs 类中的 Configure 方法配置了 ASP.NET Core 针对处理 http 请求的管道。(后续了解 ASP.NET Core 源码,管道是如何配置的)
IApplicationBuilder 在 ASP.NET Core 源码(在 Program.cs)中就已经完成配置,此处可以直接对其进行依赖注入操作即可。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//......
}
管道对浏览器的 http 请求如何响应?
ASP.NET Core 应用程序从浏览器接收到 http 请求:请求从管道进入,处理完后从管道返回;具体的处理过程在管道中发生,若想要对请求进行处理响应,则需要在管道中添加相应的中间件。
如下图,http 请求从浏览器进入 ASP.NET Core 管道,在管道中经过身份验证中间件(Auth)、MVC中间件、静态文件处理中间件(Static Files)后对具体的数据进行处理。
配置中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment()) //判断当前是否为 开发模式
{
app.UseDeveloperExceptionPage(); //中间件:展示当前程序没有处理和捕获的异常的详细信息到某个固定页面
}
app.UseStaticFiles(); //静态文件中间件,添加后可以使用 js,html,css 等静态文件。该中间件放在路由中间件前面即可。
app.UseHttpMethodOverride(); //可以将 http 请求转化为 https 请求。
app.UseAuthentication(); //身份验证的中间件。该中间件必须放在 UseEndpoints 之前
app.UseRouting(); //路由中间件:
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
如上 Startup.cs 类中的 Configure 方法代码,添加了如下中间件:
- UseDeveloperExceptionPage():展示当前程序没有处理和捕获的异常的详细信息到某个固定页面
- UseStaticFiles():静态文件中间件,添加后可以使用 js,html,css 等静态文件。该中间件放在路由中间件前面即可。
- UseHttpMethodOverride():可以将 http 请求转化为 https 请求。
- UseAuthentication():身份验证的中间件。该中间件必须放在 UseEndpoints 之前
- UseRouting():路由中间件
- UseEndpoints:端点中间件。
中间件注册的先后顺序非常重要:如上文中 UseAuthentication 中间件必须放在 UseEndpoints 之前,因为很多情况下,端点的请求在处理之前需要对身份进行验证。
路由
路由是 Startup.cs 类中的 Configure 方法另一个重要的作用。
在 ASP.NET Core 3.0 之前,路由中间件(UseRouting())是作为 MVC 中间件的一部分存在的。在 3.0 版本之后将 路由中间件单独提取出来,这样就可以配合其它中间件一起使用。
为什么把 路由中间件单独提取出来?见下文“ASP.NET Core 应用的多样性”
路由中间件(UseRouting())检查在应用中已经注册的端点(见下文),这个端点可能是 MVC 注册的,也可能是 SignalR 注册的,抑或是其它;
路由中间件判断进入管道的 http 请求是在哪个端点上出现的(这是个重要的信息),并传递给后续的中间件,后续的中间件就可以知道端点的信息(如端点是谁注册的)
**端点中间件(UseEndpoints())**可以注册端点,当请求到达 UseEndpoints(),请求就可以被响应的端点进行处理
ASP.NET Core 应用的多样性
ASP.NET Core 应用存在多种技术,如下三种技术,都需要路由,故将路由中间件提取出来。
- MVC:/Home/Index
- Razor Pages:/SomePage
- SignalR:/Hub/Chat
端点 endpoint
端点指的是进入管道的 http 请求的 url 的结尾那部分,这部分会被中间件进行处理。
- /{controller}/{action}
- /home/index
在 MVC 中,如果想处理端点,就需要指定路由。指定路由有两种方式:
- 在 Controller 上写一些 Attribute:Attribute 路由(MVC 5)
- 指定一个路由表,表中设定的路由其实就是一些模板,这些模板会尝试匹配一些特定的 url 端点,
在 MVC 项目中,可将上述 Configure 方法中的端点中间件(UseEndpoints)中间的路由配置改成如下形式:
如下代码设置默认路由为 Home/Index
app.UseEndpoints(endpoints =>
{
//使用 MVC 可以将上述代码改成如下形式
//controller 默认状为 Home;action 默认值为 Index;id 可选
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}"); //路由表中添加一个路由方法
//当使用 Attribute 路由时,使用如下方法即可
//endpoints.MapControllers();
});
最后
以上就是细心茉莉为你收集整理的ASP.NET Core 3.x 学习笔记(1)——从项目结构了解依赖注入、管道、路由ASP.NET Core 3.x 学习笔记(1)——从项目结构了解依赖注入、管道、路由的全部内容,希望文章能够帮你解决ASP.NET Core 3.x 学习笔记(1)——从项目结构了解依赖注入、管道、路由ASP.NET Core 3.x 学习笔记(1)——从项目结构了解依赖注入、管道、路由所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复