.NET 6 入门实战
Part1 项目结构搭建
项目结构
CXY.XiguaData.Common 通用类帮助类 如 MD5Helper CacheHelper JwtHelper
CXY.XiguaData.Extensions 扩展类 AutoMapper Autofac 等扩展插件
依赖关系图
Part2 Swagger 组件添加
概述
Swagger (OpenAPI) 是一个与语言无关的规范,用于描述 REST API。 它使计算机和用户无需直接访问源代码即可了解 REST API 的功能。 其主要目标是:
- 尽量减少连接分离的服务所需的工作量。
- 减少准确记录服务所需的时间。
.NET 的两个主要 OpenAPI 实现是 Swashbuckle 和 NSwag
Swashbuckle 有三个主要组成部分:
- Swashbuckle.AspNetCore.Swagger:将 对象公开为 JSON 终结点的 Swagger 对象模型和中间件。
- Swashbuckle.AspNetCore.SwaggerGen:从路由、控制器和模型直接生成 对象的 Swagger 生成器。 它通常与 Swagger 终结点中间件结合,以自动公开 Swagger JSON。
- Swashbuckle.AspNetCore.SwaggerUI:Swagger UI 工具的嵌入式版本。 它解释 Swagger JSON 以构建描述 Web API 功能的可自定义的丰富体验。 它包括针对公共方法的内置测试工具。
引入 nuget 包
StartUp ConfigureService 修改
ConfigureService 配置
services.AddSwaggerGen(c=>
{
c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
{
Version = "v0.1.0",
Title = "GFSystem",
Description = "接口说明文档",
Contact = new Microsoft.OpenApi.Models.OpenApiContact
{
Name="CXY",
Email = "xxxx@qq.com"
}
});
});
Configure 添加中间件
app.UseSwagger();
app.UseSwaggerUI(c=>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
});
配置 XML 注释
- 在解决方案资源管理器中右键单击该项目,然后选择“Edit <project_name>.csproj”。
- 手动将突出显示的行添加到
.csproj
文件:
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
启用 XML 注释,为未记录的公共类型和成员提供调试信息。 警告消息指示未记录的类型和成员。 例如,以下消息指示违反警告代码 1591:
要在项目范围内取消警告,请定义要在项目文件中忽略的以分号分隔的警告代码列表。 将警告代码追加到 $(NoWarn);
也会应用 C# 默认值。
要仅针对特定成员取消警告,请将代码附入 #pragma warning 预处理程序指令中。 此方法对于不应通过 API 文档公开的代码非常有用。在以下示例中,将忽略整个 Program
类的警告代码 CS1591。 在类定义结束时还原警告代码的强制执行。 使用逗号分隔的列表指定多个警告代码。
namespace TodoApi
{
#pragma warning disable CS1591
public class Program
{
public static void Main(string[] args) =>
BuildWebHost(args).Run();
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
#pragma warning restore CS1591
}
将 Swagger 配置为使用按照上述说明生成的 XML 文件。 对于 Linux 或非 Windows 操作系统,文件名和路径区分大小写。 例如,TodoApi.XML
文件在 Windows 上有效,但在 CentOS 上无效。
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "ToDo API",
Description = "A simple example ASP.NET Core Web API",
TermsOfService = new Uri("https://example.com/terms"),
Contact = new OpenApiContact
{
Name = "Shayne Boyer",
Email = string.Empty,
Url = new Uri("https://twitter.com/spboyer"),
},
License = new OpenApiLicense
{
Name = "Use under LICX",
Url = new Uri("https://example.com/license"),
}
});
// Set the comments path for the Swagger JSON and UI.
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
在上述代码中,反射用于生成与 Web API 项目相匹配的 XML 文件名。 AppContext.BaseDirectory 属性用于构造 XML 文件的路径。 一些 Swagger 功能(例如,输入参数的架构,或各自属性中的 HTTP 方法和响应代码)无需使用 XML 文档文件即可起作用。 对于大多数功能(即方法摘要以及参数说明和响应代码说明),必须使用 XML 文件。
Part3 EntityFrameWork 组件添加
概述
Entity Framework (EF) Core 是轻量化、可扩展、开源和跨平台版的常用 Entity Framework 数据访问技术。
EF Core 可用作对象关系映射程序 (O/RM),这可以实现以下两点:
- 使 .NET 开发人员能够使用 .NET 对象处理数据库。
- 无需再像通常那样编写大部分数据访问代码。
模型
对于 EF Core,使用模型执行数据访问。 模型由实体类和表示数据库会话的上下文对象构成。 上下文对象允许查询并保存数据。 有关详细信息,请参阅创建模型。
EF 支持以下模型开发方法:
- 从现有数据库生成模型。
- 对模型手动编码,使其符合数据库。
- 创建模型后,使用 EF 迁移从模型创建数据库。 模型发生变化时,迁移可让数据库不断演进。
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace Intro;
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public int Rating { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
查询
使用语言集成查询 (LINQ) 从数据库检索实体类的实例
using (var db = new BloggingContext())
{
var blogs = db.Blogs
.Where(b => b.Rating > 3)
.OrderBy(b => b.Url)
.ToList();
}
保存数据
使用实体类的实例在数据库中创建、删除和修改数据。
using (var db = new BloggingContext())
{
var blog = new Blog { Url = "http://sample.com" };
db.Blogs.Add(blog);
db.SaveChanges();
}
需要引用的包
Microsoft.EntityFrameworkCore.SqlServer :EF Core 通过使用“数据库提供程序”支持不同的数据库系统。 每个系统都有自己的数据库提供程序,而提供程序以 NuGet 包的形式提供。 应用程序应安装其中一个或多个提供程序包。
使用用于 EF Core 迁移和现有数据库中的反向工程(基架)的工具需要安装相应的工具包:
- 可在 Visual Studio 包管理器控制台中使用的 PowerShell 工具的 Microsoft.EntityFrameworkCore.Tools
- 跨平台命令行工具的 dotnet-ef 和 Microsoft.EntityFrameworkCore.Design
Database First
工作原理
反向工程从读取数据库架构开始。 它会读取有关表、列、约束和索引的信息。
接下来,它将使用架构信息创建 EF Core 模型。 使用表创建实体类型;使用列创建属性;使用外键创建关系。
最后,使用模型生成代码。 为相应实体类型类、Fluent API 和数据注释搭建基架,以便从应用重新创建相同的模型。
命令解释
反向工程是基于数据库架构搭建实体类型类和 DbContext 类基架的过程。 可使用 EF Core 包管理器控制台 (PMC) 工具的 Scaffold-DbContext
命令或 .NET 命令行接口 (CLI) 工具的 dotnet ef dbcontext scaffold
命令执行这一过程。
Scaffold-DbContext 'Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook' Microsoft.EntityFrameworkCore.SqlServer
- 第一个参数是指向数据库的连接字符串
- 第二个参数是提供程序名称。 提供程序名称通常与提供程序的 NuGet 包名称相同。
- 默认情况下,将数据库架构中的所有表反向工程为实体类型。 可通过指定架构和表来限制对哪些表进行反向工程。
Scaffold-DbContext ... -Tables Artist, Album
- 默认情况下,使用 Fluent API 配置实体类型。 指定
-DataAnnotations
(PMC) 或--data-annotations
(.NET Core CLI) 以改为使用数据注释(如果可能)。
例如,使用 Fluent API 将搭建以下项的基架
entity.Property(e => e.Title)
.IsRequired()
.HasMaxLength(160);
而使用数据注释则将搭建以下项的基架:
[Required]
[StringLength(160)]
public string Title { get; set; }
- 默认情况下,已搭建基架的 DbContext 类名称将是后缀为 Context 的数据库名称。 若要指定不同名称,请在 PMC 中使用
-Context
,在 .NET Core CLI 中使用--context
。 - 可使用
-OutputDir
指定在其中为类搭建基架的目录,并且可使用-ContextDir
将 DbContext 类搭建到与实体类型类不同的目录中:
Scaffold-DbContext ... -ContextDir Data -OutputDir Models
默认情况下,命名空间将是根命名空间加上项目根目录下任何子目录的名称。 但是,从 EFCore 5.0 开始,可使用 -Namespace
覆盖所有输出类的命名空间。 还可使用 -ContextNamespace
仅覆盖 DbContext 类的命名空间。
Scaffold-DbContext ... -Namespace Your.Namespace -ContextNamespace Your.DbContext.Namespace
- 对数据库进行更改后,可能需要更新 EF Core 模型以反映这些更改。 如果数据库更改很简单,只需手动对 EF Core 模型进行更改即可。 例如,重命名表或列、删除列或更新列的类型都是在代码中进行的微小更改。但是,更重要的更改并不容易手动完成。 一种常见的工作流是使用
-Force
(PMC) 或--force
(CLI) 再次从数据库对模型进行反向工程,以使用更新的模型覆盖现有模型。
Code First
概念
在实际项目中,数据模型随着功能的实现而变化:添加和删除新的实体或属性,并且需要相应地更改数据库架构,使其与应用程序保持同步。 EF Core 中的迁移功能能够以递增方式更新数据库架构,使其与应用程序的数据模型保持同步,同时保留数据库中的现有数据。
简要地说,迁移的方式如下:
- 当引入数据模型更改时,开发人员使用 EF Core 工具添加相应的迁移,以描述使数据库架构保持同步所需的更新。EF Core 将当前模型与旧模型的快照进行比较,以确定差异,并生成迁移源文件;文件可在项目的源代码管理中进行跟踪,如任何其他源文件。
- 生成新的迁移后,可通过多种方式将其应用于数据库。 EF Core 在一个特殊的历史记录表中记录所有应用的迁移,使其知道哪些迁移已应用,哪些迁移尚未应用。
命令
创建模型
首先先创建 Model 以及 DbContext
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace EFGetStarted;
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public string DbPath { get; }
public BloggingContext()
{
var folder = Environment.SpecialFolder.LocalApplicationData;
var path = Environment.GetFolderPath(folder);
DbPath = System.IO.Path.Join(path, "blogging.db");
}
// The following configures EF to create a Sqlite database file in the
// special "local" folder for your platform.
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite($"Data Source={DbPath}");
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
指示 EF Core 创建名为 InitialCreate 的迁移:EF Core 将在项目中创建一个名为“Migrations”的目录,并生成一些文件
Add-Migration InitialCreate
创建数据库和架构
此时,可以让 EF 创建数据库并从迁移中创建架构。 可以通过以下操作实现这一点:
Update-Database
CURD
通过迁移或者反向工程会得到 DbContext,接下来对数据库的所有操作都会通过 DbConext 将 LINQ 解析成 SQL 语句,从数据库中取出数据。DbContext
的生存期从创建实例时开始,并在释放实例时结束。 DbContext
实例旨在用于单个工作单元。 这意味着 DbContext
实例的生存期通常很短。
使用 Entity Framework Core (EF Core) 时的典型工作单元包括:
-
创建
DbContext
实例 -
根据上下文跟踪实体实例。 实体将在以下情况下被跟踪
-
根据需要对所跟踪的实体进行更改以实现业务规则
-
调用 SaveChanges 或 SaveChangesAsync。 EF Core 检测所做的更改,并将这些更改写入数据库。
-
释放
DbContext
实例
注册 DbContext
在许多 Web 应用程序中,每个 HTTP 请求都对应于单个工作单元。 这使得上下文生存期与请求的生存期相关,成为 Web 应用程序的一个良好默认值。
使用依赖关系注入配置 ASP.NET Core 应用程序。 可以使用 Startup.cs
的 ConfigureServices
方法中的 AddDbContext 将 EF Core 添加到此配置。 例如:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddDbContext<ApplicationDbContext>(
options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection"));
}
此示例将名为 ApplicationDbContext
的 DbContext
子类注册为 ASP.NET Core 应用程序服务提供程序(也称为依赖关系注入容器)中的作用域服务。 上下文配置为使用 SQL Server 数据库提供程序,并将从 ASP.NET Core 配置读取连接字符串。 在 ConfigureServices
中的何处调用 AddDbContext
通常不重要。
ApplicationDbContext
类必须公开具有 DbContextOptions<ApplicationDbContext>
参数的公共构造函数。 这是将 AddDbContext
的上下文配置传递到 DbContext
的方式。 例如:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
然后,ApplicationDbContext
可以通过构造函数注入在 ASP.NET Core 控制器或其他服务中使用。 例如:
public class MyController
{
private readonly ApplicationDbContext _context;
public MyController(ApplicationDbContext context)
{
_context = context;
}
}
最终结果是为每个请求创建一个 ApplicationDbContext
实例,并传递给控制器,以在请求结束后释放前执行工作单元。
简单的增删查改操作
保存数据
每个上下文实例都有一个 ChangeTracker
,它负责跟踪需要写入数据库的更改。 更改实体类的实例时,这些更改会记录在 ChangeTracker
中,然后在调用 SaveChanges
时被写入数据库。 此数据库提供程序负责将更改转换为特定于数据库的操作(例如,关系数据库的 INSERT
、UPDATE
和 DELETE
命令)。
Add
using (var context = new BloggingContext())
{
var blog = new Blog { Url = "http://example.com" };
context.Blogs.Add(blog);
context.SaveChanges();
}
Update
using (var context = new BloggingContext())
{
var blog = context.Blogs.First();
blog.Url = "http://example.com/blog";
context.SaveChanges();
}
Delete
using (var context = new BloggingContext())
{
var blog = context.Blogs.First();
context.Blogs.Remove(blog);
context.SaveChanges();
}
加载数据
Read
using (var context = new BloggingContext())
{
var blogs = context.Blogs
.Where(b => b.Url.Contains("dotnet"))
.ToList();
}
Part4 AutoFac 自动依赖注入
概述
ASP.NET Core 6.0 关于 Autofac 使用 - 芦荟柚子茶 - 博客园 (cnblogs.com)
注册服务
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer
{
builder.RegisterModule<AutofacModuleRegister>();
});
使用 Autofac 管理依赖注入
其中,AutofacModuleRegister 为自定义的 Autofac 配置类,实现如下:
public class AutofacModuleRegister: Module
{
protected override void Load(ContainerBuilder builder)
{
//把服务的注入规则写在这里
builder.RegisterType<TestService>().As<ITestService>();
builder.RegisterGeneric(typeof(BaseRepository<>)).As(typeof(IBaseRepository<>)).InstancePerDependency();
builder.RegisterGeneric(typeof(BaseServices<>)).As(typeof(IBaseService<>)).InstancePerDependency();
var assemblyServices = Assembly.Load("CXY.XiguaData.Services");
builder.RegisterAssemblyTypes(assemblyServices).AsImplementedInterfaces().EnableInterfaceInterceptors().InterceptedBy(cacheType.ToArray());
var assemblyRepository = Assembly.Load("CXY.XiguaData.Repositories");
builder.RegisterAssemblyTypes(assemblyRepository).AsImplementedInterfaces();
}
}
Part5 AutoMapper 自动映射对象
dotnet - Add AutoMapper to .Net 6 (issuecloser.com)
dotnet add package AutoMapper --version 10.1.1
dotnet add package AutoMapper.Extensions.Microsoft.DependencyInjection --version 8.1.1