笔记源于课堂编写:BiliBili
源视频教程:https://www.bilibili.com/video/BV1tK4y1j7Eu

C#7~9版本新语法-官网:
C#7:https://docs.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-7
C#8:https://docs.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-8
C#9:https://docs.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-9

一、C# 6新语法

1.1-自动属性初始化表达式

002.3-NET5零基础到精通实战全集 - 图1
002.3-NET5零基础到精通实战全集 - 图2

1.2-using static

002.3-NET5零基础到精通实战全集 - 图3
002.3-NET5零基础到精通实战全集 - 图4

1.3-Null 条件运算符

002.3-NET5零基础到精通实战全集 - 图5

1.4-字符串内插

002.3-NET5零基础到精通实战全集 - 图6

1.5-异常刷选器

002.3-NET5零基础到精通实战全集 - 图7

1.6-nameof表达式

002.3-NET5零基础到精通实战全集 - 图8

1.7-事件(发布订阅模式)

002.3-NET5零基础到精通实战全集 - 图9
002.3-NET5零基础到精通实战全集 - 图10
002.3-NET5零基础到精通实战全集 - 图11

1.8-使用索引器初始化关联集合

002.3-NET5零基础到精通实战全集 - 图12

二、C# 7新语法

2.1-Out变量

002.3-NET5零基础到精通实战全集 - 图13
002.3-NET5零基础到精通实战全集 - 图14

2.2-元祖

002.3-NET5零基础到精通实战全集 - 图15
002.3-NET5零基础到精通实战全集 - 图16
//2
002.3-NET5零基础到精通实战全集 - 图17
002.3-NET5零基础到精通实战全集 - 图18

2.3-弃元

002.3-NET5零基础到精通实战全集 - 图19
002.3-NET5零基础到精通实战全集 - 图20

2.4-模式

002.3-NET5零基础到精通实战全集 - 图21
002.3-NET5零基础到精通实战全集 - 图22

2.5-本地方法

002.3-NET5零基础到精通实战全集 - 图23

2.6-默认文本表达式

002.3-NET5零基础到精通实战全集 - 图24

2.7-数字语法改进

002.3-NET5零基础到精通实战全集 - 图25
002.3-NET5零基础到精通实战全集 - 图26

2.8-命名实参

002.3-NET5零基础到精通实战全集 - 图27
002.3-NET5零基础到精通实战全集 - 图28
002.3-NET5零基础到精通实战全集 - 图29

2.9-private protected访问修饰符-新复合访问修饰符

002.3-NET5零基础到精通实战全集 - 图30

2.10-增强的泛型约束

002.3-NET5零基础到精通实战全集 - 图31
002.3-NET5零基础到精通实战全集 - 图32

2.11-通用的异步返回类型

002.3-NET5零基础到精通实战全集 - 图33

三、C# 8新语法

3.1-默认接口方法

002.3-NET5零基础到精通实战全集 - 图34
002.3-NET5零基础到精通实战全集 - 图35

3.2-switch表达式

//传统方式switch
002.3-NET5零基础到精通实战全集 - 图36
//新玩法
002.3-NET5零基础到精通实战全集 - 图37

3.3-属性模式

002.3-NET5零基础到精通实战全集 - 图38
002.3-NET5零基础到精通实战全集 - 图39

3.4-元祖模式

002.3-NET5零基础到精通实战全集 - 图40
002.3-NET5零基础到精通实战全集 - 图41

3.5-位置模式

002.3-NET5零基础到精通实战全集 - 图42
002.3-NET5零基础到精通实战全集 - 图43

3.6-静态本地函数

002.3-NET5零基础到精通实战全集 - 图44

3.7-异步流

002.3-NET5零基础到精通实战全集 - 图45
002.3-NET5零基础到精通实战全集 - 图46
002.3-NET5零基础到精通实战全集 - 图47

四、C# 9新语法

4.1-记录

//针对属性:
002.3-NET5零基础到精通实战全集 - 图48
002.3-NET5零基础到精通实战全集 - 图49
//新的
002.3-NET5零基础到精通实战全集 - 图50
002.3-NET5零基础到精通实战全集 - 图51

//针对方法:
002.3-NET5零基础到精通实战全集 - 图52002.3-NET5零基础到精通实战全集 - 图53

4.2-顶级语句

002.3-NET5零基础到精通实战全集 - 图54

4.3-对象声明(简化)

002.3-NET5零基础到精通实战全集 - 图55
//方法调用
002.3-NET5零基础到精通实战全集 - 图56

4.4-静态修饰

002.3-NET5零基础到精通实战全集 - 图57

4.5-模式匹配

002.3-NET5零基础到精通实战全集 - 图58
002.3-NET5零基础到精通实战全集 - 图59

4.6-为空判断

002.3-NET5零基础到精通实战全集 - 图60

4.7-协变返回值

4.8-nint

002.3-NET5零基础到精通实战全集 - 图61

4.9-Lambda 参数弃元

002.3-NET5零基础到精通实战全集 - 图62

4.10-关系匹配

002.3-NET5零基础到精通实战全集 - 图63

五、创建项目+Seesion传值

5.1-使用Session

002.3-NET5零基础到精通实战全集 - 图64

5.2-Log4Net组件使用

(1)管理Nuget程序,下载【log4net】和【Microsoft.Extensions.Logging.Log4Net.AspNetCore】
002.3-NET5零基础到精通实战全集 - 图65
002.3-NET5零基础到精通实战全集 - 图66
(2)新建一个文件夹,保存log4net配置文件,一定要在【属性】中的 复制到输出目录 选择【始终复制】。
002.3-NET5零基础到精通实战全集 - 图67
(3)在【Program.cs】文件的【CreateHostBuilder】方法中配置log4net。
002.3-NET5零基础到精通实战全集 - 图68
//也可以使用以下方式配置(在Startup中):
//这里注意,别选择错了!然后就可以了。
002.3-NET5零基础到精通实战全集 - 图69

六、程序的发布运行

6.1-项目的发布

(1)右击项目,选择【发布】
002.3-NET5零基础到精通实战全集 - 图70
002.3-NET5零基础到精通实战全集 - 图71
(2)选择【文件夹】
002.3-NET5零基础到精通实战全集 - 图72
(3)选择要保存的路径,然后点击【完成】;
002.3-NET5零基础到精通实战全集 - 图73
(4)点击【发布】,可以看到已经发布完成了。
002.3-NET5零基础到精通实战全集 - 图74
002.3-NET5零基础到精通实战全集 - 图75

6.2-项目的运行

6.2.1-IIS发布

  • IIS直接简历网站,目录指向项目跟目录下的Debug、Net5文件;——不行
  • 把项目发布后,目录指向项目发布目录;——可以的

6.2.2-ASP.NET Core跨平台原因
002.3-NET5零基础到精通实战全集 - 图76

6.2.3-使用脚本启动网站
002.3-NET5零基础到精通实战全集 - 图77
002.3-NET5零基础到精通实战全集 - 图78

6.2.4-发布之后运行为什么样式加载不出404?
(1)需要在【startup.cs】文件的【Configure】方法中引入一个中间件。
002.3-NET5零基础到精通实战全集 - 图79

