ASP.NET Core 菜鸟之路:从Startup.cs说起

1.前言

本文主要是以Visual Studio 2017 默认的 WebApi 模板作为基架,基于Asp .Net Core 1.0,本文面向的是初学者,如果你有 ASP.NET Core 相关实践经验,欢迎在评论区补充。
与早期版本的 ASP.NET 对比,最显著的变化之一就是配置应用程序的方式, Global.asax、FilterConfig.cs 和 RouteConfig.cs 统统消失了,取而代之的是 Program.cs 和 Startup.cs。Program.cs 作为 Web 应用程序的默认入口,不做任何修改的情况下,会调用同目录下 Startup.cs 中的 ConfigureServices 方法 和 Configure 方法。

应用启动的流程


对于初学者来说,第一次面对 Startup.cs 往往无从下手,本文将一步步介绍作者的经验,但是不会涉入到内部的代码实现以及相关的原理,那并不是本文想要讨论的范畴。

默认的Startup.cs


相信我,这将是你迈出构建灵活而强大的ASP.NET Core 应用程序的第一步。

2.配置参数选项

在官方文档中提供多种方式来配置参数选项:

  • 文件格式(INI,JSON和XML)

  • 命令行参数

  • 环境变量

  • 内存中的 .NET 对象

  • 用户机密存储

  • Azure 键值

  • 自定义提供程序

虽然提供了很多选择,但是我们只选择其中的JSON文件和环境变量来提供配置参数。

2.1 Json配置参数选项

参考官方文档的示例,我们在 appsettings.json 加入如下的参数:

appsettings.json


与此同时,我们还需要一个类来映射这些配置参数:

MyOptions.cs

思考一下 subsection 应该是字典还是一个对象?如果是字典,是否可以为<string,dynamic>或者<string,object>?

好了,现在就差怎么让他们联系起来,只需在 ConfigureServices 方法中将他们配对:

  services.Configure<MyOptions>(Configuration);

最后就是解决怎么使用这些配置参数的问题了,举个最简单的例子,我们可以在某个控制器中把我们的所有参数打印出来:

不知道你有没有发现 MyOptions 类中有些属性首字母大写,有些属性没有,并不是与json文件中完全一致,也就是说可以忽略大小写的。

回到之前的匹配环节,我们可以发现 services.Configure 的方法中似乎还有更多选择,比如我们把之前的那一行代码替换为:

services.Configure<MyOptions>(Configuration.GetSection("wizards"));//选择wizards节点

我们可以发现返回的对象里面的属性都为null,这是因为json中的 "wizards"的节点并不能与我们的类匹配。

那么问题来了,如果匹配的代码如下,又会产生什么样的结果呢?先别急着回答,我会在下一节中给出答案。

2.2环境变量

环境变量,或者说系统变量,在windows中我们可以在系统属性中配置:

在Linux环境中也有相应的配置,但是在开发过程中,我们可以在 Visual Studio 中配置:

在这之前,我们的Json文件中已经有 "option1" 和 "option2"的参数选项,那么会产生什么样的结果呢?

