ASP.NET Core 2 preview 1中Program.cs,Startup.cs和CreateDefaultBuilder的探索
Exploring Program.cs, Startup.cs and CreateDefaultBuilder in ASP.NET Core 2 preview 1
ASP.NET Core 2.0 的目标之一是已经被简洁化的基础模板。简化了其基本使用,并且让开始一个新项目变得更加简单。
明显从表面上来看,新的 Program 和 Startup 类型相比于 ASP.NET Core 1.0 更加简单。现在,我将从新的 WebHost.CreateDefaultBuilder() 方法出发,看看它是如何引导你的应用程序的。
Program和Startup在ASP.NET Core 1.X中的职责
在ASP.NET Core 1.X中, Program类用来建立IWebHost。一个基础的web app模板就像这样:
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
这个相对紧凑的文件做了下面这些事情:
- 配置一个Web服务器(Kestrel)
- 设置内容目录(这个目录包括appsettings.json文件等)
- 建立IIS集
- 定义Startup类
- Build()和Run IWebHost
Startup的实现可能存在很大的差别,这取决于你建立的应用程序。 MVC模板展现的是一个典型的启动模板
public class Startup
{
public Startup(IHostingEnviroment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsetting.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
// add framework services
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{Controller=Home}/{action=Index}/{id?}"
);
});
}
}
这个文件主要有以下四个职责:
- 在Startup构造函数中建立配置
- 在ConfigureService中建立依赖注入关系
- 在Configure中启动Logging
- 在Configure中建立中间件管道
这些都运行的不错,但是ASP.NET团队认为还是有很多地方考虑的不够全面。
首先,设置配置比较冗长,但也很标准,总的来说不太需要过多的调整。
其次,Logging是在Startup的Configure中配置的,它建立在Configuration和DI配置完成之后。这里有两个缺点。一方面,这使Logging看上去像个二等公民-Configure通常被用来配置中间件管道,这样使得Logging配置在这里意义不大。同样也意味着你无法记录应用程序本身引导过程的日志。有很多方法能解决这个问题,但都不是特别有效。
在ASP.NET Core 2.0 preview 1中,这两点已经通过修改IWebHost角色,通过创建一个辅助方法配置应用程序。
Program和Startup在ASP.NET Core 2.0 preview 1中的责任
在ASP.NET Core 2.0 previe 1中,IWebHost的职责发生了一些改变。在之前拥有的职责上,增加了额外两点:
- Setup Configuration
- Setup Logging
此外,ASP.NET Core 2.0引入了一个辅助方法CreateDefaultBuilder。它封装了Program.cs中大部分常见的代码,以及configuration和logging!
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
正如你所看到的,这里没有提及Kestrel,IIS,configuration等-这些全部放在CreateDefaultBuilder方法中处理。
将configuration和logging代码转移到这个方法中处理简化了Startup文件:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}"
);
});
}
}
这个类除了logging和许多configuration代码被移除外,和1.0的非常相似。注意IConfiguration对象注入到类型的一个属性,而不是创建配置构造函数本身。
这是ASP.NET 2.0新引入的-IConfiguration对象默认通过DI注册。在1.X中,如果你需要从DI中获取IConfiguration对象,你必须自己注册。
最初,我认为CreateDefaultBuilder只是进行了模糊的设置,感觉好像有点退步,但是回想起来,这里更多的只是一个“谁动了我的奶酪”的感觉。CreateDefaultBuilder没有什么奇特的地方,他只是隐藏了一些通常保持不变的标准代码。
WebHost.CreateDefaultBuilder辅助方法
为了能确切地弄懂静态辅助方法CreateDefaultBuilder方法,我决定看一看GitHub上的源代码! 你会惊喜地发现,如果你使用过ASP.NET Core 1.X, 这些看起来都很相似。
public static IWebHostBuilder CreateDefaultBulder(string[] args)
{
var builder = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) => {/* setup config */})
.ConfigureLogging((hostingContext, config) => {/* setup logging */})
.UseIISIntegration()
.UseDefaultServiceProvider((context, options) => {/* setup the DI container to use */})
.ConfigureServices(services =>
{
services.AddTransient<IConfigureOptions<KestrelServerOptions>, KestrelServerOptionsSetup>();
});
return builder;
}
这里一些新的方法被我省略了,我将在以后的帖子对这些方法进行解析。你能看出来这些方法和ASP.NET Core 1.0中很大程度上做着相同的工作-建立Kestrel服务器,定义ContentRoot,建立IIS集。另外,它也做了一些其他的事情
- ConfigureAppConfiguration-这里包含过去编写在Startup的配置代码
- ConfigureLogging-建立过去在Startup.Configure中的logging配置
- UseDefaultServiceProvider-后面我会就此深入讨论, 但是这里设置内置的DI容器,并且允许你定制自定义行为
- ConfigureServices-向IWebHost中添加额外所需的组件服务。特别地,可以配置Kestrel服务的选项,允许你可以轻松定义你的Web主机就像普通配置的一部分一样。
这篇帖子中,我将仔细看看configuration和logging,其他方法的深入将在以后的帖子中展现。
在ConfigureAppConfiguration中设置app configuration
ConfigureAppConfiguration方法中是一个包含两个参数的lambda表达式-WebHostBuilderContext对象hostingContext,和IConfigurationBuilder实例config:
ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsetting.json, optional:true, reloadOnChange: true")
.AddJsonFile($"appsetting.{env.Environment}.json", optional: true, reloadOnChange: true);
if(env.IsDevelopment())
{
var appAssembly = Assembly.Load(new Assembly(env.ApplicationName));
if(appAssembly != null)
{
config.AddUserSecrets(appAssembly, optional: true);
}
}
config.AddEnvironmentVariables();
if(args != null)
{
config.AddCommandLine(args);
}
});
可以看到,参数hostingContext暴露了IHostingEnvironment(不管是运行在开发环境还是生产环境)作为一个属性,HostingEnvironment。如果你使用过ASP.NET Core 2.0, 除了形式上意外,大部分代码都非常相似。
一个特例是在建立User Secret时候,做法有一点点不同。它通过一个程序集引用加载User Secret,但你仍然可以使用通用config.AddUserSecrets<T>进行配置。
在ASP.NET Core 2.0中, UserSecretsId被存储在一个Assembly Attribute中,因此需要先引入Assembly中。你仍然可以使用csproj文件定义id-它将会在编译时被嵌入到assembly level attribute中。
这些都是标准的东西。它通过下面的提供者,通过下面的顺序加载配置:
- appsettings.json(optional)
- appsettings.{env.EnvironmentName}.json(optional)
- User Secrets
- Environment Variables
- Command line arguments
这个方法与ASP.NET Core 1.X的主要不同在于所处的位置-config现在作为WebHost的一部分,而不是通过构造函数植入。同时,最初的建立和最终的调用通过Web Host本身的IConfigurationBuilder,而不是你处理。
在ConfigureLogging中配置logging
ConfigureLogging方法同样是两个参数的lambda表达式-一个WebHostBuilderContext对象hostingContext,一个和configuration方法一样的LoggerFactory实例logging:
ConfigureLogging((hostingContext, logging) =>
{
logging.UseConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
});
logging基础设施在ASP.NET Core 2.0中有一些改变。但是一般来说,这些代码与你在ASP.NET Core1.0应用程序的Configure方法中发现的建立Console和Debug日志方式遥相呼应。你可以用UseConfiguration方法设置日志级别,通过访问已定义好的暴露在hostingContext.Configuration的IConfiguration接口。
自定义WebHostBuilder
我希望通过对WebHost.CreateDefaultBuilder的深入探讨能够表达ASP.NET团队之所以使用它的原因。有许多方法可以建立并运行一个app,但是这种方式使得它更加简单。
但是,假如这不是你想要的启动方式?你可以不适用它!没有什么特殊的辅助,你可以复制粘贴实现代码到你自己的app中,定制它,同样也可以很好的工作。
这不是很确切-KestrelServerOptionsSetup类在ConfigureServices内部引用,因此你将它删除。我将在后面的帖子中进行深入分析。
总结
这篇帖子看起来像是介绍从ASP.NET Core 1.X向ASP.NET Core 2.0 preview 1转移中Program.cs和Startup.cs的不同。特别地,我稍微深入了解了一下WebHost.CreateDefaultBuilder方法,它的作用实际上只是使建立app更加简单。如果你不喜欢他给你做的选择,或者需要自己定制。你仍然可以做到这点,就像以前一样。选择在于你自己!
ASP.NET Core 2 preview 1中Program.cs,Startup.cs和CreateDefaultBuilder的探索的更多相关文章
- asp.net core 3.1 入口:Program.cs中的Main函数
本文分析Program.cs 中Main()函数中代码的运行顺序分析asp.net core程序的启动,重点不是剖析源码,而是理清程序开始时执行的顺序.到底用了哪些实例,哪些法方. asp.net c ...
- 从ASP.Net Core Web Api模板中移除MVC Razor依赖项
前言 :本篇文章,我将会介绍如何在不包括MVC / Razor功能和包的情况下,添加最少的依赖项到ASP.NET Core Web API项目中. 一.MVC VS WebApi (1)在ASP. ...
- 跨平台应用集成(在ASP.NET Core MVC 应用程序中集成 Microsoft Graph)
作者:陈希章 发表于 2017年6月25日 谈一谈.NET 的跨平台 终于要写到这一篇了.跨平台的支持可以说是 Office 365 平台在设计伊始就考虑的目标.我在前面的文章已经提到过了,Micro ...
- Asp.Net Core 入门(一)——Program.cs做了什么
ASP.NET Core 是微软推出的一种全新的跨平台开源 .NET 框架,用于在 Windows.Mac 或 Linux 上生成基于云的新式 Web 应用程序.国内目前关于Asp.Net Core的 ...
- ASP.NET Core 3.0 WebApi中使用Swagger生成API文档简介
参考地址,官网:https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/getting-started-with-swashbuckle?view ...
- Asp.Net Core 第02局:Program
总目录 前言 本文介绍Program,它包含程序的入口Main方法.从这里开始... 环境 1.Visual Studio 2017 2.Asp.Net Core 2.2 开局 第一手:Program ...
- 在 ASP.NET Core和Worker Service中使用Quartz.Net
现在有了一个官方包Quartz.Extensions.Hosting实现使用Quartz.Net运行后台任务,所以把Quartz.Net添加到ASP.NET Core或Worker Service要简 ...
- ASP.NET Core 在 JSON 文件中配置依赖注入
前言 在上一篇文章中写了如何在MVC中配置全局路由前缀,今天给大家介绍一下如何在在 json 文件中配置依赖注入. 在以前的 ASP.NET 4+ (MVC,Web Api,Owin,SingalR等 ...
- VS 2017开发ASP.NET Core Web应用过程中发现的一个重大Bug
今天试着用VS 2017去开发一个.net core项目,想着看看.net core的开发和MVC5开发有什么区别,然后从中发现了一个VS2017的Bug. 首先,我们新建项目,ASP.NET Cor ...
随机推荐
- Vim 自定义补全利器 Snippet
Vim Snippet 设置 本人是 vim 用户,可以说能不用 IDE 就不用 IDE. Snippet 是一种支持用户自定义补全的需求,在 vim 中,可以使用 UltiSnips 和 Vim-S ...
- 网络安全-主动信息收集篇第二章-二层网络扫描之scapy
scapy是python第三方库文件,可以使用python进行调用也单独进行使用. 非常强大可以用于抓包.分析.创建.修改.注入网络流量. 使用scapy 详细使用方式可以查看github:https ...
- Codeforces 1109D: generalizations of Cayley's formula证明
做这题的时候发现题解里有提到\(generalizations\ of\ Cayley's\ formula\)的,当场懵逼,Wikipedia里也就带到了一下,没有解释怎么来的,然后下面贴了篇论文. ...
- CSPS模拟 80
题还没改完就来臭不要脸的写反思了. (主要因为太困了懒得改了) (还因为T2看起来太过弱智) (也许等我生物钟恢复正常后能当做课余消遣水一水) statistic:skyh接了两杯水,真能喝啊 然后他 ...
- Kubernetes 挂载文件到pod里面
下面以chart为例子: 1.创建ConfigMap,这里要注意config.js为挂载的文件名 [root@cn-hongkong templates]# cat app-config.yaml a ...
- python——float()函数用法
float()函数是python中一个比较常用的内建函数,我们要详细掌握它的使用方法,避免在编写代码的过程中错误使用. float()函数返回一个十进制浮点型数值(小数). float()括号内只能是 ...
- mvn上传dubbo jar到nexus
第一种方式: mvn deploy:deploy-file -DgroupId=com.alibaba -DartifactId=dubbo -Dversion=2.8.4 -Dpackaging=j ...
- JVM 中你不得不知的一些参数
有的同学虽然写了一段时间 Java 了,但是对于 JVM 却不太关注.有的同学说,参数都是团队规定好的,部署的时候也不用我动手,关注它有什么用,而且,JVM 这东西,听上去就感觉很神秘很高深的样子,还 ...
- HTML和css面试题:内容转载
1.常见的块级元素 内联元素 div -最常用的块级元素 dl - 和dt-dd 搭配使用的块级元素 form - 交互表单 h1 -h6- 大标题 hr - 水平分隔线 ol – 有序列表 p - ...
- Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring - 大新博客 - 推酷 - 360安全浏览器 7.1
Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring - 大新博客 时间 2014-02-11 21:08:00 博客园-所有随笔区 ...