七、命令参数读取+配置多种读取

7.1-配置文件读取(1)

//在【startup.cs】文件中读取配置文件
002.3-NET5零基础到精通实战全集 - 图80
//在【控制器】中读取配置文件。
(1)先构造函数注入Configure
002.3-NET5零基础到精通实战全集 - 图81
(2)写代码获取
002.3-NET5零基础到精通实战全集 - 图82
002.3-NET5零基础到精通实战全集 - 图83

7.2-配置文件读取(2)

(1)定义一个类,结构(数据类型、属性名)和配置文件中完全一致。
002.3-NET5零基础到精通实战全集 - 图84
(2)在【Startup.sc】配置一下
002.3-NET5零基础到精通实战全集 - 图85
(3)在控制器中,构造函数注入一个IOptions
002.3-NET5零基础到精通实战全集 - 图86
(4)获得并返回值
002.3-NET5零基础到精通实战全集 - 图87
(5)前端获取值
002.3-NET5零基础到精通实战全集 - 图88
002.3-NET5零基础到精通实战全集 - 图89

八、MVC开发

8.1-什么是MVC?

  • V——View——视图:呈现给用户看到的内容(表现层)
  • C——Controller——控制器:控制业务逻辑计算,调用服务,选择返回什么内容,可以返回视图,JSON、字符串等等。
  • M——Model——视图模型:用作控制器和视图之间传递数据的载体。

8.2-cshtml文件

其实是一个类文件。
Razor混编:可以在cshtml上写 后台C#代码 + 前台html代码,混合起来写;
(1)可以引入命名空间
002.3-NET5零基础到精通实战全集 - 图90
(2)直接写后台代码
002.3-NET5零基础到精通实战全集 - 图91
(3)实现接口
002.3-NET5零基础到精通实战全集 - 图92
(4)可以依赖注入
002.3-NET5零基础到精通实战全集 - 图93
(5)可以添加特性Class
002.3-NET5零基础到精通实战全集 - 图94
(6)定义方法并调用
002.3-NET5零基础到精通实战全集 - 图95
(7)写单行代码、多行代码
002.3-NET5零基础到精通实战全集 - 图96
002.3-NET5零基础到精通实战全集 - 图97
(8)Razor表达式
002.3-NET5零基础到精通实战全集 - 图98
(9)输出尖括号
002.3-NET5零基础到精通实战全集 - 图99
(10)for循环
002.3-NET5零基础到精通实战全集 - 图100
(11)在后台代码内部写HTML代码
002.3-NET5零基础到精通实战全集 - 图101

8.3-如何解决修改视图后无需编译后即可生效?

//修改视图,增加了html代码,不能马上生效,怎么办?使用中间件
002.3-NET5零基础到精通实战全集 - 图102
//1.引入Nuget包
002.3-NET5零基础到精通实战全集 - 图103
//2.在【Startup.cs】文件的票【ConfigureServices】方法中配置。
002.3-NET5零基础到精通实战全集 - 图104

8.4-Razor布局

8.4.1-我们看到的页面组成到底有哪些内容?
答:包含了Layout的模板嵌套的返回的需要渲染的视图内容;

8.4.2-如何嵌套呢?
答:通过Layout中RendBody()方法做了替换;把返回的视图替换到模板也中,形成了一整块的内容;目的在于每一次返回不同的页面的时候,能够吧不变的视图部分,种以重用;这样就可以少些代码。
002.3-NET5零基础到精通实战全集 - 图105

8.4.3-在模板页面导入了JQ,在视图页面使用JQ为什么报错?
注意:

  • 在模板页中使用CSS/JS的时候,为了提高效率,会把Css引入在模板的上方,将JS写在模板的下方。页面嵌套到模板页后,就会出现在引用JS的上方调用JS,此时JS其实是调用不了的。

002.3-NET5零基础到精通实战全集 - 图106
答:因为Script是写在下面的,先加载RenderBody,后加载JQ,所以会报错,解决方法如下:
002.3-NET5零基础到精通实战全集 - 图107

九、Razor扩展-HTML控件

9.1-Html扩展控件(1)

//本质:通过一个后台方法,返回一个【已经存在】的Html标签的字符串,浏览器在读取的时候,就读取成一个Html标签。
//1.定义

  1. /// <summary>
  2. /// 图片
  3. /// </summary>
  4. /// <param name="helper"></param>
  5. /// <param name="src"></param>
  6. /// <returns></returns>
  7. public static IHtmlContent Img(this IHtmlHelper helper,string src,string @class)
  8. {
  9. return new HtmlString($"<img src='{src}' class='{@class}'/>");
  10. }

//2.调用

  1. <!--1.引入命名空间-->
  2. <!--2.使用图片--自定义 扩展方法-->
  3. @Html.Img("https://tpc.googlesyndication.com/simgad/3105023548593992165/downsize_200k_v1?w=200&h=200","border:1px solid red;")

9.2-Html扩展控件(2)

//通过一个后台方法,返回一个【不存在】的Html标签的字符串,在读取的时候,通过制后台方法,去生成我们制定的标签。
//1.写一个扩展方法,定义一个普通类,类名建议以TagHelper结尾,加上特性;如果没有标记特性,视图中在调用的时候使用当前类名去掉TagHelper后缀得到的的字符串来调用。继承TagHelpre抽象类、或者实现接口ITagHelpr,二者选一起均可。然后实现接口Proccss方法。
002.3-NET5零基础到精通实战全集 - 图108
//2.在【_ViewImports.cshtml】进行注册
002.3-NET5零基础到精通实战全集 - 图109
//3.使用
002.3-NET5零基础到精通实战全集 - 图110

9.3-Razor局部视图

//1.创建一个局部视图
002.3-NET5零基础到精通实战全集 - 图111
//2.进行调用
002.3-NET5零基础到精通实战全集 - 图112

9.3.1-局部视图的缺陷:
局部视图没有去访问控制器中的Action,所以不能完美的实现后台代码。可以使用视图组件解决。

9.4-视图组件-扩展定制

9.4.1-视图组件的优点?

  • 呈现页面相应的某一部分而不是整个相应
  • 包括在控制器和视图之间发现的关注分离和可测试性优势
  • 可以具有参数和业务逻辑
  • 通常在页面布局中调用

9.4.2-如何自定义视图组件?
(1)Rzaor组件对应的类需要以ViewComponent结尾,该类需要继承自ViewCompnent类。
002.3-NET5零基础到精通实战全集 - 图113
(2)定义一个异步版本的InvokeAsync,可以自定义参数,IncokeAsync就是返回组件内容的方法。
002.3-NET5零基础到精通实战全集 - 图114
(3)在Views/Shared文件下建立Components文件夹,在这个文件下创建一个和组件类名相同(如果加了特性,就按照特性上面的名称来)的文件夹,然后创建一个Default.cshtml视图。
002.3-NET5零基础到精通实战全集 - 图115
//注意:以上步骤可以不按照上面执行,我们可以随意新建一个视图,然后指定路径就可以了。
002.3-NET5零基础到精通实战全集 - 图116
(4)调用
002.3-NET5零基础到精通实战全集 - 图117

十、内置容器基本使用

