应用--Program中的WebApplication

在6.0,微软团队对于NetCore做了很大的改变,其中有一个改变就是推出了新的托管模型--最小托管模型,使用该模型可以创建最小的web应用。(最小webapi请查看官网

需要掌握:

  • 什么是最小托管模型?以及他的作用
  • 什么是WebApplication和WebApplicationBuilder?他们和Host的区别是什么
  • WebApplication代码上以及对应逻辑上的构造流程,能简单描述就好了
  • WebApplication的六个属性以及其作用,为什么需要这6个属性?
  • WebApplicationBuilder的作用
  • WebApplication的6个属性以及继承4个接口有什么用
我自己默写一遍,整理完有点乱,
首先,最小托管模型是6.0微软推出来的一个新的应用模板,为的是方便配置和学习,他只有3句代码,利用他可以生成最小webapi。
第一句是var bulider = WebAppliaction.CreateBuilder();
这句代码的作用是通过调用WebAppliaction的工厂方法CreateBuilder()得到WebApplicationBuilder对象,因为创建一个WebApplication对象需要一个Host,Host则必须由HostBuilder创建,所以WebApplicationBuilder对象的作用是提供一个封装好的HostBuilder对象用来构建IHost,
它含有6个属性以及一个构造函数,属性包括IServiceCollection依赖注入容器Services、ConfigureManage配置管理Configure、IWebHostEnvironment托管环境environment、ILoggingBuilder日志记录logging、ConfigureWebHostBuilder类型webhost、ConfigureHostBuilder类型host,需要这6个属性的目的就是用来提供HostBuilder的创建
构造函数的作用是根据传进来的命令行参数来初始化这些属性,首先他会初始化一个_hostBuilder对象,然后创建一个bootstrapBuilder对象用来调用他的拓展方法收集服务和配置,赋值给services和configure属性,接下里根据bootstrapBuilder对象的一些属性,初始化剩余属性,初始化WebHost和Host。 第二句代码是var app = bulider.bulider();
在这句代码之前,我们可以注入自己的一些服务和系统服务,通过调用AddScope()等依赖注入方法或者使用系统提供的服务方法、如AddController(),
这句代码的作用是,根据得到WebApplicationBuilder对象来创建WebApplication,这句代码最重要的就是,把services和configure属性赋值给HostBuilder,然后我们可以看到这个对象继承了4个接口,一个是IHost接口,这就解释了为什么WebApplicationBuilder需要有一个ConfigurHostBuilder对象,还有一个IApplicationBuilder接口,这个接口是构建中间件管道服务的接口,所以我们的中间件可以直接注册在WebApplication的原因,IEndpointRouteBuilder则是默认构造了路由,还有一个异步释放的接口。 第三句代码是app.Run();
在这句代码之前可以注入中间件服务,比如UseAuthorization()之类的,
这句代码的作用是,通过调用WebApplication内部的BuildRequestDelegation()方法把注册的中间件管道作为请求处理器,至此一个WebApplication对象完成
所以根据这几行代码我们不难看出,WebApplication其实就是对Host的再次封装,只是为了我们更加简单的去配置一些我们需要的服务和中间件

构造流程

得到WebApplicationBuilder构造器 -> 配置服务 -> build()方法得到WebApplication对象 -> 配置中间件 -> 运行主机

// 得到应用构造器:WebApplicationBuilder
var builder = WebApplication.CreateBuilder(args);
// 配置日志
builder.Logging.AddLog4Net("ConfigFile/log4net.config");
// 得到应用:WebApplication
var app = builder.Build();
// 配置中间件
app.UseStaticFiles();
// 运行主机
app.Run();

你可能在疑惑,在3.0至5.0的版本都是直接调用Host.CreateDefaultBuilder()方法得到HostBuilder构造器,然后调用ConfigureWebHostBuilder()配置WebHost,然后在上面配置一些服务,构建然后运行。而6.0使用WebApplication.CreateBuilder(args)方法得到的是一个WebApplicationBuilder构造器,然后构建运行,他们有什么区别吗?

答:没什么区别,流程都是一样的,WebApplication对主机和服务做了一个更进一步的封装,使得更加方便配置和学习,而且额外暴露2个Host属性WebHost属性用来配置(这2个属性也是方便之前的版本迁移到6.0的关键)。举个很简单的例子

区别 在3.0至5.0的版本中 6.0版本中
中间管道的配置 必须放在Startup.cs类中的Configure方法中,或者通过ConfigureWebHostDefaults中的webBuilder 来配置服务 通过调用app.UseXXXX来配置
路由中间件 使用app.UseRouting()之后才能app.UseEndpoints() 因为WebApplication继承了WebIEndpointRouteBuilder可以直接将路由,而无需显式调用 UseEndpointsUseRouting

按照上方Program.cs流程顺序介绍相关类和方法

1. CreateBuilder(args) 方法:

使用默认值来生成构造一个WebApplicationBuilder对象

该方法有3个重载:

  • WebApplication.CreateBuilder():使用预配置的默认值来构造;
  • WebApplication.CreateBuilder(String []):根据传入的命令行参数初始化;
  • WebApplication.CreateBuilder(WebApplicationOption):根据传入的预配置来构造;
public class WebApplicationOptions
{
public WebApplicationOptions(); // 命令行参数
public string[]? Args { get; init; } // 环境名称。
public string? EnvironmentName { get; init; } // 应用程序名称。
public string? ApplicationName { get; init; } // 内容根路径。
public string? ContentRootPath { get; init; } // Web 根路径。
public string? WebRootPath { get; init; }
}

WebApplicationBuilder类:

要创建一个WebApplication对象,需要一个IHost对象IHost对象是通过IHostBuilder创建的,而WebApplication需要WebApplicationBuilder来构建,所以WebApplicationBuilder还需要一个IHostBuilder对象,我们针对WebApplication的一切配置,最终都会转移到这个对象上面才能生效,所以这就是为什么WebApplicationBuilder提供了这6个属性的原因。

构造函数

当通过调用WebApplication.CreateBuilder()方法的时候,根据命令行的参数传给WebApplicationBuilder的构造函数,而WebApplicationBuilder的构造函数内部会做:

  1. 创建HostBuilder _hostBuilder 类。
  2. 创建BootstrapHostBuilder对象,调用拓展方法ConfigureWebHostBuilder()ConfigureDefaults()方法,将初始化的设置和服务收集起来,然后把收集到的服务和配置注入到Services成员属性Configure成员属性中。
  3. 然后会创建承载托管环境的IWebHostEnvironment,对于Environment成员属性初始化。
  4. 调用Apply()方法得到HostBuilderContext上下文
  5. 使用HostBuilderContextWebHostBuilderContext,创建ConfigureWebHostBuilder和ConfigureHostBuilder并赋值给WebHost和Host属性。初始化Logging属性
  6. 得到一个Configure、Environment、WebHost、Host、Logging属性都被初始化的WebApplication对象

WebApplicationBuilder构造函数源码

public class WebApplicationBuilder
{
private readonly HostBuilder _hostBuilder = new HostBuilder();
private WebApplication _application;
// 提供应用程序正在运行的Web托管环境的信息
public IWebHostEnvironment Environment { get; } // 提供应用程序所需要的服务,即依赖注入容器
public IServiceCollection Services { get; } // 提供应用程序所需要的配置
public ConfigurationManager Configuration { get; } // 提供日志记录
public ILoggingBuilder Logging { get; } // 配置WebHost服务器特定属性,实现IWebHostBuilder
public ConfigureWebHostBuilder WebHost { get; } // 配置Host特定属性,实现IHostBuilder
public ConfigureHostBuilder Host { get; } public WebApplicationBuilder(WebApplicationOptions options)
{
//创建BootstrapHostBuilder并利用它收集初始化过程中设置的配置、服务和针对依赖注入容器的设置
var args = options.Args;
var bootstrap = new BootstrapHostBuilder();
bootstrap
.ConfigureDefaults(null)
// 此处用于中间件的注册
.ConfigureWebHostDefaults(webHostBuilder => webHostBuilder.Configure(app =>app.Run(_application.BuildRequestDelegate())))
.ConfigureHostConfiguration(config => {
// 添加命令行配置源
if (args?.Any() == true)
{
config.AddCommandLine(args);
} // 将WebApplicationOptions配置选项转移到配置中
Dictionary<string, string>? settings = null;
if (options.EnvironmentName is not null) {
(settings ??= new())[HostDefaults.EnvironmentKey] = options.EnvironmentName;
}
if (options.ApplicationName is not null){
(settings ??= new())[HostDefaults.ApplicationKey] = options.ApplicationName;
}
if (options.ContentRootPath is not null){
(settings ??= new())[HostDefaults.ContentRootKey] = options.ContentRootPath;
}
if (options.WebRootPath is not null) {
(settings ??= new())[WebHostDefaults.WebRootKey] = options.EnvironmentName;
}
if (settings != null)
{
config.AddInMemoryCollection(settings);
}
}); // 将BootstrapHostBuilder收集到配置和服务转移到Configuration和Services上
// 将应用到BootstrapHostBuilder上针对依赖注入容器的设置转移到_hostBuilder上
// 得到BuilderContext上下文
bootstrap.Apply(_hostBuilder, Configuration, Services, out var builderContext); // 如果提供了命令行参数,在Configuration上添加对应配置源
if (options.Args?.Any() == true)
{
Configuration.AddCommandLine(options.Args);
}
// 构建WebHostBuilderContext上下文
// 初始化Host、WebHost和Logging属性
var webHostContext = (WebHostBuilderContext)builderContext.Properties[typeof(WebHostBuilderContext)];
Environment = webHostContext.HostingEnvironment;
Host = new ConfigureHostBuilder(builderContext, Configuration, Services);
WebHost = new ConfigureWebHostBuilder(webHostContext, Configuration, Services);
Logging = new LogginigBuilder(Services);
} }

简单来说WebApplicationBuilder的作用就是为了提供构建封装的一个HostBuilder对象

注意:记住这6个属性,NetCore的生态库基本上就是围绕这几个来构建的

接下来我们按照这几个属性来逐一分析其作用

IWebHostEnvironment Environment 属性

接口,继承IHostEnvironment,提供一些该应用程序的环境信息,比如根目录、环境变量、名称等,包含几个属性

  • WebRootPath,用于设置和获取Web的根目录,默认是wwwroot的子文件夹(在5.0的时候。是通过Host.CreateDefaultBuilder()方法去设置的);
  • ApplicationName:应用名称;
  • ContentRootFileProvider:;
  • ContentRootPath:
  • EnvironmentName:环境名称;

比如我们经常用的判断是否是开发环境就是用的该类

demo

var builder = WebApplication.CreateBuilder(args);
bool isDevelopment = builder.Environment.IsDevelopment();
IServiceCollection Services 属性

依赖注入容器,可以注入服务,也可也获取服务实例,继承于ICollection<ServiceDescriptor>泛型接口,这个我们后续会在依赖注入章节详细描述。

通过往该属性添加系统服务支持,或者注入自己的服务

demo

var builder = WebApplication.CreateBuilder(args);
// 注入Sql数据库支持
builder.Services.AddDbContext<SqlDbContext>();
// 依赖注入
builder.Services.AddSingleton<PersonService>();
ConfigurationManager Configuration 属性

配置管理,是6.0版本新增的类,更见简单的用于获取和设置系统配置文件,替换掉了5.0版本中IConfigurationBuilder接口IConfigurationRoot接口(6.0是把这2个接口整合在一起了,看源码可以发现ConfigureManager继承于这2个接口)

ConfigurationManager密封类源码

public sealed class ConfigurationManager : IConfigurationBuilder, IConfigurationRoot, IConfiguration, IDisposable
{
public ConfigurationManager();
public string this[string key] { get; set; }
public void Dispose();
public IEnumerable<IConfigurationSection> GetChildren();
public IConfigurationSection GetSection(string key);
} public interface IConfigurationBuilder
{
IDictionary<string, object> Properties { get; }
IList<IConfigurationSource> Sources { get; }
IConfigurationBuilder Add(IConfigurationSource source);
IConfigurationRoot Build();
}

增加系统配置文件

当你调用builder.Configuration.AddJsonFile("文件名称")拓展方法的来增加自定义配置文件的时候(实际上是往调用的IConfigurationBuilder.Add()方法往IList<IConfigurationSource> Sources { get; }属性增加了一条数据),会将立即加载提供程序并更新配置,这样可以不用等到Build()方法,可以避免在部分生成方法多次加载配置源数据。

demo

var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("servicesetting.json");

获取系统配置数据

demo

var builder = WebApplication.CreateBuilder(args);
ConfigurationManager config = builder.Configuration;
string value1 = config["DBContextModel:SqlConnection"];
IConfigurationSection value2 = config.GetSection("DBContextModel");
ILoggingBuilder Logging

提供日志记录,包括控制台、调试、事件日志、TraceSource等组件,你是不是在疑惑为什么创建项目的时候appsetting.json配置文件有一个这样的配置?他就和日志记录息息相关

appstting.json文件节点

 "Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},

具体在日志章节描述

ConfigureWebHostBuilder WebHost 属性

继承于IWebHostBuilder接口,目的是复用接口,继承于ISupportsStartUp接口,由于6.0使用的是最小托管模型,所以传统的使用Startup.cs文件来配置服务和注册中间件已经不支持了,继承此接口的是原因是:

微软原话“但是我们希望用户在采用这种编程方式时得到显式的提醒,所以依然让它实现该接口,并在实现的方法中抛出NotImplementedException类型的异常。”

WebApplication构造函数中,通过传进来的一些构造参数初始化一个实例赋值给该属性;

构造函数,通过WebHostContext,Services成员属性、Configure成员属性来初始化

ConfigureWebHostBuilder类源码

public class ConfigureWebHostBuilder : IWebHostBuilder, ISupportsStartup
{
private readonly WebHostBuilderContext _builderContext;
private readonly IServiceCollection _services;
private readonly ConfigurationManager _configuration; public ConfigureWebHostBuilder(WebHostBuilderContext builderContext, ConfigurationManager configuration, IServiceCollection services)
{
_builderContext = builderContext;
_services = services;
_configuration = configuration;
}
}
ConfigureHostBuilder Host 属性

继承于IHostBuilder接口,目的是复用接口,他更多的用来配置主机服务

WebApplication构造函数中,通过bootStrapBuilder收集到的服务,传进来的一些构造参数初始化一个实例赋值给他;

构造函数,通过HostBuilderContext ,Services成员属性、Configure成员属性来初始化

  • Services成员属性会直接赋值ConfigureHostBuilder的_services属性

  • Configure成员属性相关Host的配置会被存放在ConfigureHostBuilder内部类的一个_configureActions字段暂时存起来

ConfigureHostBuilder类源码

public class ConfigureHostBuilder : IHostBuilder
{
private readonly ConfigurationManager _configuration;
private readonly IServiceCollection _services;
private readonly HostBuilderContext _context;
private readonly List<Action<IHostBuilder>> _configureActions = new(); internal ConfigureHostBuilder(HostBuilderContext context, ConfigurationManager configuration, IServiceCollection services)
{
_configuration = configuration;
_services = services;
_context = context;
}
}

BootstrapHostBuilder类:

BootstrapHostBuilder继承于IHostBuilder,目的是为了构建和初始化IHostBuilder对象

这个它的作用是收集初始化IHostBuilder对象提供的设置并将它们分别应用到指定的IServiceCollection、ConfigurationManager和IHostBuilder对象上,在构造函数中会调用他的Apply()方法。

2. Build()方法:

简单来说就是将对于WebApplicationBuilder的一切配置转移到IHostBuilder对象上,然后得到一个WebApplication对象

注意!!!!!

WebApplication一旦创建,环境变量、配置都不允许再次改变(虽然我们也用不着,但是知道就好)

这个方法作用:

WebApplicationConfigure成员属性Services成员属性转移到HostBuilder上面

WebApplication.Build()方法源码

 // 获取WebApplication对象,用于配置 HTTP 管道和路由的 Web 应用程序
public WebApplication Build()
{
// 在此处连接主机配置。我们不会尝试保留配置,在此处获取本身,因为我们不支持在创建构建器后更改主机值。
_hostBuilder.ConfigureHostConfiguration(builder =>
{
builder.AddInMemoryCollection(_hostConfigurationValues);
}); // 将ConfigurationManager的配置转移到_hostBuilder
_hostBuilder.ConfigureAppConfiguration(builder =>
{
builder.AddConfiguration(Configuration);
foreach (var kv in ((IConfigurationBuilder)Configuration).Properties)
{
builder.Properties[kv.Key] = kv.Value;
}
}); var chainedConfigSource = new TrackingChainedConfigurationSource(Configuration); _hostBuilder.ConfigureServices((context, services) =>
{
// 简单来说就是把WeApplicationBuilder中的IServiceCollection属性添加到泛型主机中
foreach (var s in _services)
{
services.Add(s);
} // 把服务列表只能关于主机的服务添加到主机中
// 确保添加的任何托管服务在初始托管服务集之后运行。也就是托管服务在web主机启动前运行
foreach (var s in _services.HostedServices)
{
services.Add(s);
} // 清除主机托管服务列表
_services.HostedServices.Clear(); // 将任何服务添加到用户可见的服务集合中,
_services.InnerCollection = services; // 保留主机中的配置
var beforeChainedConfig = true;
var hostBuilderProviders = ((IConfigurationRoot)context.Configuration).Providers; if (!hostBuilderProviders.Contains(chainedConfigSource.BuiltProvider))
{
((IConfigurationBuilder)Configuration).Sources.Clear();
beforeChainedConfig = false;
}
// 使配置管理器与最终_hostBuilder的配置匹配。
foreach (var provider in hostBuilderProviders)
{
if (ReferenceEquals(provider, chainedConfigSource.BuiltProvider))
{
beforeChainedConfig = false;
}
else
{
IConfigurationBuilder configBuilder = beforeChainedConfig ? _hostConfigurationManager : Configuration;
configBuilder.Add(new ConfigurationProviderSource(provider));
}
}
}); // 在最终主机构建器上运行其他回调
Host.RunDeferredCallbacks(_hostBuilder); // 构建应用
_builtApplication = new WebApplication(_hostBuilder.Build()); // 将服务集合标记为只读以防止将来修改
_services.IsReadOnly = true; // 解析_hostBuilder的配置和构建器。
_ = _builtApplication.Services.GetService<IEnumerable<IConfiguration>>();
return _builtApplication;
}

WebApplication类:

应用类

继承4个接口

  • IHost接口:所以这就是上文当中说到为什么WebApplicationBuilder需要一个IConfigureHostBuilder属性的原因;
  • IApplicationBuilder:提供配置应用程序请求管道机制的类,所以我们的中间件可以直接注册到WebApplication
  • IEndpointRouteBuilder:定义应用程序中路由生成器的协定。 路由生成器指定应用程序的路由。所以我们无需显示调用UseEndpoint、UseRouting这2个中间件,这个在6.0的更新中也提到了;
  • IAsyncDisposable:提供异步释放的接口;

6个重要属性

  • IServiceProvider:应用程序的已配置服务。提供在程序运行期间解析的服务类型,简称依赖注入容器;
  • IConfiguration:应用程序的已配置,可以获取已经配置好的配置源;
  • IWebHostEnvironment: 托管环境信息;
  • IHostApplicationLifetime:允许通知使用者应用程序生存期事件;
  • ILogger:日志服务;
  • ICollection<string> :HTTP 服务器绑定到的 URL 列表。(IServerAddressesFeature:启动地址);

WebApplication类源码

public sealed class WebApplication : IHost, IApplicationBuilder, IEndpointRouteBuilder, IAsyncDisposable
{
public IServiceProvider Services => _host.Services;
public IConfiguration Configuration => _host.Services.GetRequiredService<IConfiguration>();
public IWebHostEnvironment Environment => _host.Services.GetRequiredService<IWebHostEnvironment>();
public IHostApplicationLifetime Lifetime => _host.Services.GetRequiredService<IHostApplicationLifetime>();
public ILogger Logger { get; }
public ICollection<string> Urls => ServerFeatures.Get<IServerAddressesFeature>()?.Addresses ??
throw new InvalidOperationException($"{nameof(IServerAddressesFeature)} could not be found."); }

拓展方法

就是各种系统定义好的中间件服务。

3. Run()方法 :

WebApplication.BuildRequestDelegate()方法

前面调用ConfigureWebHostDefaults()扩展方法提供的委托会将使用BuildRequestDelegate()方法注册的中间件管道,作为请求处理器,至此一个WebApplication对象完成。

应用--WebApplication的更多相关文章

  1. [原] VS新添加WebApplication项目,无法运行,请求帮助,问题如何解决

    最近在WIN10 Pro上安装运行VS2012(安装顺利),新建WebApplication项目,无法运行,编译都无法通过,但都是警告. 症状: 1.新建项目无法编译: 2.新建后,默认引用全部感叹号 ...

  2. error MSB4019: 未找到导入的项目“C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\WebApplications\Microsoft.WebApplication.targets”

    error MSB4019: 未找到导入的项目“C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\WebApplications\ ...

  3. WebSite和WebApplication的区别

    1. WebApplication(Web应用程序)和WebSite(网站)的区别:WebSite是为了兼容从ASP转过来的开发人员的习惯而存在的,用起来简单,例如:不需要创建命名控件.C#代码修改以 ...

  4. Visual Stadio 2015创建WebApplication应用和运行赏析

    专题图: 1,创建一个WebApplication应用 2,项目结构和布局  3,运行项目 作者:ylbtech出处:http://ylbtech.cnblogs.com/本文版权归作者和博客园共有, ...

  5. web项目的两个创建形式website和webapplication(转)

    前言 在利用VS2010创建web项目的时候,会有两个选择.可以选择直接创建website网站,还可以选择使用 webapplication应用程序.刚刚接触web开发,看到这两个就疑惑了,既然是都可 ...

  6. web项目的两个创建形式website和webapplication

    前言 在利用VS2010创建web项目的时候,会有两个选择.可以选择直接创建website网站,还可以选择使用 webapplication应用程序.刚刚接触web开发,看到这两个就疑惑了,既然是都可 ...

  7. WebApplication和WebSite的区别

    不同点 1. 创建方式不同 一个是FILE->NEW->PROJECT->ASP.NET WEB APPLICATION 另外一个是 FILE->NEW->WEBSITE ...

  8. 【ASP.NET】website转webapplication

    *以下操作都以VS2013为参考: #新建两种web项目 1.添加webapplication项目: 2.添加website项目: #比较两种web项目新建的webform页面的不同点: 1.文件目录 ...

  9. WebApplication与WebSite区别

    1. WebApplication(Web应用程序)和WebSite(网站)的区别:WebSite是为了兼容从ASP转过来的开发人员的习惯而存在的,用起来简单,例如:不需要创建命名控件.C#代码修改以 ...

  10. 利用 PowerShell 分析SharePoint WebApplication 体系结构

    之前一篇文章<两张图看清SharePoint 2013 Farm 逻辑体系结构>谈到Web Application,Content Database,Site Collection的关系. ...

随机推荐

  1. BZOJ 2038: [2009国家集训队]小Z的袜子【莫队算法裸题】

    作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿. 终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命. 具体来说,小Z把这N只袜子从1到N编号,然后从 ...

  2. vivo 互联网业务就近路由技术实战

    一.问题背景 在vivo互联网业务高速发展的同时,支撑的服务实例规模也越来越大,然而单个机房能承载的机器容量是有限的,于是同城多机房甚至多地域部署就成为了业务在实际部署过程中不得不面临的场景. 一般情 ...

  3. win32com操作word API精讲 第八集 Range和Selection的区别

    本课程<win32com操作word API精讲&项目实战>以视频为主,文字为辅,公众号ID:一灯编程 众所周知,在word编程中Range和Selection都能实现范围的选中, ...

  4. Kafka 社区KIP-405中文译文(分层存储)

    原文链接:https://cwiki.apache.org/confluence/display/KAFKA/KIP-405%3A+Kafka+Tiered+Storage 译者:Kafka KIP- ...

  5. SV Interface and Program 2

    Clocking:激励的时序 memory检测start信号,当start上升沿的时候,如果write信号拉高之后,将data存储到mem中 start\write\addr\data - 四个信号是 ...

  6. 【MicroPython】生成Q(string)符号表文件 - py\makeqstrdefs.py

    脚本使用格式 python py/makeqstrdefs.py [command] [mode] [input-file] [output-directory] [output-file] comm ...

  7. Oracle 不同字符集复合索引长度验证

    Oracle 不同字符集复合索引长度验证 背景 前段时间同事找到一个参数, 可以解决Oracle的char和byte 模式存储超长的问题. 很大程度上解决了研发修改SQL的工作量. 但是发现在某些字符 ...

  8. [转帖]记一次探索内存cache优化之旅

    https://developer.aliyun.com/article/972803 背景 项目上线以来,曾出现上传镜像.下发镜像时可用内存不足,性能发生抖动的情况.研究发现是容器的 page ca ...

  9. Nginx 解决 413 问题的配置.

    Nginx 解决 413 问题的配置. Nginx 容易出现一个错误提示问题: worker_processes 1; events { worker_connections 1024; } http ...

  10. vuex标准化看这篇文章就够了~

    1.新建一个store文件夹,新建index.js文件,内容如下: import Vue from 'vue' import Vuex from 'vuex' import state from '. ...