# 基础信息

  • IHostBuilder:主机构建器,通过Build()后变成IHost
  • IWebHostingEnvironment:包含了环境名称、应用名称以及当前应用程序所处的根目录(Env.ContentRootPath)及Web静态内容的根目录(Env.WebRootPath)
  • ServiceProvider:服务容器,也是IOC容器,Autofact也是服务容器
  • IServiceCollection:服务接口,可以添加各种服务
  • IApplicationBuilder:管道构建器,可以添加各种中间件
  • IConfigurationBuilder:配置信息构建器,通过Build()后变成IConfiguration
  • ContainerBuilder:Autofact构建器
  • IOptions:选项服务
  • IHttpContextAccessor:用来访问当前请求的上下文的HttpContext
  • AppContext:应用的上下文 AppContext.BaseDirectory项目路径

# ASP.NET Core Web应用启动流程

Startup中ConfigureServices 在Builder()之后,Run()之前,Startup中Configure在Run()之后 Web应用启动流程

# Kestrel

Kestrel 是进程内托管,IIS是进程外托管

  • Kestrel可以直接连接HTTP请求,也可以连接IIS、Nginx、Apache反向代理后的HTTP
  • Kestrel仅仅是一个高性能的WEB服务,功能单一,不具备更多的功能。例如:配置域名
  • 微服务内部可以只使用Kestrel

kestrel

# 配置WEB服务地址

//Program类
webBuilder.UseUrls("http://*:6000;");
 
//appsettings.json
"urls":"http://*:7000"

//命令行
dotnet run --urls="http://*:8000" 

//环境变量
"ASPNETCORE_URLS":"http://*:9000"

四种方式的优先级:命令行 > appsettings.json > Program类 > 环境变量

# 配置信息构建器(IConfigurationBuilder)

//1、Statup类
private readonly IConfiguration _configuration;
public Startup(IConfiguration configuration){
	_configuration=configuration;
}

_configuration["WebSetting:Title"]//WebSetting的下级Title

//2、实体类
var appSetting=new AppSetting();
_configuration.Bind(appSetting);//全部绑定
_configuration.GetSection("Behavior").Bind(Behavior);//部分绑定

appSetting.Title

//3、选项服务
public void CongfigureServices(IServiceCollection services){
	//将配置对象注册到容器中,任何可以注入的地方,都可以获取配置
	services.Configure<AppSetting>(_configuration);
	//将配置对象节点里的信息注册到容器中
	services.Configure<JWTTokenOptions>(_configuration.GetSection("JWTTokenOptions"));
}
//中间件中获取
public void Configure(IApplicationBuilder app,IWebHostEnvironment env,IOptions<AppSetting> appOptions){
	appOptions.Value.Title
}
//控制器中获取
public class HomeController:Controller{ //控制中
	private readonly AppSetting _appSetting;
	public HomeController(IOptions<AppSetting> appOptions){
		_appSetting=appOptions.Value;
	}
}

//4、配置服务
public static IConfiguration configuration { get; set; }
public AppSettingsHelper(string contentPath)
{
	string Path = "appsettings.json";
	configuration = new ConfigurationBuilder().SetBasePath(contentPath).Add(new JsonConfigurationSource { Path = Path, Optional = false, ReloadOnChange = true }).Build();
}

configuration["WebSetting:Title"]

# 服务的获取方式

//Controller构造方法
public  IndexController(IServiceProvider serviceProvider){
 	
}

# 自定义服务封装注册

public class MessageService{
	public IServiceCollection _serviceCollection{get;set;}
	public MessageService(IServiceCollection serviceCollection){
		_serviceCollection=serviceCollection;
	}
	public void UseEmail(){
		_serviceCollection.AddTransient<IMessageService,EMailService>();
	}
	public void UseSMS(){
		_serviceCollection.AddTransient<IMessageService,SMSService>();
	}
}
//静态扩展类,每个服务都有个静态扩展类
public static class MessageServiceExtentions{
	public static void AddMessage(this IServiceCollection serviceCollection,Action<MessageService> messageService){
		var service=new MessageService(serviceCollection);
		messageService(service);
	}
	//设置默认值
	public static void AddMessage(this IServiceCollection serviceCollection){
		var service=new MessageService(serviceCollection);
		service.UseEmail();
	}
}

//调用
service.AddMessage(message=>message.UseEmail());
service.AddMessage();