10.1-什么是IOC?

把对象的创建,统一交给第三方容器来创建;

10.2-如何使用IOC?

(1)在【Startup.cs】的【ConfigureServices】中注册服务;注册抽象和具体的依赖关系;
002.3-NET5零基础到精通实战全集 - 图118
(2)通过构造函数进行依赖注入,自动得到服务的实例;
002.3-NET5零基础到精通实战全集 - 图119
(3)调用;
002.3-NET5零基础到精通实战全集 - 图120

10.3-如何使用IOC?(第二种方法)

(1)在【Startup.cs】的【ConfigureServices】中注册服务;注册抽象和具体的依赖关系;
002.3-NET5零基础到精通实战全集 - 图121
(2)通过构造函数进行依赖注入。
002.3-NET5零基础到精通实战全集 - 图122
(3)调用;
002.3-NET5零基础到精通实战全集 - 图123

10.4-在视图中使用IOC

002.3-NET5零基础到精通实战全集 - 图124

10.4-什么是依赖注入?

DI依赖注入:IServiceCollection支持且支持构造函数注入。
如对象A依赖对象B,对象B依赖于对象C,就可以先构造对象C,然后传递给对象B,然后传递给对象A,然后得到具体的实例。可以支持无限层级的依赖注入,前提是先要先注入服务(注册抽象和具体的映射关系)。

10.5-IServiceCollection生命周期

那么在创建对象的时候, 不同的情况,需要让对象单例,每一次都创建新的对象实例,不同的作用于创建新的实例。
//AddTransient:顺时声明周期,每次获取的都是不同的实例
002.3-NET5零基础到精通实战全集 - 图125
//AddSingleton:单例生命周期,在整个进程中获取的都是同一个实例
002.3-NET5零基础到精通实战全集 - 图126
//AddScoped:作用域生命周期(同一个作用域,获取的是同一个对象的实例,不同的作用域,获取的是不同的独对象实例)
002.3-NET5零基础到精通实战全集 - 图127
//建议:开发工作中,一般情况下,都是一个请求一个对象的实例,所以使用的是顺时声明周期(AddTransient)。

十一、Autofac容器

11.1-Autofac容器初识?

Autofac也是一款流行的IOC容器;

11.2-如何使用Autofac容器?

(1)管理Nuget程序包,下载并安装【Autofac】
002.3-NET5零基础到精通实战全集 - 图128
(2)在【Startup.cs】的【ConfigureServices】中注册服务;
002.3-NET5零基础到精通实战全集 - 图129

11.3-Autofac注入方式-构造函数注入

002.3-NET5零基础到精通实战全集 - 图130
002.3-NET5零基础到精通实战全集 - 图131

11.4-Autofac注入方式-属性注入

002.3-NET5零基础到精通实战全集 - 图132
002.3-NET5零基础到精通实战全集 - 图133

11.5-Autofac注入方式-方法注入

002.3-NET5零基础到精通实战全集 - 图134
002.3-NET5零基础到精通实战全集 - 图135

11.6-Autofac生命周期-瞬时生命周期(默认)

瞬时生命周期:每一次获取对象都是一个全新的实例,默认的生命周期。
002.3-NET5零基础到精通实战全集 - 图136

11.7-Autofac生命周期-单例生命周期

单例声明周期:在整个进程中,对象永远都是同一个实例(SingleInstance)
002.3-NET5零基础到精通实战全集 - 图137

11.8-Autofac生命周期-每个生命周期范围一个实例

每个生命周期范围一个实例:同一个生命周期范围内是同一个实例,不同的生命周期范围,实例不一样。(InstancePerLifetimeScope)
002.3-NET5零基础到精通实战全集 - 图138

11.9-Autofac生命周期-每个匹配生命周期范围一个实例

语法:InstancePerMatchingLifetimeScope(名称)
002.3-NET5零基础到精通实战全集 - 图139

11.10-Autofac生命周期-每个请求一个实例

002.3-NET5零基础到精通实战全集 - 图140

11.11-Autofac支持配置文件

(1)管理Nuget包,引入3个程序集;
002.3-NET5零基础到精通实战全集 - 图141
(2)新建一个配置文件【autofac.json】,记得将配置文件设置为:始终复制到目录。
002.3-NET5零基础到精通实战全集 - 图142
002.3-NET5零基础到精通实战全集 - 图143
(3)在【Startup.cs】的【ConfigureServices】中注册服务;
002.3-NET5零基础到精通实战全集 - 图144

11.12-Autofac整合MVC

注意:Autofac是一个第三方容器;
(1)指定Autofac工厂替换默认工厂,在【Program.cs】中的【CreateHostBuilder】方法中指定。
002.3-NET5零基础到精通实战全集 - 图145
(2)在【Startup.cs】类中增加一个【ConfigureContainer】方法,用来注册服务关系。
///

/// 增加一个方法: /// 整个方法被Autofac自动调用 /// 负责注册各种服务 /// /// public void ConfigureContainer(ContainerBuilder containerBuilder) { containerBuilder.RegisterType().As(); containerBuilder.RegisterType().As(); containerBuilder.RegisterType().As(); containerBuilder.RegisterType().As().PropertiesAutowired(); containerBuilder.RegisterType().As(); }
(3)通过控制器构造函数注入,获取实例。
002.3-NET5零基础到精通实战全集 - 图146
//这种方法也还能用:
002.3-NET5零基础到精通实战全集 - 图147

11.13-Autofac支持控制器属性注入

(1)首先在【Startup.cs】中【ConfigureServices】方法中,指定控制器实例容器来创建,进行替换。
002.3-NET5零基础到精通实战全集 - 图148
(2)创建一个类(特性);
002.3-NET5零基础到精通实战全集 - 图149
(3)创建一个类,用来判断维度;
002.3-NET5零基础到精通实战全集 - 图150
(4)在【Startup.cs】中创建一个【ConfigureContainer】方法,负责注册各种服务。
002.3-NET5零基础到精通实战全集 - 图151

11.14-Autofac一个实例多实现的问题

注意:

  • 如果一个抽象多个实例,都注册了,通过构造函数用抽象类型来获取实例,哪个是后面注册的,就能获得哪个,覆盖类型的。
  • 如果一个抽象多个实例,都注册了,可以通过一个IEnumerable<抽象类>,当做构造函数参数,可以获取到左右注册的具体的实例。

002.3-NET5零基础到精通实战全集 - 图152
//一般使用以下方法:
(1)在【Startup.cs】中创建的【ConfigureContainer】方法中,注册资源和实现(单抽象、多实现)
002.3-NET5零基础到精通实战全集 - 图153
(2)通过构造函数中,使用具体理性实理性做我参数,可以匹配到不同的具体类型实例。
002.3-NET5零基础到精通实战全集 - 图154

002.3-NET5零基础到精通实战全集 - 图155
(1)新建一个类,该类继承Module类,实现Load方法。
002.3-NET5零基础到精通实战全集 - 图156
(2)与之前相同,不同的而方式:在【Startup.cs】中创建的【ConfigureContainer】方法中,注册资源和实现(单抽象、多实现)
002.3-NET5零基础到精通实战全集 - 图157