显然我们可以看到环境变量的参数覆盖了Json文件的参数。而引起这种变化的原因还是需要回到Startup的初始化:

    public Startup(IHostingEnvironment env){            var builder = new ConfigurationBuilder().SetBasePath(env.ContentRootPath).AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
//必须的json文件,并且自动重载.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
//不必须的json文件.AddEnvironmentVariables();//启用环境变量Configuration = builder.Build();}

从中我们可以看出环境变量的配置在读取 Json 文件参数之后,这样就会覆盖已经存在的同名参数,而已经从 Json 文件被匹配的参数并不会被清空(同样适用于前一节提出的问题)。从另一方面来说,如果你不需要环境变量,则需要去掉 "AddEnvironmentVariables() ",以免覆盖预期参数。
回到本节的中心,我们为什么会需要环境变量呢?我个人会在Dockerfile中配置一些环境变量,比如某种服务的访问地址、某中功能的开关等等。下面举例说说两个常用的环境变量:
ASPNETCORE_URLS 如果你没有指定对应的 Url 监听地址,可以通过该参数修改,如设置为 "http://*:80"。
ASPNETCORE_ENVIRONMENT 开发环境(Development)、预演环境(Staging)、生产环境(Production),将在工作环境一节中做详细介绍。不同的工作环境将使得整个软件流程变得清晰。

2.3配置参数小贴士

  • 参数有多种来源,如不需要勿增来源。

  • 要注意"最近原则",避免参数同名引起冲突。

  • 参数的key可以忽略大小写,所以环境变量中的 "OPTION2" 可以引起覆盖 Json文件中的 "option2" 的效果。

  • 为复杂参数选择合适的类型很重要,比如字典还是对象的取舍。

3.依赖注入

依赖注入在 ASP.NET Core 中无处不存在,在之前打印参数的例子中同样用到。依赖注入好处都有啥?为什么我们需要依赖注入?在 ASP .NET Core 中文文档中依赖注入的章节 很好地解释了:

你应该设计你的依赖注入服务来获取它们的合作者。这意味着在你的服务中避免使用有状态的静态方法调用(代码被称为 static cling)和直接实例化依赖的类型。当选择实例化一个类型还是通过依赖注入请求它时,它可以帮助记住这句话, New is Glue。通过遵循 面向对象设计的 SOLID 原则,你的类将倾向于小、易于分解及易于测试。

3.1注册服务以及简单使用

为了方便下一节测试,我准备三个文件,简单的接口、该接口的实现类,拥有接口成员的类:

IRepository

MemoryRepository

ProductTotalizer


接下来,我们使用 ASP.NET Core 自带的 DI 来注册服务:

 

可以看到,注册对象有很多种方法,并且我们可以管理对象的生命周期。注册完对象,我们就可以在我们需要的地方注入对应的对象了,还是最简单的例子——在控制器中使用:

 

 

对于控制器,我们有三种方式注入对象:构造函数、控制器动作、属性注入。然而,在一般的类中,使用自带的 DI 只能是构造函数注入。到底是哪种方式好,见仁见智。

3.2生命周期

ASP.NET Core 服务可以被配置为以下生命周期:

  • 瞬时(Transient) 在它们每次请求时都会被创建。这一生命周期适合轻量级的,无状态的服务。

  • 作用域 (Scoped) 在每次请求中只创建一次。

  • 单例(Singleton) 在它们第一次被请求时创建(或者如果你在 ConfigureServices运行时指定一个实例)并且每个后续请求将使用相同的实例。

我们将通过逐步更改 IRepository 的生命周期来看看会发生什么事情。
首先是瞬时:

接着是作用域:

最后是单例:


瞬时很好理解,类似每次都会new了一个对象。而对于作用域,如果一次请求中,有两个甚至多个非单例对象引用到同一个作用域类型时,他们将会收获同一个实例。单例也很好理解,从头到尾都是同一个实例。

 

控制单一变量,如果只是改变 ProductTotalizer 的生命周期而不是改变 IRepository 的生命周期的话,会发生什么情况呢?

3.3依赖注入小贴士

  • 遵循 SOLID 原则,考虑一下哪些是需要依赖注入的。

  • 合理考虑生命周期,假如某个类型在不同上下文中需要不同生命周期时,是否需要显式命名区分?还是考虑结构是否合理?

  • 避免静态访问服务。

  • 避免静态访问 HttpContext 。

4.启用扩展

在项目中我们往往会添加许多扩展,比如用于API文档说明的Swagger、计划任务的Hangfire、压缩响应的GZIP、跨域访问、日志扩展等等。他们的共同点就是需要先安装相应的nuget包,然后在 ConfigureServices() 方法中配置服务,最后在 Configure() 方法中启用。
我们以Swagger为例,首先是安装对应的 nuget 包—— Swashbuckle。
接着是配置扩展:

最后就是启用 Swagger 了:

 

我们访问 Swagger 的地址看看效果:

 

5.中间件

中间件是用于组成应用程序管道来处理请求和响应的组件。管道内的每一个组件都可以选择是否将请求交给下一个组件、并在管道中调用下一个组件之前和之后执行某些操作。请求委托被用来建立请求管道,请求委托处理每一个 HTTP 请求。


中间件处理请求

举一个简单的例子(更复杂的可以在中间件依赖注入对象),从 cookie 中获取 token 并附加到请求头中:

与启用扩展一样,我们同样是需要在 Configure()方法中启用中间件:

 

 app.UseMiddleware<JWTInHeaderMiddleware>();

如果我们有多个中间件呢,中间件的顺序可能会影响到响应结果,但并不是总是线性相关的。例如,我们新增一个对响应状态码处理的中间件:

我们把它加到其他中间件的最前面:

app.UseMiddleware<StatusCodeMiddleware>();//....app.UseMiddleware<JWTInHeaderMiddleware>();

虽然对状态码处理的中间件是最前面,但可以在请求的最后关头对请求结果进行处理。当然,如果中间有某个中间件短路了(没有传递到下一个中间件),就会让我们前功尽弃。

测试多个中间件处理请求

6.过滤器

与中间相似,过滤器同样可以对请求的前后执行特定代码,但是过滤器可以配置为全局有效、仅对控制器有效或是仅对 Action 有效,比中间件更具有灵活性。

过滤器处理请求


另外,过滤器从类型上还能分为:授权过滤器、资源过滤器、Action过滤器、结果过滤器。很容易实现面向切面编程,降低了耦合。
这里举一个我最喜欢的过滤器——对请求的模型进行验证:

 

在控制器或 Action 使用,只需加上特性即可:

当然,模型验证的过滤器往往具有全局性,所以我一般是加在 services.AddMvc 中:

 

services.AddMvc(config=> 
{config.Filters.Add(new ValidateModel());});

 

7.工作环境

ASP.NET Core 提供了许多功能和约定来允许开发者更容易的控制在不同的环境中他们的应用程序的行为。当发布一个应用程序从开发到预演再到生产,为环境设置适当的环境变量允许对应用程序的调试,测试或生产使用进行适当的优化。

在软件开发的生命周期中,在不同的工作环境中往往是不同的状态。比如说,在测试或者预演环境中,启用Swagger扩展、控制台打印日志、允许跨域,而在生产环境中,往往处于安全、性能或者其他考虑,这些功能是需要禁止的。对于 MVC 开发者来说,在开发过程中会使用本地的JS、Css、图片等文件,而在生产环境中这些文件往往是从CDN中获取。

8.结语

ASP.NET Core 提供了强大而灵活的配置机制,每个点展开都像是一片新的天地。即使是经验丰富的开发者,也不能自称完全掌握全部机制。随着 .NET Core 的完善和发展,Startup.cs 也将越来越复杂。越是复杂,就越是要小心,如无需要,勿增实体!

9.相关引用

  • Configuration in ASP.NET Core

  • ASP.NET Core 中文文档

原文地址:http://www.cnblogs.com/chenug/p/6869109.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/325525.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

el表达式与jstl的用法

课上顺便整理了下java中的El表达式和jstl的用法&#xff0c;下面以举例的方式来阐述各个标签的作用&#xff1a;一、 使用el表达式将Map集合中的数据显示出来&#xff1a;先给Map集合里面放一些数据库&#xff0c;通过EL表达式显示在页面中&#xff1a;<%Map names new Has…

业务太复杂?教你如何降低软件的复杂性

转载自 业务太复杂&#xff1f;教你如何降低软件的复杂性 John Ousterhout 是斯坦福大学计算机系教授&#xff0c;也是 Tcl 语言的创造者。 今年四月&#xff0c;他出版了一本新书《软件设计的哲学》&#xff08;A Philosophy of Software Design&#xff09;。这是课程讲稿…

[翻译]在 .NET Core 中的并发编程

原文地址:http://www.dotnetcurry.com/dotnet/1360/concurrent-programming-dotnet-core 今天我们购买的每台电脑都有一个多核心的 CPU&#xff0c;允许它并行执行多个指令。操作系统通过将进程调度到不同的内核来发挥这个结构的优点。然而&#xff0c;还可以通过异步 I/O 操作…

JS中函数和变量声明的提升

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>01_变量提升与函数提升</title> </head> <body> <!-- 1. 变量声明提升* 通过var定义(声明)的变量, 在定义语句之前就可以访问到*…

记录学生的日常

最近比较忙&#xff0c;都没时间更新公众号了&#xff0c;粉丝每天都在减&#xff0c;哈哈哈。最近19级的学生们在做网页设计静态网页项目&#xff0c;从上周五到现在&#xff0c;班内除了两个小组比较慢之外&#xff0c;其余的进度都还可以&#xff0c;从做项目中就可以看出来…

Mono新突破:CentOS 7.2下安装Mono 5.0

微软Build2017大会期间.NET领域的.NET core之外&#xff0c;就是Visual Studio For Mac&#xff0c;大家都知道Visual Studio For Mac 是基于Mono运行的&#xff0c;Mono 5.0也是闪亮登场&#xff0c;Mono 5.0是一个非常重要的里程碑版本&#xff0c;支持Windows 64位部署&…

搞定 JVM 垃圾回收就是这么简单

转载自 搞定 JVM 垃圾回收就是这么简单 JVM的垃圾回收机制是Java中比较重要的知识点&#xff0c;也是面试官常考的问题&#xff0c;本文主要围绕以下面试题来讲解JVM的垃圾回收机制。 问题答案在文中都有提到 如何判断对象是否死亡&#xff08;两种方法&#xff09;。 简单…

一份感动到哭的成绩单……

今天对班级内进行了测试&#xff0c;这是自实行周周考以来&#xff0c;第三次测试了&#xff0c;还记得第一次的测试&#xff0c;几分的&#xff0c;十几分的&#xff0c;几十分的五花八门&#xff0c;成绩可算是惨不忍睹啊。第二次测试&#xff0c;开发的进步了好多&#xff0…

深刻理解:C#中的委托、事件

C#中的事件还真是有点绕啊&#xff0c;以前用JavaScript的我&#xff0c;理解起来还真是废了好大劲&#xff01;刚开始还真有点想不明白为什么这么绕&#xff0c;想想和JS的区别&#xff0c;最后终于恍然大悟&#xff01; C#中事件绕的根本原因&#xff1a; C#的方法&#xff…

mybatis中,collection配置后查询只显示一条记录

描述一下问题&#xff1a; 已知有两个表&#xff0c;一个是user表&#xff0c;一个是address,一&#xff08;user&#xff09;对多(address)的关系&#xff0c;在user的实体类里面写属性&#xff1a; private List<Address> addressList new ArrayList<Address>(…

Java中的List你真的会用吗

转载自 Java中的List你真的会用吗 List是Java中比较常用的集合类&#xff0c;关于List接口有很多实现类&#xff0c;本文就来简单介绍下其中几个重点的实现ArrayList、LinkedList和Vector之间的关系和区别。 List List 是一个接口&#xff0c;它继承于Collection的接口。它…

Android 全局字体设置 例如楷体

1、在res下新建资源文件目录font&#xff0c;把字体文件拷贝到font文件夹中 2、在AndroidManifest.xml中的application节点下&#xff0c;设置全局style&#xff0c;引入字体文件 <item name"android:fontFamily">font/pingfang_sc_regular</item>或者

.Net Core中使用ref和Spanamp;lt;Tamp;gt;提高程序性能

一、前言 其实说到ref&#xff0c;很多同学对它已经有所了解&#xff0c;ref是C# 7.0的一个语言特性&#xff0c;它为开发人员提供了返回本地变量引用和值引用的机制。Span 也是建立在ref语法基础上的一个复杂的数据类型&#xff0c;在文章的后半部分&#xff0c;我会有一个例…

微服务为什么选Spring Cloud

转载自 微服务为什么选Spring Cloud 现如今微服务架构十分流行&#xff0c;而采用微服务构建系统也会带来更清晰的业务划分和可扩展性。同时&#xff0c;支持微服务的技术栈也是多种多样的&#xff0c;本系列文章主要介绍这些技术中的翘楚——Spring Cloud。这是序篇&#x…

压力与动力是否成正比?

昨天在班里测试了下&#xff0c;检测他们数据库学的怎么样&#xff0c;看他们平时在课堂上的互动挺棒。看了下题&#xff0c;不是很难&#xff0c;满怀着愉悦的心情去打印了50份&#xff0c;挨个分发下去&#xff0c;由于我18级那边有课要上&#xff0c;所以这边的考试就辛苦王…

[开源] 基于ABP,Hangfire的开源Sharepoint文件同步解决方案----SuperRocket.SPSync

&#xff08;一&#xff09;项目背景 Sharepoint是微软的一个产品&#xff0c;很多公司都在使用它&#xff0c;也有很多公司以前使用它&#xff0c;现在可能需要移植到别的平台&#xff0c;也可能只是移植其中的文件存储&#xff0c;比如说移植到微软云&#xff0c;或者亚马逊云…

永远不要、不要、不要、不要放弃

Never, never, never, never give up. 永远不要、不要、不要、不要放弃。今天来写一下18级学生们的状态吧&#xff0c;最近主要是解决了1班的三大问题&#xff0c;第一&#xff0c;上机测试问题。第二&#xff0c;周一到四期间学习任务安排问题。第三&#xff0c;学习氛围的进一…

JS的时间定时器

<script>var t null;t setTimeout(time, 1000); //開始运行function time() {clearTimeout(t); //清除定时器dt new Date();var y dt.getFullYear();var mt dt.getMonth() 1;var day dt.getDate();var h dt.getHours(); //获取时var m dt.getMinutes(); //获取分…

微软正式发布XAML Standard与.NET Standard 2.0:现已提供下载

微软在本月早些时候召开的 Build 2017 开发者大会上的披露的 XAML Standard 和 .NET Standard 2.0&#xff0c;现已正式发布。新工具旨在为开发者们带来“基于同一标准的跨平台 XAML 语言结构”&#xff08;基于 UWP 和 Xamarin.Forms&#xff09;&#xff0c;以及基于社区反馈…

Spring Boot 2.X 来临,本文将带你起飞

转载自 Spring Boot 2.X 来临&#xff0c;本文将带你起飞 当前互联网技术盛行&#xff0c;以Spring 框架为主导的Java 互联网技术成了主流&#xff0c;而基于Spring 技术衍生出来的Spring Boot&#xff0c;采用了“约定优于配置”的思想&#xff0c;极大地简化了Spring 框架…