# 管道 Pipeline(ApplicationBuilder)

ASP.NET Core建立管道的代码就是Startup类型的Configure方法,该方法通过IApplicationBuilder实例来添加不同功能的中间件,通过中间件的串联形成处理管道

  • HTTP请求从管道中进去,HTTP响应从管道中出来,任何中间件也不添加会执行默认自带异常的中间件
  • 极具扩展性的请求处理管道,可以满足各种场景下的HTTP请求处理需求,路由、身份认证、授权、缓存等都是通过请求处理管道中的中间件来实现的 管道

# 中间件(Middleware)

功能性的组件,有的中间件需要依赖某些服务。作用:

  • 选择是否将请求传递给管道中的下一个中间件,或者直接做出响应(管道短路),不再继续往下传递
  • 在管道中的下一个中间件的前后执行工作

# 什么是RequestDelegate

ASP.NET Core的中间件通过一个类型Func<RequestDelegate, RequestDelegate>的委托对象来表示,而RequestDelegate也是一个委托,它代表一项请求处理任务。

每个中间件都承载着独立的请求处理任务,它本质上也体现了在当前HttpContext下针对请求的处理操作,那么为什么中间件不直接通过一个RequestDelegate对象来表示,而是表示为一个类型为Func<RequestDelegate, RequestDelegate>的委托对象呢?原因很简单,中间件并不孤立地存在,所有注册的中间件最终会根据注册的先后顺序组成一个链表,每个中间件不仅仅需要完成各自的请求处理任务外,还需要驱动链表中的下一个中间件。

对于一个由多个Func<RequestDelegate, RequestDelegate>对象组成的中间链表来说,某个中间件会将后一个Func<RequestDelegate, RequestDelegate>对象的返回值作为输入,而自身的返回值则作为前一个中间件的输入。某个中间件执行之后返回的RequestDelegate对象不仅仅体现了自身对请求的处理操作,而是体现了包含自己和后续中间件一次对请求的处理。那么对于第一个中间件来说,它执行后返回的RequestDelegate对象实际上体现了整个应用对请求的处理逻辑。

# 创建自定义中间件

  • 必须要有一个公共的构造函数,参数必须是RequestDelegate类型
  • 必须要有的一个InvokeAsync的方法(实现中间件的业务逻辑),返回Task类型,第一个参数必须是HttpContext
public class TestMiddleware{
	private readonly RequestDelegate _next; 
	public TestMiddleware(RequestDelegate next){
		_next=next;
	}
	public async Task InvokeAsync(HttpContext context){
		await HttpContext.Response.WriteAsync("Hell Test");
		await _next(httpContext);//执行下一个
	}
}
//此时调用  app.UseMiddleware<TestMiddleware>();
//封装
public static IApplicationBuilder UseTestMildd(this IApplicationBuilder app)
{
	return app.UseMiddleware<TestMiddleware>();
}
//调用
app.UseTestMildd();

# 环境变量

  • env.IsDevelopment:开发环境
  • env.IsStaging:预览
  • env.IsProduction:生产环境 正式环境
  • env.IsEnvironment:自定义环境名称 IsEnvironment("Demo")
//多环境 每种环境对应一个Startup类
public class Startup{
	public void ConfigureServices(IServiceCollection services){};
	ublic void Configure(IApplicationBuilder app, IWebHostEnvironment env){};
}
public class StartupDemo{
	public void ConfigureServices(IServiceCollection services){};
	ublic void Configure(IApplicationBuilder app, IWebHostEnvironment env){};
}
//Program类中
UseStartup<Startup>() 替换成 UseStartup(Assembly.GetExecutingAssembly().FullName);

Assembly.GetExecutingAssembly(); //获取当前程序集

# 诊断中间件

  • app.UseDeveloperExceptionPage() 开发时的异常页面,显示异常信息
  • app.UseStatusCodePages() 返回400-600之间的状态码
  • app.UserExceptionHandler 自定义异常处理器
  • app.UseWelcomePage() 初始页面,放在最前面

# HttpContextAccessor

ASP.NET Core中提供了一个IHttpContextAccessor接口,HttpContextAccessor 默认实现了它
程序启动时在IServicesCollection中注册,这样在程序中就能获取到HttpContextAccessor

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

public class HomeController : Controller
{
	private IHttpContextAccessor _accessor;
	public HomeController(IHttpContextAccessor accessor)
	{
		_accessor = accessor;
	}
	public IActionResult Index()
	{
		//获取到 HttpContext
		var httpcontext = _accessor.HttpContext;
		return View();
	}
}