11.15-Autofac通过抽象(接口)支持AOP(面向切面编程-做应用型系统)

AOP-面向切面编程:不用修改之前代码的基础上,可以动态的在某个动作之前加一些操作,动态的在某一个动作之后做点什么事。
(1)管理Gurget程序包,下载【Castle.Core】包,该包用来动态代理。
002.3-NET5零基础到精通实战全集 - 图158
(2)创建一个类为【CustomAutofacAop】,该类继承自【IInterceptor】接口,并实现接口中的【Intercept】方法。
002.3-NET5零基础到精通实战全集 - 图159
(3)在服务的抽象上面做一个标记,这个标记是用来:支持AOP扩展能够生效。
002.3-NET5零基础到精通实战全集 - 图160
(4)因为这个【CustomAutofacAop】实例也是通过Autofac的IOC来做的,所以需要在【Startup.cs】中创建的【ConfigureContainer】方法中,注册服务,让Autofac支持AOP。
002.3-NET5零基础到精通实战全集 - 图161

11.16-Autofac通过类支持AOP

(1)管理Gurget程序包,下载【Castle.Core】包,该包用来动态代理。
002.3-NET5零基础到精通实战全集 - 图162
(2)创建一个类为【CustomAutofacAopClass】,该类继承自【IInterceptor】接口,并实现接口中的【Intercept】方法。
002.3-NET5零基础到精通实战全集 - 图163
(3)在类上面做一个标记,这个标记是用来:支持AOP扩展能够生效。
002.3-NET5零基础到精通实战全集 - 图164
(4)因为这个【CustomAutofacAop】实例也是通过Autofac的IOC来做的,所以需要在【Startup.cs】中创建的【ConfigureContainer】方法中,注册服务,让Autofac支持AOP。
002.3-NET5零基础到精通实战全集 - 图165

11.17-Autofac单抽象多实现构造函数注入(MVC)

(1)在【Startup.cs】中创建的【ConfigureContainer】方法中,注册服务。
002.3-NET5零基础到精通实战全集 - 图166
(2)在控制器中调用。
002.3-NET5零基础到精通实战全集 - 图167

11.18-Autofac单抽象多实现属性注入

(1)道理和上面是一样的,可以吧Autofac上下文当做属性来注入。
002.3-NET5零基础到精通实战全集 - 图168
(2)在使用的时候,通过Autofac上下文+不同注册的标识,获取到不同的具体实例。
002.3-NET5零基础到精通实战全集 - 图169

十二、Filter过滤器

12.1-.NET5中5个Filter

  • AuthorizationFilter:鉴权授权
  • ResourceFilter:资源
  • ExceptionFilter:异常
  • ActionFilter:方法
  • ResultFilter:结果

12.2-ActionFilter

1.自定义一个CusotmActionFilterAttribute
002.3-NET5零基础到精通实战全集 - 图170
2.将特性标记在控制器中的某个方法上。
002.3-NET5零基础到精通实战全集 - 图171
3.执行顺序如下:

  • 执行控制器构造函数
  • 执行CusotmActionFilterAttribute类的OnActionExecuting()方法
  • 执行Action
  • 执行CusotmActionFilterAttribute类的OnActionExecuted()方法

12.3-ActionFilter的多种使用

1.通过实现IActionFilter接口来完扩展
002.3-NET5零基础到精通实战全集 - 图172
2.通过继承ActionFilterAttribute(系统提供的实现),根据不同的方法,达到自己的需求。
002.3-NET5零基础到精通实战全集 - 图173
3.异步版本的实现,通过实现IAsyncActionFilter接口来实现。
002.3-NET5零基础到精通实战全集 - 图174

12.4-ActionFilter的应用(日志处理)+依赖注入

1.做记录日志;ActionFilter比较靠近Action,日志记录就可以记录到Action内部做的一些处理。
(1)通过Log4net完成日志记录,需要注入Logger。
002.3-NET5零基础到精通实战全集 - 图175

12.5-Filter的多种注入和特点

(1)[CustomActionFilter]:Filter必须是无参数构造函数
(2)[TypeFilter(typeof(CusotmLogFilterAttribute))]:可以没有无参数构造函数,可以支持依赖注入。
(3) [ServiceFilter(typeof(CusotmLogFilterAttribute))]:可以没有无参数构造函数,可以支持依赖注入。但是如果要使用这个,必须在【Startup.cs】中创建的【ConfigureContainer】方法中,注册服务注册一下;
002.3-NET5零基础到精通实战全集 - 图176
002.3-NET5零基础到精通实战全集 - 图177
(4)问:依赖注入是如何支持的?
答:IOC来做到的

12.6-ServiceFilter_TypeFilter的原理/扩展定制FilterFacoty

1.为什么可以使用ServiceFilter/TypeFilter都可以支持依赖注入呢?—是IOC容器来完成。
(1)自定义一个特性类,继承Attribute,实现接口IFilterFactory,实现接口中的方法;通过构造函数传递需要实例化的特性的Type类型;在实现接口中,通过Type获取到实例;
002.3-NET5零基础到精通实战全集 - 图178
(2)标记在Action中。
002.3-NET5零基础到精通实战全集 - 图179

12.7-Filter生效范围和控制执行顺序

12.7.1-Filter生效范围

  • 标记在Action上,就只对当前Action生效。
  • 标记在Controller上,就对改Controller上所有的Action生效。
  • 全局注册,对于当前整个项目中的Actioin都生效(在【Startup.cs】中创建的【ConfigureServices】方法中进行全局注册)。

002.3-NET5零基础到精通实战全集 - 图180

12.7.2-Filter的执行顺序
问:如果有三个ActionFilter,分别注册全局、控制器、Action;执行顺序如何呢?
答:先执行全局——>控制器——>Action——>控制器——>全局
002.3-NET5零基础到精通实战全集 - 图181
//俄罗斯套娃

12.7.3-改变Filter的执行顺序
(1)将全局、控制器、Action的类继承自ActionFilterAttribute;
002.3-NET5零基础到精通实战全集 - 图182
(2)使用是传入Order参数,值越小越先执行。
002.3-NET5零基础到精通实战全集 - 图183
12.7.4-在自定义扩展中改变Filter的执行顺序
002.3-NET5零基础到精通实战全集 - 图184

12.7-ResourceFilter扩展定制做缓存(为缓存而生)

002.3-NET5零基础到精通实战全集 - 图185
(1)自定义一个特性类,继承Attribute,实现接口IResourceFilter,实现接口中的方法;
002.3-NET5零基础到精通实战全集 - 图186
(2)标记在Action中;
002.3-NET5零基础到精通实战全集 - 图187

12.8-Filter匿名

问题:如果全局注册,Filter生效于所有的Action,如果有部分Action我希望你不生效,怎么办呢?
匿名:可以避开Filter的检查;

如何支持自定义的Filter匿名:
(1)自定义一个特性类,继承Attribute。
002.3-NET5零基础到精通实战全集 - 图188
(2)需要在需要匿名的Filter内部,检查是否需要匿名(检查是否标记的有匿名特)如果有就避开。
002.3-NET5零基础到精通实战全集 - 图189
(3)使用Action。
002.3-NET5零基础到精通实战全集 - 图190

