尝试使用
ASP.Net Core
开发web应用程序一段时间了,感觉ASP.Net core
不论是开发体验还是各方面都很优秀,整理笔记,便于后面使用时翻看。
Init
初始化
创建
官方文档 dotnet 指令
新建项目
代码语言:javascript复制dotnet new web
官方文档 dotnet new
使用Visual Studio 2017 直接新建 .NET Core 项目
项目结构
此处以一个Web API 项目为例, 针对不太大的项目,采用了一个划分为三层的结构。
XXXX.Core
项目核心 (Class Library)XXXX.Infrastructure
基础设施 (Class Library)XXXX.Api
API主体 (dotnet
生成)
其中,Infrastructure 依赖于Core ,API主体依赖于Core 和 Infrastructure。
几个文件
XXX.csproj
每个 dotnet core
项目都会有一个唯一的xxx.csproj
,区别于一整个解决方案一个唯一的xxx.sln
,解决方案内的每一个项目,包括类库等,都有自己唯一的xxx.csproj
,这是标识了当前项目的内容,依赖,和配置信息等构建这个项目一切内容的一个 xml
文档。
- 定义项目的类型:Web,Console,Library
- 定义项目的目标平台:.NET Core, .NET Framework, Mono
- 列举项目依赖(
Nuget
,其他类库等)
Program.cs
主程序入口。有一个 Main 方法。
事实上,Web 项目的本质就是一个 Console 项目,在Main 中声明和创建了一个 IWebHost
来作为 ASP.NET Core
应用的核心,其中包含了配置信息,和Kestrel
服务。
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().RUn();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
Startup.cs
ASP.NET Core
有两个配置文件,上面我们也看到了,在Program.cs
中进行了一些列的配置,同样,也注意到,后面使用了.UseStartup<Startup>()
来调用Startup.cs
中的配置文件。
Program 主要进行基础设施的配置,通常不会随便变化:
- HTTP Server
- 集成 IIS
- 配置信息来源
Startup 主要配置自定义行为,需要经常进行修改
- 组建,服务,功能
- 中间件管道
Startup.ConfigureServices 的主要功能是
注册服务
,即注册服务到IoC容器。 关于 dotNet core 中的依赖注入和 IoC 可以参考 - ASP.NET Core中的依赖注入(1):控制反转(IoC)
运行时
ASP.NET Core 应用启动时读取ASPNETCORE_ENVIRONMENT
这个环境变量的值, 并保存在IHostingEnvironment.EnvironmentName
里。
环境变量 ASPNETCORE_ENVIRONMENT 可以是任何值. ASP.NET Core里默认带了三个值:
- Production
- Development
- Staging
如果ASPNETCORE_ENVIRONMENT没有被设置, 那么会默认取值为Production.
开发时和生产时的配置肯定会有不同,通常设置不同的环境配置,来切换调试,设置方法:
- PropertieslaunchSettings.json (仅限开发时)
environmentVariables
- 在Visual Studio 2017 里编辑项目属性
Debug -> Profile 和 Environment Variables
- 在系统里设置环境变量
- 开发时的环境可以使用
PropertieslaunchSettings.json
来进行设置, 这里的值会覆盖系统级环境变量的值
ASP.NET Core应用可以为不同的环境定义单独的Startup类/方法, 并在运行时选择适当的Startup类/方法
使用基于环境的类:Startup{环境名称}
- StartupDevelopment
- StartupProduction
- StartupStaging
在Program里配置IWebHostBuilder时使用UseStartup(IWebHostBuilder, String)而不是- UseStartup(IWebHostBuilder).String参数是StartupXxx所在的Assembly的名字.
常用服务和技巧
列举几个 dotNet core 常用的服务和开发技巧,并介绍安装使用过程:
开启支持HTTPS
微软建议所有的 ASP.NET Core应用都调用HTTPS重定向中间件, 来把所有的HTTP请求重定向为HTTPS.
HTTPS
Startup里:
- ConfigureServices方法注册, 并配置端口和状态码等: services.AddHttpsRedirection(…)
- Configure方法使用该中间件: app.UseHttpsRedirection()
HSTS(HTTP Strict Transport Security Protocol)
微软建议在生产环境下启用HSTS. Startup里:
- ConfigureServices方法注册和配置HSTS: services.AddHsts(…)
- Configure方法使用该中间件: app.UseHsts()
Entity Framework Core
Entity Framework (EF) Core 是轻量化、可扩展和跨平台版的常用 Entity Framework 数据访问技术。
EF Core 可用作对象关系映射程序 (O/RM),以便于 .NET 开发人员能够使用 .NET 对象来处理数据库,这样就不必经常编写大部分数据访问代码了。
EF Core 支持的数据集及其Nuget包参阅 https://docs.microsoft.com/zh-cn/ef/core/providers/index
添加Entity Framework Core
安装:
- 安装相关的包
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.Sqlite
(此处使用SqlLite 作为本地Dev 环境数据库) - 建立Context
- 建立Entities
- 建立Context, 继承于DbContext
- 在Startup里注册Context.
services.AddDbContext<XxxContext>(…)
参考上面的目录结构,Entities放在BlogDemo.Core项目.Context放在BlogDemo. Infrastructure项目. 在BlogDemo. Api项目进行注册配置.
数据库迁移:
- 在 Tools > NuGet Package Manager > Package Manager Console 输入命令.
- Add-Migration Xxx 添加迁移.
- Update-Database 更新到数据库
使用dotnet cli 迁移:参考 https://docs.microsoft.com/zh-tw/ef/core/miscellaneous/cli/dotnet
建立和注册Context
Entity 约束
实现 Entity 约束有两种方法:
- 使用IEntityTypeConfiguration.
- DbContext里的OnModelCreating().
使用Unit of Work Repository模式
Repository模式
为什么要使用Repository模式?
- 与持久化技术无关.
- 易于测试.
- 代码重用.
- 依赖注入, 松耦合, DIP原则.
DIP, 也就是SOLID里面的D, 高级别的模块不应该依赖于低级别的模块, 它们都应该依赖于抽象
ASP.NET Core 服务注册生命周期
- Transient: 每次其它的类请求(不是指HTTP Request)都会创建一个新的实例,它比较适合轻量级的无状态的(Stateless)的service.
- Scope: 每次HTTP请求会创建一个实例。
- Singleton: 在第一次请求的时候就会创建一个实例,以后也只有这一个实例; 或者在ConfigureServices这段代码运行的时候创建唯一一个实例。
按照最初提出者的介绍,它是衔接数据映射层和域之间的一个纽带,作用相当于一个在内存中的域对象集合。客户端对象把查询的一些实体进行组合,并把它们提交给Repository。对象能够从Repository中移除或者添加,就好比这些对象在一个Collection对象上就行数据操作,同时映射层的代码会对应的从数据库中取出相应的数据。从概念上讲,Repository是把一个数据存储区的数据给封装成对象的集合并提供了对这些集合的操作。在领域驱动设计中,我们有个集合(aggregate)的概念, 通常我们是对于domain的每个集合会对应的定义一个repository。也就说,并不是每个实体都会有对应的一个repository。
Unit of Work模式
简说了,主要作用是在数据持久化过程中,数据提交,确保数据的完整性,对象使用确保同一上下文对象。如果有异常,提供回滚。
为什么要使用Unit of Work模式?
- DbContext已经实现了Unit of Work 和 Repository 模式.
- Controller等不应该直接使用DbContext.
Uow 和 Repository模式 的关系即:
工作单元服务于仓储,并在工作单元中初始化上下文,为仓储单元提供上下文对象,由此确保同一上下文对象。