第 3 章 ASP.NET Core 核心特性

3.1 启动与宿主

ASP.NET Core 应用程序启动时,它首先会配置并运行其宿主,宿主主要用来启动、初始化应用程序,并管理其生命周期

ASP.NET Core 应用程序本质上就是控制台应用程序

public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}

由 CreateDefaultBuilder 方法创建 IWebHostBuilder 对象时所包含的主要默认选项如下:

  • 配置 Kestrel 服务器作为默认的 Web 服务器来负责处理 Web 请求与响应
  • 使用当前目录作为应用程序的内容目录,该目录决定了 ASP.NET Core 查找内容文件的位置
  • 从以 ASPNETCORE_ 开头的环境变量中以及命令行参数中加载配置项
  • 从 appsetting.json、appsettings.{Environment}.json、用户机密(仅开发环境)、环境变量和命令行参数等位置加载应用配置
  • 配置日志功能,默认添加控制台输出和调试输出
  • 如果应用程序呗托管在 IIS 中,启动 IIS 集成,它会配置应用程序的主机地址和端口,并允许捕获启动错误等

CreateDefaultBuilder 方法中所包含的默认配置能够通过 IWebHostBuilder 接口提供的扩展方法进行修改或增加

如 ConfigureAppConfiguration,ConfigureKestrel,ConfigureLogging,UseContentRoot 和 UseUrls 等

 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddXmlFile("appsettings.xml", optional: true, reloadOnChange: true);
})
.UseEnvironment(EnvironmentName.Development)
.UseContentRoot(@"C:\public")
.UseSetting("https_port", "8080")
.UseUrls("http://*:5000;http://localhost:5001;https://hostname:5002")
.UseStartup<Startup>();

ASP.NET Core 内置了对程序运行环境的支持,通过设置不同的环境,能够使应用程序在运行时获取相应的配置,从而具有不同的行为和逻辑

内部提供3个环境:

  • Development:开发
  • Staging:预演
  • Production:生产

Kestrel 是轻量级、托管的、开源且跨平台的 Web 服务器,它作为 ASP.NET Core 的组成部分,能够使 ASP.NET Core 应用程序运行在任何平台上

当 Kestrel 作为 ASP.NET Core 的服务器时,它会在 ASP.NET Core 的进程内运行,并负责监听 HTTP 请求以及对每一次的请求返回 HTTP 响应

在实际生产环境部署应用程序时,推荐使用主流的 Web 服务器(如 IIS 和 Apache 等)放在 Kestrel 之前作为反向代理服务器,增加应用程序的安全性,也提供了负载均衡、过滤请求和 URL 重定向等功能

IWebHostBuilder 接口有多个扩展方法,其中有一个很重要的是 UseStartup 方法,它主要向应用程序提供用于配置启动的类,而指定的这个类应具有以下两个方法:

  • ConfigureServices:用于向 ASP.NET Core 的依赖注入容器添加服务
  • Configure:用于添加中间件,配置请求管道
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
}); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy(); app.UseMvc();
}

3.2 中间件

所谓中间件,就是处理 HTTP 请求和响应的组件,本质上是一段用来处理请求与响应的代码,多个中间件之间的链式关系使之形成了管道

ASP.NET Core 中内置了多个中间件,它们主要包含 MVC 认证、错误、静态文件、HTTPS 重定向和跨域资源共享(CORS)等,ASP.NET Core 也允许向管道添加自定义中间件

上一节的 Configure 方法中就是添加中间件的地方

中间件的添加顺序将决定 HTTP 请求以及 HTTP 响应遍历它们的顺序

每一个中间件都是通过调用 IApplicationBuilder 接口的 Use 和 Run 方法添加到请求管道中的

下面的例子是使用 Run 方法来添加一个中间件,该中间件会输出与本次请求相关的信息

app.Run(async (context) =>
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("----REQUEST----");
sb.AppendLine($"Host: {context.Request.Host}");
sb.AppendLine($"Method: {context.Request.Method}");
sb.AppendLine($"Path: {context.Request.Path}");
sb.AppendLine($"Protocol: {context.Request.Protocol}");
foreach (var item in context.Request.Headers)
{
sb.AppendLine($" {item.Key}: {item.Value}");
} await context.Response.WriteAsync(sb.ToString());
});