12.9-ExceptionFilter-异常处理

(1)自定义一个CustomExceptionAttribute,继承Attribute,实现IExceptionFilter接口。

  • 实现方法,先判断,异常是都被处理过,如果没有被处理过,就处理。
  • 分情况处理:1.如果是ajax请求,就返回JsonReulst,如果不是Ajax,就返回错误页面。

    1. public class CustomExceptionAttribute : Attribute, IExceptionFilter
    2. {
    3. private readonly IModelMetadataProvider _modelMetadataProvider = null;
    4. /// <summary>
    5. /// 依赖注入:Model元数据的驱动
    6. /// </summary>
    7. public CustomExceptionAttribute(
    8. IModelMetadataProvider modelMetadataProvider
    9. ) {
    10. _modelMetadataProvider = modelMetadataProvider;
    11. }
    12. /// <summary>
    13. /// 当异常发生的时候出发到这里来
    14. /// </summary>
    15. /// <param name="context"></param>
    16. public void OnException(ExceptionContext context)
    17. {
    18. //判断异常有没有被处理过
    19. if (context.ExceptionHandled == false) {
    20. //没有处理过,在这里开始处理
    21. //如果是Ajax请求(看看Header是不是XMLHttpRequest)
    22. if (this.IsAjaxRequest(context.HttpContext.Request))
    23. {
    24. //中断式:如果对Result赋值,请求到这里结束了,不在继续Action
    25. context.Result = new JsonResult(new
    26. {
    27. Result = false,
    28. Msg = context.Exception.Message
    29. });
    30. }
    31. else {
    32. //跳转到异常页面
    33. var result = new ViewResult { ViewName = "~/Views/Errors.cshtml" };
    34. result.ViewData = new ViewDataDictionary(_modelMetadataProvider, context.ModelState);
    35. result.ViewData.Add("Exception", context.Exception);
    36. result.ViewData.Add("ErrDate", DateTime.Now);
    37. //中断式:如果对Result赋值,请求到这里结束了,不在继续Action
    38. context.Result = result;
    39. }
    40. context.ExceptionHandled = true;//指定异常已经被处理了
    41. }
    42. }
    43. /// <summary>
    44. /// 判断是不是Ajax请求
    45. /// </summary>
    46. /// <param name="request"></param>
    47. /// <returns></returns>
    48. private bool IsAjaxRequest(HttpRequest request)
    49. {
    50. string header = request.Headers["X-Requested-With"];
    51. return "XMLHttpRequest".Equals(header);
    52. }
    53. }

    (2)注册到Action上,只对Action生效。
    002.3-NET5零基础到精通实战全集 - 图191
    //一般不会注册到Action上,一般会注册到全局(在【Startup.cs】中创建的【ConfigureServices】方法中进行全局注册)。
    002.3-NET5零基础到精通实战全集 - 图192
    问题:ExceptionFilter能捕捉到哪些异常?能捕获到所有异常吗?

12.10-ExceptionFilter-异常捕捉覆盖

  • 控制器实例化异常——能
  • 异常发生在Try-cache中——不能,因为异常已经被捕捉到了
  • 在视图中发生异常——不能
  • 在Service层(业务逻辑层)中发生异常——能
  • 在Action中发生异常——能
  • 请求错误路径异常——不能(但是可以通过中间件解决)

//在【Startup.cs】中创建的【Configure】方法中进行使用,只要状态不是200,就可以处理。

  1. #region 捕捉异常的补充
  2. //只要不是200,都能进来
  3. app.UseStatusCodePagesWithReExecute("/Home/Error/{0}");
  4. app.UseExceptionHandler(errorApp => {
  5. errorApp.Run(async context =>
  6. {
  7. context.Response.StatusCode = 200;
  8. context.Response.ContentType = "text/html";
  9. await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
  10. await context.Response.WriteAsync("Error!!!<br><br>\r\n");
  11. var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
  12. Console.WriteLine("------------------------------------------------");
  13. Console.WriteLine($"{ exceptionHandlerPathFeature?.Error.Message}");
  14. Console.WriteLine("------------------------------------------------");
  15. if (exceptionHandlerPathFeature?.Error is FileNotFoundException) {
  16. await context.Response.WriteAsync("File error thrown!<br><br>\r\n");
  17. }
  18. await context.Response.WriteAsync("<a href=\"/\">Home</a><br>\r\n");
  19. await context.Response.WriteAsync($"<p>{ exceptionHandlerPathFeature?.Error.Message}</p><br>\r\n");
  20. await context.Response.WriteAsync("</body></html>\r\n");
  21. await context.Response.WriteAsync(new string(' ', 512));//IE padding
  22. });
  23. });
  24. #endregion

12.11-ReusltFilter-结果Filter

002.3-NET5零基础到精通实战全集 - 图193
(1)创建ResultFilter
//自定义一个CustomResultFilterAttribute,继承Attribute,实现IResultFilter接口

  1. public class CustomResultFilterAttribute : Attribute, IResultFilter
  2. {
  3. /// <summary>
  4. /// 在渲染视图之前执行
  5. /// </summary>
  6. /// <param name="context"></param>
  7. public void OnResultExecuting(ResultExecutingContext context)
  8. {
  9. Console.WriteLine("在喧嚷视图之前执行");
  10. }
  11. /// <summary>
  12. /// 渲染视图之后执行
  13. /// </summary>
  14. /// <param name="context"></param>
  15. public void OnResultExecuted(ResultExecutedContext context)
  16. {
  17. Console.WriteLine("渲染视图之后执行");
  18. }
  19. }

(2)在Action上标记、使用
002.3-NET5零基础到精通实战全集 - 图194

12.11-ReusltFilter应用-开发双语言系统功能

//双语言系统其实就需要两个视图,要根据语言的不同,来选择不同的视图;因为在渲染视图之前,会进入到OnResultExecuting方法,就可以在这个方法中确定究竟使用哪一个视图文件。
002.3-NET5零基础到精通实战全集 - 图195

十三、权限验证

13.1-基于Seesion/Cookies的权限认证

为了拦截一些操作:

  • 传统的授权方式:Seesion、Cookies来完成:
    • 在请求某个Action之前来做校验,验证当前操作者是否登录过,登录过就有权限。
    • 如果没有权限就调到到登录页面去。
    • AOP-Filter、ActionResult

13.1.1-传统的登录需要匿名
当注册全局权限验证码的时候,需要将Login取消权限验证,不然会产生这个错误:
002.3-NET5零基础到精通实战全集 - 图196
解决:
(1)在【CustomActionAuthrizaFilterAttribute】中写代码写上这个代码支持匿名,继承自Attribute,实现IActionFilter接口。
002.3-NET5零基础到精通实战全集 - 图197
(2)在Login的Action写上这个特性。
002.3-NET5零基础到精通实战全集 - 图198

13.2-基于鉴权授权

//通过中间件来支持;
002.3-NET5零基础到精通实战全集 - 图199
(1)在【Startup.cs】中创建的【Configure】方法中进行中间件,使用中间件使用在App.UseRouting()之后,在app.UseEndpoints()之前。

  1. #region 第一步:告诉框架说我要使用鉴权授权功能
  2. app.UseAuthentication();//鉴权:检测有没有登录,登录的是谁,赋值给User
  3. app.UseAuthorization();//授权:检测有没有权限,是否能够访问后续的页面
  4. #endregion

