Hexo快速指南

欢迎使用 Hexo!这是系统自动为您创建的第一篇博客文章。 您可通过 文档 了解更多Hexo的信息。如果您在使用Hexo的过程中遇到问题,您可以通过排除故障来查找解决办法,或者您也可以通过 GitHub 向我们提问。

快速指南

创建新文章

1
$ hexo new "My New Post"

参见: 创作

运行服务器

1
$ hexo server

参见: 服务器

生成静态文件

1
$ hexo generate

参见: 生成

部署到远程站点

1
$ hexo deploy

参见: 部署

ASP.NET Core应用程序启动过程

原文链接(英)

本文内容适用于ASP.NET Core 5.0

“启动”

启动 类用于配置应用程序依赖的 服务(services) 和用于处理客户端http请求的 流水线(pipeline)

ASP.NET Core 应用程序使用 启动 类(这个 按照约定命名为 Startup )完成如下启动任务:

  1. [可选] Startup 类包括一个 ConfigureServices 方法用于配置应用程序依赖的 服务(services)服务 是为应用程序提供某项功能的可重用组件。 服务 通过 ConfigureServices 方法进行注册,注册后的服务全局可用,使用的方式是通过 依赖注入(DI)ApplicationServices
  2. Startup 类包括一个 Configure 方法,此方法用于创建处理客户端http请求的 流水线(pipeline)

Startup 类的 ConfigureServices 方法和 Configure 方法在应用程序启动时被ASP.NET Core 运行时调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}

上面的代码针对的是 Razor Pages 编程框架,使用 MVC 框架的代码和这段代码类似。

Startup 类是当应用程序的host被构建时指定的。通常情况下,Startup 类通过 host 构造器(builder)的 WebHostBuilderExtensions.UseStartup<TStartup> 方法来指定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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>();
});
}

主机(host) 通过 Startup 类的 构造器(constructor)Startup 类提供其所依赖的服务。应用程序通过 Startup 类的 ConfigureServices 方法注册应用程序依赖的其它服务。 主机 提供的 服务 和应用程序提供的 服务Startup 类的 Confugure 方法和应用程序的全局都可用。

当使用 通用主机(Generic Host [IHostBuilder]) 时,只有下面的服务可以被注入到 Startup 类的 构造器 :

  • IWebHostEnvironment
  • IHostEnvironment
  • IConfiguration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Startup
{
private readonly IWebHostEnvironment _env;

public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
_env = env;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
if (_env.IsDevelopment())
{
}
else
{
}
}
}

多数 服务Startup 类的 Confugure 方法被调用前是不可用的。

多重启动

当应用程序为不同的环境定义不同的 启动类 (例如: StartupDevelopment ),对应该环境的 启动类 会在运行时被选择。类名的后缀匹配当前运行环境的 启动类 被优先应用。比如,如果应用程序运行在开发环境下,并且定义了 StartupDevelopmentStartup 两个类,那么 StartupDevelopment 将会被运行时应用。

Startup 类的 ConfigureServices 方法

ConfigureServices 方法是可选的。

它由 主机Configure 方法被调用之前调用,用来配置应用程序所依赖的 服务主机 可能在 Startup 类的构造函数被调用前配置一些 Startup 类要用到的服务。

对于那些经常用到的 服务IServiceCollection 定义了一些形似 Add{Service} 的扩展方法,例如:
AddDbContextAddDefaultIdentityAddEntityFrameworkStoresAddRazorPages

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{

services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();

services.AddRazorPages();
}

服务 添加到 服务容器 使得这些服务在 Startup 类的 Configure 方法中可用,并且在应用程序的全局可用,这些服务可以通过 依赖注入 机制或从 ApplicationServices 中取得。

Startup 类的 Configure 方法

Configure方法用于配置应用程序如何响应HTTP请求,它通过将 中间件(middleware) 组件添加到 IApplicationBuilder 实例来配置处理HTTP请求的 流水线(pipeline)IApplicationBuilderConfigure方法可用,但是它并没有被注册到 服务容器宿主 创建IApplicationBuilder实例并将它做为参数直接传递给Configure方法。

ASP.NET Core应用程序模板配置了支持如下功能的HTTP处理 流水线 :

  • 开发者异常页面(Developer Exception Page)
  • 异常处理(Exception handler)
  • HTTP Strict Transport Security (HSTS)
  • HTTPS重定向(HTTPS redirection)
  • 静态文件(Static files)
  • ASP.NET Core MVC and Razor Pages
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}

上面的代码针对的是 Razor Pages 编程框架,使用 MVC 框架的代码和这段代码类似。

