# 基础信息
- 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()之后
# Kestrel
Kestrel 是进程内托管,IIS是进程外托管
- Kestrel可以直接连接HTTP请求,也可以连接IIS、Nginx、Apache反向代理后的HTTP
- Kestrel仅仅是一个高性能的WEB服务,功能单一,不具备更多的功能。例如:配置域名
- 微服务内部可以只使用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