(2)在【Startup.cs】中创建的【ConfigureServices】方法中增加一个AddAuthentication。

  1. #region 增加一个授权AddAuthentication
  2. //用Cookie
  3. services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).
  4. AddCookie(options =>
  5. {
  6. //如果授权是被,就跳转到这个路径中
  7. options.LoginPath = new PathString("Eighth/Login");
  8. });
  9. #endregion

(3)指定哪些Action需要做鉴权授权,直接标记特性;可以标记在控制器、Action,也可以标记在全局。
002.3-NET5零基础到精通实战全集 - 图200
(4)在控制器的Login登录方法中修改如下:

  1. #region 鉴权:鉴权,检测有没有登录,登录的是谁,赋值给User
  2. //rolelist 是登录成功后用户的角色---是来自于数据库的查询;不同的用户会查询出不同的角色;
  3. var rolelist = new List<string>() {
  4. "Admin",
  5. "Teacher",
  6. "Student"
  7. };
  8. //ClaimTypes.Role就是做权限认证的标识;
  9. var claims = new List<Claim>()//鉴别你是谁,相关信息
  10. {
  11. new Claim(ClaimTypes.Role,"Admin"),
  12. new Claim(ClaimTypes.Name,name),
  13. new Claim("password",password),//可以写入任意数据
  14. new Claim("Account","Administrator"),
  15. new Claim("role","admin"),
  16. new Claim("admin","admin"),
  17. };
  18. foreach (var role in rolelist)
  19. {
  20. claims.Add(new Claim(ClaimTypes.Role, role));
  21. }
  22. //将用户放在ClaimsPrincipal里面去了;相当身份证,将信息写到身份证里面去;
  23. ClaimsPrincipal userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Customer"));
  24. HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, userPrincipal, new AuthenticationProperties
  25. {
  26. ExpiresUtc = DateTime.UtcNow.AddMinutes(30),//过期时间:30分钟
  27. }).Wait();
  28. #endregion

002.3-NET5零基础到精通实战全集 - 图201
(5)当注册到控制器上、或者注册到全局上,又会出现这样的问题。
002.3-NET5零基础到精通实战全集 - 图202
解决:在Login的Action上加上匿名特性,这个匿名是来自于框架的;
[AllowAnonymousAttribute] //匿名

13.3-鉴权授权-角色授权(目前看是将角色定义死了)

//不同的用户,可能会存在不同的角色,然而不同的角色在访问不同的页面的时候,需要做不同的拦截。——角色授权其实就是通过角色不同,做不通的权限拦截。
1.保证上一个(13.2)代码是不变。
2.在Action需要加上对应拥有访问该视图的角色。
002.3-NET5零基础到精通实战全集 - 图203
//当访问【Index03】时,会被拦截,跳转到拦截页面:
002.3-NET5零基础到精通实战全集 - 图204

13.4-鉴权授权-策略授权

//之前的角色授权是在代码中把【角色】定义死了,我们更希望能够自己来完成校验逻辑:
(1)创建一个类为【CustomAuthorizationHandler】,这个类专用来检验逻辑的,要求继承自【AuthorizationHandler<>】泛型类(泛型类中要求实现【IAuthorizationRequirement】接口:见步骤2)然后在CustomAuthorizationHandler类中实现【HandleRequirementAsync】抽象方法,写逻辑。

  1. public class CustomAuthorizationHandler : AuthorizationHandler<CustomAuthorizationRequirement>
  2. {
  3. public CustomAuthorizationHandler() {
  4. }
  5. /// <summary>
  6. /// 实现抽象方法
  7. /// </summary>
  8. /// <param name="context"></param>
  9. /// <param name="requirement"></param>
  10. /// <returns></returns>
  11. protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomAuthorizationRequirement requirement)
  12. {
  13. if (requirement.Name == "Policy01") {
  14. //策略1的逻辑
  15. }
  16. if (requirement.Name == "Policy02")
  17. {
  18. //策略2的逻辑
  19. }
  20. if (requirement.Name == "Policy03")
  21. {
  22. //策略3的逻辑
  23. }
  24. if (true) {
  25. }
  26. //在这里可以定义自己的规则
  27. {
  28. /*
  29. 其实这里可以去数据库里面做一些查询,然后根据用户的信息,做计算:如果符合就context.Succd(requirement)
  30. 否则就Task。CompletedTask
  31. */
  32. }
  33. //context.User 鉴权成功(登录成功后),用户的信息
  34. var role = context.User.FindFirst(u => u.Value.Contains("admin"));
  35. if (role != null) {
  36. context.Succeed(requirement);//验证通过了
  37. }
  38. return Task.CompletedTask;//验证不通过
  39. }
  40. }

(2)创建一个为类【CustomAuthorizationRequirement】,改类实现【IAuthorizationRequirement】接口,用来放在AuthorizationHandler<>泛型类中。
002.3-NET5零基础到精通实战全集 - 图205
(3)怎么让其生效?在【Startup.cs】中创建的【ConfigureServices】方法中注册支持策略授权,也可以支持多种策略认证。

  1. #region 支持多种策略认证
  2. services.AddAuthorization(options =>
  3. {
  4. options.AddPolicy("customPolicy", policy =>
  5. {
  6. policy.AddRequirements(new CustomAuthorizationRequirement("Policy01"));
  7. });
  8. });
  9. services.AddAuthorization(options =>
  10. {
  11. options.AddPolicy("customPolicy01", policy =>
  12. {
  13. policy.AddRequirements(new CustomAuthorizationRequirement("Policy02"));
  14. });
  15. });
  16. services.AddAuthorization(options =>
  17. {
  18. options.AddPolicy("customPolicy02", policy =>
  19. {
  20. policy.AddRequirements(new CustomAuthorizationRequirement("Policy03"));
  21. });
  22. });
  23. #endregion
  24. //注册支持策略授权
  25. services.AddSingleton<IAuthorizationHandler, CustomAuthorizationHandler>();

十四、跨平台本质

  • web应用程序是一个控制台;——Main程序的入口

002.3-NET5零基础到精通实战全集 - 图206

  • 跨平台的主要原因:

跨平台的原因在于框架已经内置了一个主机,只要是程序启动,就是启动了主机,就可以监听端口;请求来了,只要是请求这个端口,主机就可以相应,所以无论是Windows还是在Linux下开发,都是要第一步完成环境的;这样就不同拘泥于在Windows还是Linux上。

十五、中间件

15.1-什么是中间件?

002.3-NET5零基础到精通实战全集 - 图207

  • 中间件的执行,是一个俄罗斯套娃;
  • 先Use先执行,每一次Use一个中间件,其实就是在之前的基础上,套了一层;
  • 请求来了以后,真正执行的时候,是一层一层的内部执行,在执行出来。

增加程序的扩展性:
如果想要增加一层,直接增加一个中间件就可以来完成。

15.2-常用的中间件