每一个 Use{XXX} 扩展方法添加一个 中间件 到HTTP请求处理 管道线 ,例如:UseStaticFiles 配置了用于处理静态文件的中间件。

流水线 中的每个中间件处理完自己的任务后负责调用流水线中的下一个中间件,或者如果满足某个特定条件的话 短路 流水线的处理流程,结束HTTP处理。

其它的服务,比如IWebHostEnvironmentILoggerFactory或者其它任何定义在ConfigureServices方法中的中间件,都能通过Configure方法的参数签名来指定。然后这些参数中指定服务如果可用的话就会被依赖注入机制注入。

不通过Startup类来配置服务

如果不想通过Startup类来配置应用程序依赖的服务及HTTP处理流水线,那么可以通过调用宿主建造器(builder)的ConfigureServices方法和Configure方法来实现同样的功能。对ConfigureServices的多次调用会依次将服务加入到服务容器,如果对Configure多次调用,那么最后一次的调用生效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureServices(services =>
{
services.AddControllersWithViews();
})
.Configure(app =>
{
var loggerFactory = app.ApplicationServices
.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<Program>();
var env = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();
var config = app.ApplicationServices.GetRequiredService<IConfiguration>();

logger.LogInformation("Logged in Configure");

if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}

var configValue = config["MyConfigKey"];
});
});
});
}

通过 启动筛选器(startup filters) 扩展Startup

使用IStartupFilter:

这个主题不太容易理解,请参见这篇对IStartupFilter进行详细研究的文章

  • 可在应用程序通过Startup.Configure配置的中间件流水线之前或之后配置其它的中间件,而不用显式调用Use{Middleware}。ASP.NET Core使用IStartupFilter在http处理流水线的开头添加默认处理中间件,而不必要求应用程序的作者显式地注册默认的中间件。通过IStartupFilter,不同的组件可以以应用程序作者的名义调用Use{Middleware}

  • 创建一个Configure方法调用的流水线。IStartupFilter.Configure可以设置一个中间件在某个库添加的http处理中间件这前或之后运行。

Configure方法调用的流水线

IStartupFilter实现了一个Configure方法,此方法接收并返回一个Action<IApplicationBuilder>IApplicationBuilder定义了一个用于配置应用程序http请求处理流水线的类。

每个IStartupFilter可以添加一个或多个中间件到http请求处理流水线,筛选器按照它们被添加到服务容器中的顺序被调用。

下面这个例子演示了如何通过IStartupFilter注册一个中间件,例子中的RequestSetOptionsMiddleware中间件从http请求的查询字符串参数中取得需要的值,并将这个值赋给httpContext.Items["option"]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class RequestSetOptionsMiddleware
{
private readonly RequestDelegate _next;

public RequestSetOptionsMiddleware( RequestDelegate next )
{
_next = next;
}

// Test with https://localhost:5001/Privacy/?option=Hello
public async Task Invoke(HttpContext httpContext)
{
var option = httpContext.Request.Query["option"];

if (!string.IsNullOrWhiteSpace(option))
{
httpContext.Items["option"] = WebUtility.HtmlEncode(option);
}

await _next(httpContext);
}
}

RequestSetOptionsMiddlewareRequestSetOptionsStartupFilter类中进行配置:

1
2
3
4
5
6
7
8
9
10
11
public class RequestSetOptionsStartupFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return builder =>
{
builder.UseMiddleware<RequestSetOptionsMiddleware>();
next(builder);
};
}
}

IStartupFilter通过IHostBuilder.ConfigureServices注册在服务容器中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureServices(services =>
{
services.AddTransient<IStartupFilter,
RequestSetOptionsStartupFilter>();
});
}

当http请求的查询字符串中包含option参数的值时,RequestSetOptionsMiddleware会在ASP.NET Core中间件渲染 响应(response) 之前处理httpContext.Items["option"]的赋值操作。

中间件按照IStartupFilter注册的顺序执行:

  • 多个IStartupFilter实现可能操作相同的对象,如果中间件的执行顺序与执行结果相关,那么就要根据需要排列IStartupFilter的执行顺序以达到需要的执行结果。

  • 可能通过一个或多个IStartupFilter实现来添加中间件,这些中间件在应用程序通过IStartupFilter注册的中间件之前或之后运行,要在添加的中间件之前执行某个IStartupFilter中间件:

    • 在把添加到服务容器之前注册你想要执行的服务。
    • 要在添加的中间件之后执行某个IStartupFilter中间件,在把添加到服务容器之后,再注册你想要执行的服务。