与 Run 方法不同的是,Use 方法在处理完请求后还会将请求传入下一个中间件,并由它继续处理

app.Use(async (context, next) =>
{
Console.WriteLine("中间件 A:开始");
await next();
Console.WriteLine("中间件 A:结束");
});

除了 Run 和 Use 方法外,IApplicationBuilder 还提供了 Map、MapWhen 以及 UseWhen 方法,它们都可以指定条件,并在条件满足时创建新的分支管道,同时在新的分支上添加并执行中间件

Map 会根据是否配置指定的请求路径来决定是否在一个新分支上继续执行后续的中间件,并且在新分支上执行完后,不再回到原来的管道上

MapWhen 则可以满足更复杂的条件,它会对 HttpContext 对象进行进行更细致的判断,然后决定是否进入新的分支继续执行指定的中间件

UseWhen 创建的分支在执行结束后会继续回到原来的管道上

app.Map(new PathString("/maptest"),
a => a.Use(async (context, next) =>
{
Console.WriteLine("中间件 B:开始");
await next(); // 下一个中间件
Console.WriteLine("中间件 B:结束");
})); app.UseWhen(context => context.Request.Path.Value == "/maptest",
a => a.Use(async (context, next) =>
{
Console.WriteLine("中间件 B:开始");
await next(); // 下一个中间件
Console.WriteLine("中间件 B:结束");
}));

自定义中间件

public class HttpMethodCheckMiddleware
{
// 在管道中的下一个中间件
private readonly RequestDelegate _next; /// <summary>
/// 在中间件的构造函数中,可以得到下一个中间件,并且还可以注入需要的服务,比如 IHostEnvironment
/// </summary>
/// <param name="requestDelegate"></param>
/// <param name="environment"></param>
public HttpMethodCheckMiddleware(RequestDelegate requestDelegate, IHostEnvironment environment)
{
this._next = requestDelegate;
} /// <summary>
/// 对 HTTP 请求方法进行判断,如果符合条件则继续执行下一个中间件
/// 否则返回 400 Bad Request 错误,并在响应中添加自定义消息头用于说明错误原因
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public Task Invoke(HttpContext context)
{
var requestMethod = context.Request.Method.ToUpper();
if (requestMethod == HttpMethods.Get || requestMethod == HttpMethods.Head)
{
return _next(context);
}
else
{
context.Response.StatusCode = 400;
context.Response.Headers.Add("X-AllowHTTPWeb", new[] {"GET,HEAD"});
context.Response.WriteAsync("只支持 GET、HEAD 方法");
return Task.CompletedTask;
}
}
}

添加自定义中间件

app.UseMiddleware<HttpMethodCheckMiddleware>();

为了更加方便地使用中间件,可以为它创建一个扩展方法

public static class CustomMiddlewareExtensions
{
public static IApplicationBuilder UseHttpMethodCheckMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<HttpMethodCheckMiddleware>();
}
}

调用扩展方法

app.UseHttpMethodCheckMiddleware();

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