15.2.1-app.Run:中断式,只要使用当前中间件,后面的中间件都不执行;
002.3-NET5零基础到精通实战全集 - 图208

15.2.2-app.Map:判断路径中包含什么内容。
002.3-NET5零基础到精通实战全集 - 图209

15.2.3-app.MapWhen:判断式,两个委托,第一个委托做为判断条件内容,第二个委托,是要执行的逻辑
002.3-NET5零基础到精通实战全集 - 图210

15.3-中间件扩展-引用

(1)中间件的内容可以独立开,放在一个独立的类中,需要有一定的规则如下(创建了3个中间件):

  1. /// <summary>
  2. /// 要求构造函数带有RequestDelegate参数类型——目的是为了得到下一个中间件;
  3. /// 必须包含async Task Invoke方法,方法参数为HttpContext
  4. /// </summary>
  5. public class FirstMiddleware
  6. {
  7. private readonly RequestDelegate _next;
  8. /// <summary>
  9. /// 构造函数
  10. /// </summary>
  11. /// <param name="next"></param>
  12. public FirstMiddleware(RequestDelegate next) {
  13. _next = next;
  14. }
  15. public async Task Invoke(HttpContext context) {
  16. await context.Response.WriteAsync($"<h1 style='color:red'>{nameof(FirstMiddleware)}——Hello Word Start</h1>");
  17. await _next(context);
  18. await context.Response.WriteAsync($"<h2 style='color:blue'>{nameof(FirstMiddleware)}——Hello Word End</h1>");
  19. }
  20. }

(2)在【Startup.cs】中创建的【Configure】方法中通过以下方法使用中间件:
002.3-NET5零基础到精通实战全集 - 图211

十六、EF Core

16.1-EF Core可以做什么?

通过实体和数据库的映射,可以通过实体的操作完成对数据的操作。

映射:

  • 从数据库到代码视图的映射
  • 从代码到数据库的映射

16.2-DB First(数据库优先)

DB First:现有数据库,然后通过映射得到视图(和数据库的表对应);
(1)创建一个控制台应用程序,用来操作并测试。
002.3-NET5零基础到精通实战全集 - 图212
(2)管理Nuget包,安装对应需要的包。
002.3-NET5零基础到精通实战全集 - 图213
002.3-NET5零基础到精通实战全集 - 图214

  1. Install-Package Microsoft.EntityFramewrorkCore
  2. Install-Package Microsoft.Entit3FramewrorkCore.Sqlserver
  3. Install-Package Microsoft.EntityFramewrorkCore.Tools
  4. 工具--Nuget包管理器--程序包管理器控制台-命令执行(建议使用这种):
  5. Scaffold-DbContext "Data Source=.;Initial Catalog=CovidAPI;User ID=sa;Password=3344520" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Entity -Force -Context CovidAPIDbContext -ContextDir /
  6. --可以简写为:
  7. Scaffold-DbContext "Data Source=.;database=CovidAPI;uid=sa;pwd=3344520" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Entity
  8. 命令参数:
  9. -0utputDir 实体文件所存放的文件目录
  10. -ContextDir DbContext文件存放的目录
  11. -Context DbContext文件名
  12. -Schemas 需要生成实体数据的数据表所在的模式
  13. -Tables 等需要生成实体数据的数据表的集合
  14. -DataArnotations
  15. -UseDatabaseNames 直接使用数据库中的表名和列名(某些版本不支持)
  16. -Force 强制执行,重写已经存在的实体文件

(3)将【EFCore.DbFirst】设置为启动项目,并在【程序包管理器控制台】中选中摸默认项目为【EFCore.DbFirst】,然后执行以上命令:
002.3-NET5零基础到精通实战全集 - 图215
//命令执行完毕,然后会根据数据库中的表生成以下实体和DbContext:
002.3-NET5零基础到精通实战全集 - 图216

16.3-Code First(代码优先-迁移)

迁移:代码优先,先有代码再有数据库;数据库随着业务变化迁移改变。
迁移命令:
002.3-NET5零基础到精通实战全集 - 图217
(1)可以通过EFCore代码有的API从代码生成数据库。
002.3-NET5零基础到精通实战全集 - 图218
(2)可以通过迁移命令生成数据库。
2.1-需要引入程序包
002.3-NET5零基础到精通实战全集 - 图219
2.2-将【EFCore.CodeFirst】设置为启动项目,并在【程序包管理器控制台】中选中摸默认项目为【EFCore.CodeFirst】,然后执行对应的命令:
002.3-NET5零基础到精通实战全集 - 图220
//然后可以看到生成了迁移文件和快照文件。
002.3-NET5零基础到精通实战全集 - 图221

16.4-EFCore抓取SQL语句

16.4.1-日志输出
(1)打开Nuget包安装日志输出包。
002.3-NET5零基础到精通实战全集 - 图222
(2)在数据上下文对象中的【OnConfiguring】方法中进行配置。
002.3-NET5零基础到精通实战全集 - 图223

16.4.2-SQL Srever Profiler工具
(1)在SQL Srever数据库中【工具】——>【SQL Server Profiler】。
002.3-NET5零基础到精通实战全集 - 图224
(2)打开之后进行数据库连接,和服务器是同一个服务器。
002.3-NET5零基础到精通实战全集 - 图225
(3)选择模板和事件。
002.3-NET5零基础到精通实战全集 - 图226
002.3-NET5零基础到精通实战全集 - 图227

16.5-EFCore-LinqQuery(LINQ查询)

  1. #region 其他查询
  2. using (CovidAPIDbContext context = new CovidAPIDbContext())
  3. {
  4. //Lambda查询
  5. {
  6. var idlist = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 134, 46, 23, 46, 34 };//in查询
  7. var list = context.Employees.Where(u => idlist.Contains(u.Id));//in查询
  8. foreach (var item in list)
  9. {
  10. Console.WriteLine(item.Name);
  11. }
  12. }
  13. //LINQ查询
  14. {
  15. var list = from u in context.Employees
  16. where new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }.Contains(u.Id)
  17. select u;
  18. foreach (var item in list)
  19. {
  20. Console.WriteLine(item.Name);
  21. }
  22. }
  23. //一般用于分页:Skip、Take——跳过第一条2,取2条
  24. {
  25. //var list = (from u in context.Employees
  26. // where new int[] { 1, 2, 3, 4, 5, 6, 7, 7 }.Contains(u.Id)
  27. // orderby u.Id
  28. // select new
  29. // {
  30. // Name = u.Name,
  31. // Img = u.PictureUrl
  32. // }).Skip(1).Take(2);
  33. //foreach (var item in list)
  34. //{
  35. // Console.WriteLine(item.Name);
  36. //}
  37. }
  38. //多条件
  39. {
  40. var list = context.Employees.Where(u => u.Name.StartsWith("三") && u.Name.EndsWith("三哈"))
  41. .Where(u => u.Name.StartsWith("张"))
  42. .Where(u => u.Name.Length < 5)
  43. .OrderBy(u => u.Id);
  44. foreach (var item in list)
  45. {
  46. Console.WriteLine(item.Name);
  47. }
  48. }
  49. //连接查询
  50. {
  51. var list = (from u in context.Employees
  52. join c in context.Departments
  53. on u.DepartmentId equals c.Id //注意:条件不能写 "==" 等于号,要使用equals
  54. where new int[] { 1, 2, 3, 4, 5, 6, 7 }.Contains(u.Id)
  55. select new
  56. {
  57. Id = u.Id,
  58. Nmae = u.Name,
  59. Bumen = c.Name
  60. }).OrderBy(u => u.Id);
  61. foreach (var item in list)
  62. {
  63. Console.WriteLine($"{item.Id}---{item.Nmae}---{item.Bumen}");
  64. }
  65. }
  66. //左连接
  67. //没有右连接,如果要做右连接,就把顺序调换一下就行了
  68. {
  69. var list = (from u in context.Employees
  70. join c in context.Departments on u.DepartmentId equals c.Id
  71. into ucList
  72. from uc in ucList.DefaultIfEmpty()
  73. where new int[] { 1, 2, 3, 4, 5, 6 }.Contains(u.Id)
  74. select new
  75. {
  76. Id = u.Id,
  77. Nmae = u.Name,
  78. Bumen = uc.Name
  79. }).OrderBy(u => u.Id);
  80. foreach (var item in list)
  81. {
  82. Console.WriteLine($"{item.Id}---{item.Nmae}---{item.Bumen}");
  83. }
  84. }
  85. #endregion
  86. }