# 日志组件

所有第三方的日志组件都集成ILogger接口
如在本地能写log,但是发布到IIS无法写log,请注意引用程序池的账号,默认的“ApplicationPoolIdentity”应该是没有权限的,将其改为“LocalSystem”即可

  • 引入程序包
Log4Net:Microsoft.Extensions.Logging.Log4Net.AspNetCore
NLog.Web.AspNetCore
  • 设置配置文件,属性设置为:如果较新则复制
  • 调整程序
//Program类
 public static IHostBuilder CreateHostBuilder(string[] args) =>
	Host.CreateDefaultBuilder(args)//创建默认的主机构建器
		.ConfigureLogging(logging =>
		{
			logging.ClearProviders(); //移除已经注册的其他日志处理程序  默认Log4Net
			logging.SetMinimumLevel(LogLevel.Trace); //设置最小的日志级别
			//设置日志配置文件路径,如果不配置则默认在根目录下
			//logging.AddNLog("Config/NLog.config");
			//logging.AddLog4Net("Config/Log4Net.config");
		})
		.UseNLog()//使用NLog
		
//或者 Startup类的Configure
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory){
    //NLog
    loggerFactory.AddNLog();
    env.ConfigureNLog("nlog.config");	
	//Log4Net
	loggerFactory.AddLog4Net("Config/Log4Net.config");
}
  • 调用方式,同上面的"port 参数读取"

# 新增的LINQ 方法

# TryGetNonEnumeratedCount

尝试在不强制枚举的情况下确定序列中的元素数

List<object> numbers1 = new List<object>() { 5, 4, "nihao" };
int num = 0;
numbers1.TryGetNonEnumeratedCount(out num);

//num输出为3

# Chunk

将序列的元素拆分为指定大小的区块

var list = new List<dynamic>
{
   new { Id = 1, Property = "value1" },
   new { Id = 2, Property = "value2" },
   new { Id = 3, Property = "value1" }
};
var a = list.Chunk(2);

//返回 两个元素,第一个list长度为2,第二个为1

# ElementAt

返回元素指定索引或者结束的索引

var list = new List<dynamic>
{
   new { Id = 1, Property = "value1" },
   new { Id = 2, Property = "value2" },
   new { Id = 3, Property = "value1" },
   new { Id = 4, Property = "value4" },
   new { Id = 5, Property = "value2" },
   new { Id = 6, Property = "value6" },
   new { Id = 7, Property = "value7" },
   new { Id = 8, Property = "value8" },
   new { Id = 9, Property = "value9" }

};
var  b=list.ElementAt(2);
var  a=list.ElementAt(^2);

//a返回的是id=8的item b返回的是id=9的item

# MaxBy 和 MinBy

返回元素中最大值或最小值

List<int> numbers1 = new List<int>() { 5, 4, 1, 3, 9, 8, 6, 7, 12, 10 };
var maxnum= numbers1.MaxBy(x => x);
var mixnum= numbers1.MinBy(x => x);

//maxnum输出为12,minnum为1

# DistinctBy

根据某元素去重,相当于以前的自定义方法

var list = new List<dynamic>
{
   new { Id = 1, Property = "value1" },
   new { Id = 2, Property = "value2" },
   new { Id = 3, Property = "value1" }
};

var distinctList = list.DistinctBy(x => x.Property).ToList();
// returns objects with Id = 1, 2, but not 3

//自定义方法
public static IEnumerable<t> DistinctBy<t>(this IEnumerable<t> list, Func<t, object> propertySelector)
{
   return list.GroupBy(propertySelector).Select(x => x.First());
}

# ExceptBy

返回两个序列的元素的集合差值的序列

# IntersectBy

返回两个序列元素的交集

# UnionBy

连接不同集合,过滤某元素相同项

# LastOrDefault

返回序列中的最后一个元素;如果未找到该元素,则返回默认值

# SingleOrDefault

返回序列中的唯一元素;如果该序列为空,则返回默认值;如果该序列包含多个元素,此方法将引发异常

# Zip

将指定函数应用于两个序列的对应元素,以生成结果序列

int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };

var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);

foreach (var item in numbersAndWords)
    Console.WriteLine(item);

// This code produces the following output:

// 1 one
// 2 two
// 3 three