《ASP.ENT Core 与 RESTful API 开发实战》(第3章)-- 读书笔记(上)的更多相关文章

  1. 使用ASP.NET Core构建RESTful API的技术指南

    译者荐语:利用周末的时间,本人拜读了长沙.NET技术社区翻译的技术标准<微软RESTFul API指南>,打算按照步骤写一个完整的教程,后来无意中看到了这篇文章,与我要写的主题有不少相似之 ...

  2. 4类Storage方案(AS开发实战第四章学习笔记)

    4.1 共享参数SharedPreferences SharedPreferences按照key-value对的方式把数据保存在配置文件中,该配置文件符合XML规范,文件路径是/data/data/应 ...

  3. 菜单Menu(AS开发实战第四章学习笔记)

    4.5 菜单Menu Android的菜单主要分两种,一种是选项菜单OptionMenu,通过按菜单键或点击事件触发,另一种是上下文菜单ContextMenu,通过长按事件触发.页面的布局文件放在re ...

  4. [Android]《Android艺术开发探索》第一章读书笔记

    1. 典型情况下生命周期分析 (1)一般情况下,当当前Activity从不可见重新变为可见状态时,onRestart方法就会被调用. (2)当用户打开新的Activity或者切换到桌面的时候,回调如下 ...

  5. 温故知新,使用ASP.NET Core创建Web API,永远第一次

    ASP.NET Core简介 ASP.NET Core是一个跨平台的高性能开源框架,用于生成启用云且连接Internet的新式应用. 使用ASP.NET Core,您可以: 生成Web应用和服务.物联 ...

  6. 快读《ASP.NET Core技术内幕与项目实战》WebApi3.1:WebApi最佳实践

    本节内容,涉及到6.1-6.6(P155-182),以WebApi说明为主.主要NuGet包:无 一.创建WebApi的最佳实践,综合了RPC和Restful两种风格的特点 1 //定义Person类 ...

  7. 零基础ASP.NET Core WebAPI团队协作开发

    零基础ASP.NET Core WebAPI团队协作开发 相信大家对“前后端分离”和“微服务”这两个词应该是耳熟能详了.网上也有很多介绍这方面的文章,写的都很好.我这里提这个是因为接下来我要分享的内容 ...

  8. ASP.NET Core WebApi构建API接口服务实战演练

    一.ASP.NET Core WebApi课程介绍 人生苦短,我用.NET Core!提到Api接口,一般会想到以前用到的WebService和WCF服务,这三个技术都是用来创建服务接口,只不过Web ...

  9. 从 0 使用 SpringBoot MyBatis MySQL Redis Elasticsearch打造企业级 RESTful API 项目实战

    大家好!这是一门付费视频课程.新课优惠价 699 元,折合每小时 9 元左右,需要朋友的联系爱学啊客服 QQ:3469271680:我们每课程是明码标价的,因为如果售价为现在的 2 倍,然后打 5 折 ...

  10. Asp.Net Core 5 REST API - Step by Step

    翻译自 Mohamad Lawand 2021年1月19日的文章 <Asp.Net Core 5 Rest API Step by Step> [1] 在本文中,我们将创建一个简单的 As ...

随机推荐

  1. Qt大型工程开发技术选型PartFinal:CLR调用COM组件

    Qt大型工程开发技术选型PartFinal:CLR调用COM组件 这里其实没什么内容了,直接上代码吧,如下文所示: #pragma once #using <mscorlib.dll> u ...

  2. C#设计模式04——工厂方法的写法

    1. What是C#工厂方法?C#工厂方法是一种设计模式,它通过创建具有相同基类的对象来实现代码的重用和灵活性. 2. Why使用C#工厂方法?使用C#工厂方法有以下好处:- 降低了代码的耦合性,让代 ...

  3. Go 汇编学习笔记

    0.前言 学习 Go 离不开看源码,源码又包含大量汇编代码,离开汇编是学不好 Go 的.同样,离开汇编去学习计算机是不完整的,汇编是基石,是离操作系统和硬件最近的一层. 虽然之前学过一点 Go 汇编, ...

  4. zipkin 与 sleuth 实现链路追踪

    本文为博主原创,转载请注明出处 1.Zipkin 与 Sleuth 简介 zipkin 的官网地址: https://zipkin.io/ Zipkin 和 Sleuth 都是由 Twitter 开源 ...

  5. python3使用json、pickle和sqlite3持久化存储字典对象

    技术背景 在各种python的项目中,我们时常要持久化的在系统中存储各式各样的python的数据结构,常用的比如字典等.尤其是在云服务类型中的python项目中,要持久化或者临时的在缓存中储存一些用户 ...

  6. Oracle索引&约束

    Oracle索引&约束 1索引的原理 索引是一种允许直接访问数据表某一数据行的树形结构,为了提高查询效率而引入,是独立于表的对象,可以存放在与表不同的表空间(TABLESPACE)中 索引记录 ...

  7. Go-GC

  8. 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.12.2)

    一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...

  9. [转帖]小米Redis的K8s容器化部署实践

    https://juejin.cn/post/6844904196924276743     背景 Why K8S How K8s Why Proxy Proxy带来的问题 K8s带来的好处 遇到的问 ...

  10. tempfs 的再学习

    tempfs 的再学习 背景 最近学习研究linux的内存buffer 和 cache相关的知识. 发现对linux的VFS的理解其实非常不到位. 再验证内存的使用的page caches和 drop ...