16.5-EFCore-执行查询、修改SQL语句

  1. #region 其他查询
  2. using (CovidAPIDbContext context = new CovidAPIDbContext())
  3. {
  4. //Lambda查询
  5. {
  6. var idlist = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 134, 46, 23, 46, 34 };//in查询
  7. var list = context.Employees.Where(u => idlist.Contains(u.Id));//in查询
  8. foreach (var item in list)
  9. {
  10. Console.WriteLine(item.Name);
  11. }
  12. }
  13. //LINQ查询
  14. {
  15. var list = from u in context.Employees
  16. where new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }.Contains(u.Id)
  17. select u;
  18. foreach (var item in list)
  19. {
  20. Console.WriteLine(item.Name);
  21. }
  22. }
  23. //一般用于分页:Skip、Take——跳过第一条2,取2条
  24. {
  25. //var list = (from u in context.Employees
  26. // where new int[] { 1, 2, 3, 4, 5, 6, 7, 7 }.Contains(u.Id)
  27. // orderby u.Id
  28. // select new
  29. // {
  30. // Name = u.Name,
  31. // Img = u.PictureUrl
  32. // }).Skip(1).Take(2);
  33. //foreach (var item in list)
  34. //{
  35. // Console.WriteLine(item.Name);
  36. //}
  37. }
  38. //多条件
  39. {
  40. var list = context.Employees.Where(u => u.Name.StartsWith("三") && u.Name.EndsWith("三哈"))
  41. .Where(u => u.Name.StartsWith("张"))
  42. .Where(u => u.Name.Length < 5)
  43. .OrderBy(u => u.Id);
  44. foreach (var item in list)
  45. {
  46. Console.WriteLine(item.Name);
  47. }
  48. }
  49. //连接查询
  50. {
  51. var list = (from u in context.Employees
  52. join c in context.Departments
  53. on u.DepartmentId equals c.Id //注意:条件不能写 "==" 等于号,要使用equals
  54. where new int[] { 1, 2, 3, 4, 5, 6, 7 }.Contains(u.Id)
  55. select new
  56. {
  57. Id = u.Id,
  58. Nmae = u.Name,
  59. Bumen = c.Name
  60. }).OrderBy(u => u.Id);
  61. foreach (var item in list)
  62. {
  63. Console.WriteLine($"{item.Id}---{item.Nmae}---{item.Bumen}");
  64. }
  65. }
  66. //左连接
  67. //没有右连接,如果要做右连接,就把顺序调换一下就行了
  68. {
  69. var list = (from u in context.Employees
  70. join c in context.Departments on u.DepartmentId equals c.Id
  71. into ucList
  72. from uc in ucList.DefaultIfEmpty()
  73. where new int[] { 1, 2, 3, 4, 5, 6 }.Contains(u.Id)
  74. select new
  75. {
  76. Id = u.Id,
  77. Nmae = u.Name,
  78. Bumen = uc.Name
  79. }).OrderBy(u => u.Id);
  80. foreach (var item in list)
  81. {
  82. Console.WriteLine($"{item.Id}---{item.Nmae}---{item.Bumen}");
  83. }
  84. }
  85. #endregion
  86. }

16.6-EFCore-State(动态跟踪)

增删改的动作是统一由SavaChanges以后才落实到数据库中去的:
数据库的增删改动作都是统一由SavaChanges之后,统一提交到数据库,是通过状态跟踪,任何一个增删改查的操作都会记录一个状态在内存中,增删改查的状态,一旦SavaChanges,就根据状态落实到数据库中去。

// 摘要:当前这个实体没有被上下文所跟踪 Detached=0, // 摘要:实体正在被上下文跟踪,并且存在于数据库中,他的数据库中的数据没有被更改。 Unchanged=1, // 摘要:实体被上下文跟踪,并且存在数据库中,并已标记从数据库中删除,并还没有删除。 Deleted=2, // 摘要:实体被上下文跟踪,部分或他的所有属性都已经被修改。 Modified=3, // 摘要:实体被上下文跟踪,但在数据库中还不存在。 Added=4
002.3-NET5零基础到精通实战全集 - 图228
//注意:
状态跟踪实现了增删改便捷,但是也会有性能消耗;因为每次都要去和内存的副本的状态去做比较的。

16.7-EFCore-事务(调优小技巧)

SavaChanges就是保证事务的,多个对于数据库的操作,统一SavaChanges,就是开启了一个事务的。

EF Core自带的两个事务:
(1)SavaChanges
(2)IDbContextTransaction
002.3-NET5零基础到精通实战全集 - 图229

16.8-EFCore-调优小技巧

(1)尽量不要进行Tolist();
002.3-NET5零基础到精通实战全集 - 图230
(2)尽量不要使用FirstOrDefault,要使用Find进行查询。
002.3-NET5零基础到精通实战全集 - 图231
(3)只做查询时,不需要进行增删改,就去掉状态跟踪。
002.3-NET5零基础到精通实战全集 - 图232
//全局取消
002.3-NET5零基础到精通实战全集 - 图233

十七、EFCore整合-分层架构

17.1-分层架构

002.3-NET5零基础到精通实战全集 - 图234

  • 没有分层的缺点:
    • 职责不清晰
    • 如果有一处修改,可能会导致需要重新修改,需要重新测试。
  • 分层的优点:
    • 职责更清晰
    • 需求的变更不同修改全部代码
    • 人员更好调配——让更专业的人做专业的事。
  • 三层架构:
  • UI:展示给用户,视图层
  • BLL:业务逻辑层
  • DAL:数据访问层

//分层以后:要求不能跨层调用,UI层——BLL层——DAL层

17.2-依赖注入

支持依赖注入:必须有抽象,依赖抽象而不是依赖实现细节。
上一篇

002.2-NETCore3.x入门课堂笔记

下一篇

002.4-NET Core和Blog.Core【老张的哲学】