版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-1
C#新语法1说明1、C#8.0、C#9.0和C#10.0中增加了很多的新语法,这里讲解常用、重点的新语法。2、部分语法只有VS2022及以上版本才支持,从本节课开始,使用VS2022+.NET6。顶级语句(C#9.0)1、直接在C#文件中直接编写入口方法的代码,不用类,不用Main。经典写法仍然支持。反编译一下了解真相。2、同一个项目中只能有一个文件具有顶级语句。3、顶级语句中可以直接使用await语法,也可以声明函数全局using指令(C#10)1、将global修饰符添加到using前,这个命名空间就应用到整个项目,不用重复using。2、通常创建一个专门用来编写全局using代码的C#文件。3、如果csproj中启用了<ImplicitUsings>enable</ImplicitUsings>,编译器会自动隐式增加对于System、System.Linq等常用命名空间的引入,不同各类型项目引入的命名空间也不一样。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-2
C#新语法2Using资源管理的问题1、复习:实现了IDisposible接口的对象可以用using进行管理。2、问题:如果一段代码中有很多非托管资源需要被释放的话,代码中就会存在着多个嵌套的using语句。Using声明(C#8)在实现了Idisposable/IAsyncDisposable接口的类型的变量声明前加上using,当代码执行离开变量的作用域时,对象就会被释放。usingSqlConnectionconn=newSqlConnection("DataSource=.;InitialCatalog=db1;IntegratedSecurity=True");conn.Open();usingSqlCommandcmd=conn.CreateCommand();cmd.CommandText="select*fromT_Articles";usingSqlDataReaderreader=cmd.ExecuteReader();while(reader.Read()){stringtitle=reader.GetString(reader.GetOrdinal("Title"));Console.WriteLine(title);}Using声明的陷阱usingvaroutStream=File.OpenWrite("e:/1.txt");usingvarwriter=newStreamWriter(outStream);writer.WriteLine("hello");strings=File.ReadAllText("e:/1.txt");Console.WriteLine(s);文件范围的命名空间声明(C#10)1、在之前版本的C#中,类型必须定义在namespace中。2、namespaceTMS.Admin;classTeacher{publicintId{get;set;}publicstringName{get;set;}}谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-3
C#新语法3:可空引用类型可空的引用类型(C#8)1、复习:C#数据类型分为值类型和引用类型两种,值类型的变量不可以为空,而引用类型变量可以为空。2、问题:如果不注意检查引用类型变量是否可空,就有可能造成程序中出现NullReferenceException异常。可空的引用类型(C#8)1、csproj中<Nullable>enable</Nullable>启用可空引用类型检查。2、在引用类型后添加“?”修饰符来声明这个类型是可空的。对于没有添加“?”修饰符的引用类型的变量,如果编译器发现存在为这个变量赋值null的可能性的时候,编译器会给出警告信息。有警告的声明publicclassStudent{ publicstringName{get;set;} publicstringPhoneNumber{get;set;} publicStudent(stringname) { this.Name=name; }}消除警告publicclassStudent{ publicstringName{get;set;} publicstring?PhoneNumber{get;set;} publicStudent(stringname) { this.Name=name; }}有警告的代码Students1=GetData();Console.WriteLine(s1.Name.ToLower());Console.WriteLine(s1.PhoneNumber.ToLower());StudentGetData(){Students1=newStudent("Zack");s1.PhoneNumber="999";returns1;}消除警告的代码Students1=GetData();Console.WriteLine(s1.Name.ToLower());if(s1.PhoneNumber!=null){Console.WriteLine(s1.PhoneNumber.ToLower());}else{Console.WriteLine("手机号为空");}思考:第1-2行?使用!抑制警告1、如果程序员确认被访问的变量、成员确实不会出现为空的情况,也可以在访问可空的变量、成员的时候加上!来抑制编译器的警告。Students1=GetData();Console.WriteLine(s1.Name.ToLower());Console.WriteLine(s1.PhoneNumber!.ToLower());2、不要滥用。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-4
C#新语法4:record基础记录(record)类型(C#9)1、C#中的==运算符默认是判断两个变量指向的是否是同一个对象,即使两个对象内容完全一样,也不相等。可以通过重写Equals方法、重写==运算符等来解决这个问题,不过需要开发人员编写非常多的额外代码。2、在C#9.0中增加了记录(record)类型的语法,编译器会为我们自动生成Equals、GetHashcode等方法。publicrecordPerson(stringFirstName,stringLastName);3、Personp1=newPerson("Yang","Zack");Personp2=newPerson("Yang","Zack");Personp3=newPerson("Gates","Bill");Console.WriteLine(p1);Console.WriteLine(p1==p2);Console.WriteLine(p1==p3);Console.WriteLine(p1.FirstName);谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-5
C#新语法5:record的原理及深入原理探究1、编译器会根据Person类型中的属性定义,自动为Person类型生成包含全部属性的构造方法。注意,默认情况下,编译器会生成一个包含所有属性的构造方法,因此,我们编写newPerson()、newPerson(“Yang”)这两种写法都是不可以的。也会生成ToString方法和Equals等方法。2、通过反编译看背后原理。避免反编译器的优化,需要把反编译器生成的代码改成C#8.0的语法。结论:record就是普通的一个类。3、record数据类型为我们提供了为所有属性赋值的构造方法,所有属性都是只读的,而且对象可以进行值相等性比较,并且提供了可读性强的ToString()返回值。在需要编写一些不可变类并且需要进行对象值比较的对象时候,record可以帮我们把代码的编写难度大大降低。Record深入1、可以实现部分属性是只读的、而部分属性是可以读写。2、默认生成的构造方法的行为不能修改,我们可以为类型提供多个构造方法,然后其他构造方法通过this调用默认的构造方法。3、也推荐使用只读属性的类型。这样的所有属性都为只读的类型叫做“不可变类型”,可以让程序逻辑简单,减少并发访问、状态管理等的麻烦。对象的副本1、record也是普通类,变量的赋值是引用的传递。这是和结构体不同之处。2、生成一个对象的副本,这个对象的其他属性值与原对象的相同,只有一个或者少数几个属性改变。麻烦的做法:Useru2=newUser(u1.UserName,"test@example",u1.Age);3、用with关键字简化:Useru2=u1with{Email=“test@example”};
创建的也是拷贝。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-6
ASP.NETCore入门没有“课程顾问”关于我的.NET书为什么到这里才说私人联系方式没有所谓“课程顾问”,只是了解大家学习视频的情况私信(不是“评论”):你真帅什么是ASP.NETCore1、ASP.NETCore是.NET中做Web开发的框架。2、ASP.NETCoreMVC。3、ASP.NETCoreWebAPI:前后端分离、多端开发。4、ASP.NETCoreMVC其实包含WebAPI,不过……5、侧重WebAPI6、需要你有Html、JavaScript的基础,需要了解Http协议。ASP.NETCoreMVC入门1、VS中创建MVC项目。2、.NET6中ASP.NETCore项目结构和旧版不一样,默认MinimalAPI,没有Startup。仍然支持旧版写法。3、运行项目。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-7
ASP.NETCore
MVCASP.NETCoreMVC概念模型(Model)、视图(View)和控制器(Controller)老师是控制器,成绩单是模型,你爸是视图。项目结构1、控制器由Controller类实现,视图一般是扩展名为cshtml的文件,而模型则是只有属性的普通C#类。2、控制器类的名字一般以Controller结尾,并且被放到Controllers文件夹下。控制器的名字为控制器的类名去掉Controller。3、视图一般被放到Views文件夹下的控制器名字的文件夹下。4、视图→浏览器端提交的请求→模型→控制器→处理→模型→视图。渲染:Render。MVC项目1、publicrecordPerson(stringName,boolIsVIP,DateTimeCreatedTime);2、publicclassTestController:Controller{ publicIActionResultDemo1() { varmodel=newPerson("Zack",true,newDateTime(1999,9,9)); returnView(model); }}3、@modelMVC项目1.Models.Person<div>姓名:@Model.Name</div><div>@(Model.IsVIP?"VIP":"普通会员")</div><div>注册时间:@Model.CreatedTime</div>谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-8
效率利器HotReloadHotReload1、困惑:修改了服务器端的代码,必须重新运行程序。2、方法1:【启动(不调试)】3、方法2:.NET6开始的HotReload(热重载)局限删除了方法或者修改了参数,热重载就可能无法正常执行HotReload轶事启示:开源对于微软和开发者意味着什么。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-9
WebAPI入门1WebAPI1、什么是结构化的Http接口。Json。2、WebAPI项目的搭建。3、WebAPI项目没有Views文件夹。4、运行项目,解读代码结构。5、【启用OpenAPI支持】→swagger,在界面上进行接口的测试。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-10
WebAPI入门2其他谓词1、为控制器类增加一个标注了[HttpPost]的操作方法。2、把用户提交的内容保存到文本文件中,方法的返回值为保存的文件名。[HttpPost]publicstringSaveNote(SaveNoteRequestreq){ stringfilename=$"{req.Title}.txt"; System.IO.File.WriteAllText(filename,req.Content); returnfilename;}3、测试接口。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-11
什么是RESTRPC1、WebAPI两种风格:面向过程(RPC)、面向REST(REST)2、RPC:“控制器/操作方法“的形式把服务器端的代码当成方法去调用。把HTTP当成传输数据的通道,不关心HTTP谓词。通过QueryString、请求报文体给服务器传递数据。状态码。比如:/Persons/GetAll、/Persons/GetById?id=8、/Persons/Update、/Persons/DeleteById/8;RESTREST:按照HTTP的语义来使用HTTP协议:1、URL用于资源的定位:/user/888、/user/888/orders;2、HTTP谓词:GET、POST(新增)、PUT(整体更新)、DELETE、PATCH(局部更新)等;3、什么是“幂等”,举例?DELETE、PUT、GET是幂等的,POST不幂等;4、GET的响应可以被缓存;5、服务器端要通过状态码来反映资源获取的结果:404、403(没有权限)、201(新增成功)。[Route("api/[controller]")]publicclassPersonsController:ControllerBase{ [HttpGet] publicIEnumerable<Person>GetPersons(); [HttpGet("{id}")] publicPersonGetPerson(longid); [HttpPut("{id}")] publicvoidUpdatePerson(longid,Personperson); [HttpPost] publicvoidSavePerson(Personperson); [HttpDelete("{id}")] publicvoidDeletePerson(longid);}如何请求这样的控制器?RPC:业务驱动,自然。REST:要求开发人员对REST原则更了解、并且有更多的设计能力。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-12
REST的优缺点REST的优点1、通过URL对资源定位,语义更清晰;2、通过HTTP谓词表示不同的操作,接口自描述;3、可以对GET、PUT、DELETE请求进行重试;4、可以用GET请求做缓存;5、通过HTTP状态码反映服务器端的处理结果,统一错误处理机制。6、网关等可以分析请求处理结果。REST的缺点1、真实系统中的资源非常复杂,很难清晰地进行资源的划分,对技术人员的业务和技术水平要求高。2、不是所有的操作都能简单地对应到确定的HTTP谓词中。3、系统的进化可能会改变幂等性。4、通过URL进行资源定位不符合中文用户的习惯。5、HTTP状态码个数有限。6、有些环节会篡改非200响应码的响应报文。7、有的客户端不支持PUT、DELETE请求。选择1、REST是学术化的概念,仅供参考。为什么AWS、ES等比较RESTful。为什么阿里、腾讯等很多系统不RESTful?2、根据公司情况,进行REST的选择和裁剪。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-13
Restful中如何传递参数HTTP传递参数的三种方式URL:适合定位;长度限制。QueryString:灵活;长度限制。请求报文体:灵活;长度不限制;不支持GET、Delete。三种方式的不同语义URL:资源定位。QueryString:URL之外的额外数据。请求报文体:供PUT、POST提供数据。实施指南1、完全按照HTTP语义要求高。2、我的建议:1)对于保存、更新类的请求POST、PUT请求,把全部参数都放到请求报文体中;2)对于DELETE请求,要传递的参数就是一个资源的id,因此把参数放到QueryString中即可;3)对于GET请求,一般参数的内容都不会太长,因此统一通过QueryString传递参数就可以。对于极少数参数内容超过URL限制的请求,由于GET、PUT请求都是幂等的,因此我们把请求改成通过PUT请求,然后通过报文体来传递参数。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-14
ASP.NETCore如何返回错误码状态码1、REST:通过HTTP状态码返回服务器端的处理结果。2、问题:1)HTTP状态码数量有限;2)HTTP的状态码并不适合用来表示业务层面的错误码,它是一个用来表示技术层面信息的状态码。新增用户的操作中,如果服务器端要求Json格式,客户端提交XML,服务器返回400是没问题的。但是如果用户名格式错误或者用户名重复,存在200派和400派。400派观点1、网关等可以监控HTTP状态码,如果接口频繁出现4xx状态码,那么就说明客户端的代码不完善。2、很多的系统都是按照HTTP状态码的不同含义进行设计的。如果失败了服务器端返回的状态码还是200的话,这会违背软件设计的初衷。200派观点网络的问题归网络、业务的问题归业务。业务错误不应该和技术错误混在一起。把系统日志和业务日志区分开。大企业也不统一百度:200派;谷歌:400派;同一家公司:企业微信和微信小程序:200派;微信支付:400派;我的观点:400派1、对于数据库服务器连接失败、请求报文格式、服务器端异常等非业务错误,服务器端应该返回4xx、5xx等状态码。2、对于业务层面的错误,比如用户不存在,我们要使用4xx等HTTP状态码返回。同样在响应报文体中给出详细的错误信息,比如{“code”:3,”message”:”用户不存在”}。3、不仅要返回4xx的HTTP状态码,而且不要忘了通过响应报文体给出详细的错误信息。对于用户不存在,不仅要404,而且把响应报文体设置为{“code”:3,”message”:”用户名已存在”},这样能区分出来是哪里的问题。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-15
ASP.NETCore中Rest落地指南如果没有条件完美地实现REST
那么……实现建议1、使用RPC风格:Users/AddNew、Users/GetAll、Users/DeleteById。2、对于可以缓存的操作,使用GET请求;对于幂等的更新操作,使用PUT请求;对于幂等的删除操作,使用DELETE请求;对于其他操作,统一使用POST请求。3、参数:保存、更新类的请求使用POST、PUT请求,把全部参数都放到请求报文体中;对于GET和DELETE请求,把参数放到QueryString中。推荐尽量使用URL做资源定位。4、对于业务错误,服务器端返回合适的4XX状态码,不知道该选择哪个状态码就用400;同时,在报文体中通过code参数提供业务错误码以及错误消息。5、如果请求的处理执行成功,服务器端返回值为200的Http状态码,如果有需要返回给客户端的数据,则服务器端把这些数据放到响应报文体中。实现技术1、控制器上[Route("[controller]/[action]")]2、强制要求控制器中不同的操作用不同的方法名3、把[HttpGet]、[HttpPost]、[HttpDelete]、[HttpPut]等添加到对应的操作方法上。注意:如果控制器中存在一个没有添加[HttpGet]、[HttpPost]等的public方法,Swagger就会报错,可以用[ApiExplorerSettings(IgnoreApi=true)]演示一下谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-16
ASP.NETCoreWebAPI
控制器及返回值控制器类1、ControllerBase与Controller2、控制器类可以不显式地继承自任何类。Action方法的异步1、Action方法既可以同步也可以异步。2、异步Action方法的名字一般不需要以Async结尾。3、WebAPI中Action方法的返回值如果是普通数据类型,那么返回值就会默认被序列化为Json格式。4、WebAPI中的Action方法的返回值同样支持IActionResult类型,不包含类型信息,因此Swagger等无法推断出类型,所以推荐用ActionResult<T>,它支持类型转换,从而用起来更简单。publicActionResult<Person>GetPerson(intid){ if(id<=0) returnBadRequest("id必须是正数"); elseif(id==1) returnnewPerson(1,"杨中科",18); elseif(id==2) returnnewPerson(2,"Zack",8); else returnNotFound(“人员不存在”);//自定义消息也重要}谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-17
ASP.NETCoreWebAPI
Action方法参数捕捉URL占位符1、在[HttpGet]、[HttpPost]等中使用占位符,比如{schoolName},捕捉路径中的内容,从而供Action方法的参数使用。/Students/GetAll/school/MIT/class/A001[HttpGet("school/{schoolName}/class/{classNo}")]2、捕捉的值会被自动赋值给Action中同名的参数;如果名字不一致,可以用[FromRoute(Name="名字")]3、演示混用。捕捉QueryString的值1、使用[FromQuery]来获取QueryString中的值。如果名字一致,只要为参数添加[FromQuery]即可;而如果名字不一致,[FromQuery(Name=名字)]。2、QueryString和Route可以混用。演示。Json报文体1、WebAPI的开发模式下,Json格式的请求体是主流。2、只要声明一个模型类和Json请求的格式一致即可。3、也是可以把从URL获取参数、从请求报文体获取数据等这些混合使用。[HttpPost("classId/{classId}")]publicActionResult<long>AddNew(longclassId,StudentModels)4、一定要设定请求头中的Content-Type为application/json,而且数据必须是合法的json格式。其他方式WebAPI中很少用的方式:1、从Content-Type为multipart/form-data的请求中获取数据的[FromForm]2、从请求报文头中获取值的[FromHeader]。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-18
ASP.NETCore
前后端分离开发1前后端分离1、传统MVC开发模式:前后端的代码被放到同一个项目中,前端人员负责编写页面的模板,而后端开发人员负责编写控制器和模型的代码并且“套模板”。缺点:互相依赖;耦合性强;责任划分不清。2、主流的“前后端分离”:前端开发人员和后端开发人员分别负责前端和后端代码的开发,各自在自己的项目中进行开发;后端人员只写WebAPI接口,页面由前端人员负责。为什么“前后端分离”更流行:需求变动越来越大、交付周期越来越短、多端支持。。优点:独立开发,不互相依赖;耦合性低;责任划分清晰;前后端分别部署,可以针对性运维(扩容等)缺点:对团队的沟通能力要求更高,提前沟通好接口和通知接口变更;不利于SEO(可以用“服务器端渲染”SSR);对运维要求更高。3、只有大项目才需要前后端分离吗?[Route("api/[controller]/[action]")][ApiController]publicclassLoginController:ControllerBase{ [HttpPost] publicActionResult<LoginResult>Login(LoginRequestloginReq) { if(loginReq.UserName=="admin"&&loginReq.Password=="123456") { varprocesses=Process.GetProcesses().Select(p=>newProcessInfo( p.Id,p.ProcessName,p.WorkingSet64)).ToArray(); returnnewLoginResult(true,processes); } elsereturnnewLoginResult(false,null); }}谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-19
ASP.NETCore
前后端分离开发2搭建前端开发环境1、WebAPI做后端开发,不绑定前端技术,也支持其他客户端。这一节用Vue演示,不讲解Vue基础。2、Vue搭建步骤:1)安装Node.js2)设定国内镜像npmconfigsetregistry3)安装yarn:npminstall-gyarn4)创建Vue项目:yarncreate@vitejs/app项目名字5)按照提示运行项目。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-20
ASP.NETCore
前后端分离开发3前后端结合11、在src文件夹下创建views文件夹。2、安装ajax库axios,项目根目录:yarnaddaxios3、在views文件夹下创建Login.vue文件<inputtype="text"v-model="state.loginData.userName"/><inputtype="submit"value="登录"@click="loginSubmit"/><trv-for="pincesses":key="p.id"><td>{{(p.workingSet64/1024)}}K</td></tr>importaxiosfrom'axios';import{reactive,onMounted}from'vue'exportdefault{name:'Login',setup(){conststate=reactive({loginData:{},processes:[]});constloginSubmit=async()=>{constpayload=state.loginData;//if(!data.isOK)constresp=awaitaxios.post('https://localhost:44360/api/Login/Login',payload);constdata=resp.data;cesses=cesses;}return{state,loginSubmit};},}前后端结合24、使用vue-router来做前端的页面路由。在前端的项目根目录执行:yarnaddvue-router@45、在src下创建route文件夹,并且在route文件夹下创建index.js文件import{createRouter,createWebHashHistory}from"vue-router";importTestfrom"../views/Test.vue";importLoginfrom"../views/Login.vue";constroutes=[{path:"/",redirect:"/Test"},{path:"/Test",name:"Test",component:Test},{path:"/Login",name:"Login",component:Login}]constrouter=createRouter({history:createWebHashHistory(),routes:routes});exportdefaultrouter前后端结合36、编辑src/main.js,增加importrouterfrom‘./route’以及use(router),修改main.js:import{createApp}from'vue'importAppfrom'./App.vue'importrouterfrom'./route'createApp(App).use(router).mount('#app’);7、src/App.vue中增加指向Login视图的链接以及显示路由视图的<router-view/><template><div><router-linkto="Login">Login</router-link></div><router-view/></template>CORS1、跨域通讯的问题。解决方案:JSONP、前端代理后端请求、CORS等。2、CORS原理:在服务器的响应报文头中通过access-control-allow-origin告诉浏览器允许跨域访问的域名。3、在Program.cs的“varapp=builder.Build()”这句代码之前注册string[]urls=new[]{"http://localhost:3000"};builder.Services.AddCors(options=>options.AddDefaultPolicy(builder=>builder.WithOrigins(urls).AllowAnyMethod().AllowAnyHeader().AllowCredentials()));4、在Program.cs的app.UseHttpsRedirection()这句代码之前增加一行app.UseCors()谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-21
ASP.NETCore中依赖注入的使用ASP.NETCore中服务注入的地方1、在ASP.NETCore项目中一般不需要自己创建ServiceCollection、IServiceProvider。在Program.cs的builder.Build()之前向builder.Services中注入。2、在Controller中可以通过构造方法注入服务。3、演示。低使用频率的服务1、把Action用到的服务通过Action的参数注入,在这个参数上标注[FromServices]。和Action的其他参数不冲突。2、一般不需要,只有调用频率不高并且资源的创建比较消耗资源的服务才[FromServices]。3、只有Action方法才能用[FromServices],普通的类默认不支持。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-22
案例:开发模块化的服务注册框架框架的使用1、目的:在分层项目中,让各个项目负责各自的服务注册。2、先学会使用:1)Install-PackageZack.Commons2)每个项目中创建一个或者多个实现了IModuleInitializer接口的类。3)初始化DI容器varassemblies=ReflectionHelper.GetAllReferencedAssemblies();services.RunModuleInitializers(assemblies);原理讲解1、/yangzhongke/NETBookMaterials/2、主要分析RunModuleInitializers方法和ReflectionHelper.cs谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-23
程序员的性能优化万金油:缓存什么是缓存缓存(Caching)是系统优化中简单又有效的工具,投入小收效大。数据库中的索引等简单有效的优化功能本质上都是缓存。缓存的概念1、缓存命中2、缓存命中率3、缓存数据不一致多级缓存谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-24
ASP.NETCore客户端响应缓存cache-control1、RFC7324是HTTP协议中对缓存进行控制的规范,其中重要的是cache-control这个响应报文头。服务器如果返回cache-control:max-age=60,则表示服务器指示浏览器端“可以缓存这个响应内容60秒”。2、我们只要给需要进行缓存控制的控制器的操作方法添加ResponseCacheAttribute这个Attribute,ASP.NETCore会自动添加cache-control报文头。3、验证:编写一个返回当前时间的Action方法。分别加和不加ResponseCacheAttribute看区别。也F12看看Network。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-25
ASP.NETCore服务器端响应缓存ResponseCachingMiddleware1、如果ASP.NETCore中安装了“响应缓存中间件”,那么ASP.NETCore不仅会继续根据[ResponseCache]设置来生成cache-control响应报文头来设置客户端缓存,而且服务器端也会按照[ResponseCache]的设置来对响应进行服务器端缓存。和客户端端缓存的区别?来自多个不同客户端的相同请求。2、“响应缓存中间件”的好处:对于来自不同客户端的相同请求或者不支持客户端缓存的客户端,能降低服务器端的压力。3、用法:app.MapControllers()之前加上app.UseResponseCaching()。请确保app.UseCors()写到app.UseResponseCaching()之前。演示效果1、大部分浏览器都是支持RFC7324规范的,所以不方便用来测试服务器端响应缓存。用默认忽略RFC7324规范的PostMan测试。试一下请求服务器端。2、可以在浏览器的“开发人员工具”中禁用缓存的,但是和PostMan中不一致,为什么?“cache-control:no-cache”3、也可以让Postman在请求报文头中加入“cache-control:no-cache”,只要在Postman的设置中开启【Sendno-cacheheaders】服务器端响应缓存很鸡肋1、无法解决恶意请求给服务器带来的压力。2、服务器端响应缓存还有很多限制,包括但不限于:响应状态码为200的GET或者HEAD响应才可能被缓存;报文头中不能含有Authorization、Set-Cookie等。3、不怪他,honorRFC7234.
It’s
afeature,notabug.4、怎么办?采用内存缓存、分布式缓存等。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-26
ASP.NETCore中的内存缓存内存缓存(In-memorycache)1、把缓存数据放到应用程序的内存。内存缓存中保存的是一系列的键值对,就像Dictionary类型一样。2、内存缓存的数据保存在当前运行的网站程序的内存中,是和进程相关的。因为在Web服务器中,多个不同网站是运行在不同的进程中的,因此不同网站的内存缓存是不会互相干扰的,而且网站重启后,内存缓存中的所有数据也就都被清空了。内存缓存用法1、启用:builder.Services.AddMemoryCache()2、注入IMemoryCache接口,查看接口的方法:TryGetValue、Remove、Set、GetOrCreate、GetOrCreateAsync3、用GetOrCreateAsync讲解publicasyncTask<Book[]>GetBooks(){logger.LogInformation("开始执行GetBooks");varitems=awaitmemCache.GetOrCreateAsync("AllBooks",async(e)=>{logger.LogInformation("从数据库中读取数据");returnawaitdbCtx.Books.ToArrayAsync();});logger.LogInformation("把数据返回给调用者");returnitems;}谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-27
缓存的过期时间策略缓存的过期时间1、上面的例子中的缓存不会过期,除非重启服务器。2、解决方法:在数据改变的时候调用Remove或者Set来删除或者修改缓存(优点:及时);过期时间(只要过期时间比较短,缓存数据不一致的情况也不会持续很长时间。)3、两种过期时间策略:绝对过期时间、滑动过期时间。它们分别是什么?缓存的绝对过期时间1、GetOrCreateAsync()方法的回调方法中有一个ICacheEntry类型的参数,通过ICacheEntry对当前的缓存项做设置。2、AbsoluteExpirationRelativeToNow用来设定缓存项的绝对过期时间。3、测试演示。缓存的滑动过期时间1、ICacheEntry的SlidingExpiration属性用来设定缓存项的滑动过期时间。2、测试演示。两种过期时间混用使用滑动过期时间策略,如果一个缓存项一直被频繁访问,那么这个缓存项就会一直被续期而不过期。可以对一个缓存项同时设定滑动过期时间和绝对过期时间,并且把绝对过期时间设定的比滑动过期时间长,这样缓存项的内容会在绝对过期时间内随着访问被滑动续期,但是一旦超过了绝对过期时间,缓存项就会被删除。内存缓存的是与非1、无论用那种过期时间策略,程序中都会存在缓存数据不一致的情况。部分系统(博客等)无所谓,部分系统不能忍受(比如金融)。2、可以通过其他机制获取数据源改变的消息,再通过代码调用IMemoryCache的Set方法更新缓存。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-28
缓存穿透问题什么是缓存穿透stringcacheKey="Book"+id;//缓存键Book?b=memCache.Get<Book?>(cacheKey);if(b==null)//如果缓存中没有数据{ //查询数据库,然后写入缓存
b=awaitdbCtx.Books.FindAsync(id); memCache.Set(cacheKey,b);}缓存穿透的解决方案1、解决方法:把“查不到”也当成一个数据放入缓存。2、我们用GetOrCreateAsync方法即可,因为它会把null值也当成合法的缓存值。stringcacheKey="Book"+id;varbook=awaitmemCache.GetOrCreateAsync(cacheKey,async(e)=>{ varb=awaitdbCtx.Books.FindAsync(id); logger.LogInformation("数据库查询:{0}",b==null?"为空":"不为空"); returnb;});logger.LogInformation("Demo5执行结束:{0}",book==null?"为空":"不为空");谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-29
缓存雪崩和数据混乱问题缓存雪崩1、缓存项集中过期引起缓存雪崩。2、解决方法:在基础过期时间之上,再加一个随机的过期时间。缓存数据混乱publicUserGetUserInfo(){ GuiduserId=...;//获取当前用户Id returnmemCache.GetOrCreate("UserInfo",(e)=>{ returnctx.User.Find(userId); });}解决方法:合理设置key谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-30
封装内存缓存操作的帮助类需求1、IQueryable、IEnumerable等类型可能存在着延迟加载的问题,如果把这两种类型的变量指向的对象保存到缓存中,在我们把它们取出来再去执行的时候,如果它们延迟加载时候需要的对象已经被释放的话,就会执行失败。因此缓存禁止这两种类型。2、实现随机缓存过期时间接口1、publicinterfaceIMemoryCacheHelper{TResult?GetOrCreate<TResult>(stringcacheKey, Func<ICacheEntry,TResult?>valueFactory,intexpireSeconds);Task<TResult?>GetOrCreateAsync<TResult>(stringcacheKey, Func<ICacheEntry,Task<TResult?>>valueFactory,intexpireSeconds);voidRemove(stringcacheKey);}2、使用演示NuGet包:Zack.ASPNETCore3、查看实现代码/yangzhongke/NETBookMaterials/tree/main/%E6%9C%80%E5%90%8E%E5%A4%A7%E9%A1%B9%E7%9B%AE%E4%BB%A3%E7%A0%81/YouZack-VNext/Zack.ASPNETCore/MemoryCacheHelper.cs
谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-31
分布式缓存分布式系统中的内存缓存如果集群节点的数量非常多的话,这样的重复查询也同样可能会把数据库压垮。分布式缓存服务器分布式缓存服务器1、常用的分布式缓存服务器有Redis、Memcached等。2、.NETCore中提供了统一的分布式缓存服务器的操作接口IDistributedCache,用法和内存缓存类似。3、分布式缓存和内存缓存的区别:缓存值的类型为byte[],需要我们进行类型转换,也提供了一些按照string类型存取缓存值的扩展方法。用什么做缓存服务器1、用SQLServer做缓存性能并不好。2、Memcached是缓存专用,性能非常高,但是集群、高可用等方面比较弱,而且有“缓存键的最大长度为250字节”等限制。可以安装EnyimMemcachedCore这个第三方NuGet包。3、Redis不局限于缓存,Redis做缓存服务器比Memcached性能稍差,但是Redis的高可用、集群等方便非常强大,适合在数据量大、高可用性等场合使用。分布式缓存用法1、NuGet安装Microsoft.Extensions.Caching.StackExchangeRedis2、builder.Services.AddStackExchangeRedisCache(options=>{options.Configuration="localhost";options.InstanceName=“yzk_”;//避免混乱});3、用时间显示测试用法。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-32
封装分布式缓存操作的帮助类需求1、解决缓存穿透、缓存雪崩等问题。2、自动地进行其他类型的转换。publicinterfaceIDistributedCacheHelper{ TResult?GetOrCreate<TResult>(stringcacheKey,Func<DistributedCacheEntryOptions, TResult?>valueFactory,intexpireSeconds); Task<TResult?>GetOrCreateAsync<TResult>(stringcacheKey, Func<DistributedCacheEntryOptions,Task<TResult?>>valueFactory,intexpireSeconds); voidRemove(stringcacheKey); TaskRemoveAsync(stringcacheKey);}3、实现类/yangzhongke/NETBookMaterials/tree/main/%E6%9C%80%E5%90%8E%E5%A4%A7%E9%A1%B9%E7%9B%AE%E4%BB%A3%E7%A0%81/YouZack-VNext/Zack.ASPNETCore\DistributedCacheHelper.cs谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-33
ASP.NETCore与配置系统的集成ASP.NETCore默认添加的配置提供者1)加载现有的IConfiguration。2)加载项目根目录下的appsettings.json。3)加载项目根目录下的appsettings.{Environment}.json。4)当程序运行在开发环境下,程序会加载“用户机密”配置。5)加载环境变量中的配置。6)加载命令行中的配置。配置的环境问题1、Why?开发环境、测试环境、生产环境需要进行不同配置。2、运行环境:ASP.NETCore会从环境变量中读取名字为ASPNETCORE_ENVIRONMENT的值。推荐值:Development(开发环境)、Staging(测试环境)、Production(生产环境)。3、读取方法:app.Environment.EnvironmentName、app.Environment.IsDevelopment()……4、在Windows和VS(推荐开发时用)中设置环境变量的方法。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-34
.NETCore防止机密配置外泄悲剧UserSecrets1、把不方便放到appsettings.json中的机密信息放到一个不在项目中的json文件中。2、在ASP.NETCore项目上单击鼠标右键,选择【管理用户机密】。3、secrets.json文件到底保存在哪里?如何和项目建立关系?csproj文件中的<UserSecretsId>注意事项1、供开发人员使用的,不适合在生产环境中使用。2、仍然是明文存储。不想别人看到怎么办?AzureKeyVault、Zack.AnyDBConfigProvider等。无法完全避免。加强安全防控更重要。3、如果因为重装、新员工等原因导致secrets.json重建,就要重新配置,麻烦。如果影响大的话,还是用集中式配置服务器。谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-35
ASP.NETCore配置系统综合案例功能需求1) 系统的主要配置(Redis、Smtp)放到配置专用的数据库中。Zack.AnyDBConfigProvider2) 连接配置数据库的连接字符串配置在“用户机密”中。"DataSource=.;InitialCatalog=demo1;IntegratedSecurity=SSPI;"3) 把Smtp的配置显示到界面上。4) 程序启动的时候就连接Redis,并且把Redis连接对象注册到依赖注入系统中。builder.Services.AddSingleton<IConnectionMultiplexer>(sp=>{stringconnStr=builder.Configuration.GetValue<string>("Redis:ConnStr");returnConnectionMultiplexer.Connect(connStr);});谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-36
分层项目中EFCore的用法分层项目的建立1、为什么要项目分层?带来什么问题?2、创建一个.NET类库项目BooksEFCore,放实体等类。NuGet:Microsoft.EntityFrameworkCore.Relational3、BooksEFCore中增加实体类Book和配置类。数据库的配置11、上下文类MyDbContext:为什么正式项目中最好不要在MyDbContext写数据库配置(连接不同的DB甚至不同类型的DB)。尽量数据库配置的代码写到ASP.NETCore项目中。不重写OnConfiguring方法,而是为MyDbContext类的构造方法增加DbContextOptions<MyDbContext>参数。在ASP.NETCore项目对DbContextOptions的配置。2、创建ASP.NETCore项目,添加对“BooksEFCore”项目的引用。NuGet安装Microsoft.EntityFrameworkCore.SqlServer。3、配置文件、配置代码等放到ASP.NETCore项目中。builder.Services.AddDbContext<MyDbContext>(opt=>{stringconnStr=builder.Configuration.GetConnectionString("Default");opt.UseSqlServer(connStr);});数据库的配置24、在Controller中注入MyDbContext,编写测试代码。5、生成实体类的迁移脚本。多项目的环境下执行Add-Migration的时候可能会出现这个错误,原理是什么?数据库的配置36、不用研究多项目中Add-Migration的细节。实用的方案:编写实现IDesignTimeDbContextFactory接口的类,把配置放到里面,反正是开发环境用而已。7、可以把连接字符串配置到环境变量中,不过MyDesignTimeDbContextFactory中来读取配置系统,可以直接用Environment.GetEnvironmentVariable()读取环境变量。8、数据库迁移脚本要生成到BooksEFCore中,因此为这个项目安装Microsoft.EntityFrameworkCore.Tools、Microsoft.EntityFrameworkCore.SqlServer。然后把BooksEFCore设置为启动项目,并且在【程序包管理器控制台】中也选中BooksEFCore项目后,执行Add-Migration和Update-Database步骤汇总:1、建类库项目,放实体类、DbContext、配置类等DbContext中不配置数据库连接,而是为DbContext增加一个DbContextOptions类型的构造函数。2、EFCore项目安装对应数据库的EFCoreProvider3、core项目引用EFCore项目,并且通过AddDbContext来注入DbContext及对DbContext进行配置。4、Controller中就可以注入DbContext类使用了。5、让开发环境的Add-Migration知道连接哪个数据库在EFCore项目中创建一个实现了IDesignTimeDbContextFactory的类。并且在CreateDbContext返回一个连接开发数据库的DbContext。
publicMyDbContextCreateDbContext(string[]args){DbContextOptionsBuilder<MyDbContext>builder=newDbContextOptionsBuilder<MyDbContext>();stringconnStr="DataSource=.;InitialCatalog=demo666;IntegratedSecurity=SSPI;";builder.UseSqlServer(connStr);MyDbContextctx=newMyDbContext(builder.Options);returnctx;}如果不在乎连接字符串被上传到Git,就可以把连接字符串直接写死到CreateDbContext;如果在乎,那么CreateDbContext里面很难读取到VS中通过简单的方法设置的环境变量,所以必须把连接字符串配置到Windows的正式的环境变量中,然后再Environment.GetEnvironmentVariable读取。6、正常执行Add-Migration、Update-Database迁移就行了。需要把EFCore项目设置为启动项目,并且在【程序包管理器控制台】中也要选中EFCore项目,并且安装Microsoft.EntityFrameworkCore.SqlServer、Microsoft.EntityFrameworkCore.Tools慎用AddDbContextPool1、用AddDbContextPool代替AddDbContext可以实现“DbContext池”。2、AddDbContextPool的问题:1)用AddDbContextPool注册的DbContext无法注入其他服务?而AddDbContext可以。为啥要为DbContext注册服务?为什么AddDbContextPool不行?2)很多数据库的ADO.NET提供者都实现了数据库连接池机制,可能会有冲突,实用的时候需要自己调节。3、AddDbContextPool意义不大:“小上下文”策略有数据库连接池谢谢我是杨中科一名快乐的程序员主讲人:杨中科
.NET
/.NETCore教程
第四部分
ASP.NETCore-37
案例:批量注册上下文的方案案例:复杂.NETCore项目中批量注册上下文1、项目采用“小上下文”策略,在项目中可能存在着多个上下文类,如果手动AddDbContext就太麻烦。2、反射扫描程序集中所有的上下
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 企业安全距离制度规范
- 培训机构末位淘汰制度
- 矿山安全生产规章制度
- 2026年海上轮机理论知识考试题库(附答案)
- 烧结工艺指标培训
- 空气消毒仪培训
- 空姐化妆培训
- DB65T 4991-2025伊犁绢蒿种子质量分级及检验
- 外爬架施工方案(印尼)
- 安全生产责任制履职情况报告
- 2025年贵州事业编a类考试真题及答案
- 2026绍兴理工学院招聘32人备考题库及答案详解(考点梳理)
- 2026上海市事业单位招聘笔试备考试题及答案解析
- GB/T 21558-2025建筑绝热用硬质聚氨酯泡沫塑料
- 2025年领导干部任前廉政知识测试题库(附答案)
- 贷款担保人免责协议书
- 《电力机车牵引控制技术》课件全套 第1-6章 电力机车牵引控制概述- HXD3B型电力机车总线及TCMS系统
- 胃镜室院感知识培训
- 长期照护师内部技能考核试卷及答案
- 2025年中考英语复习必背1600课标词汇(30天记背)
- 2025小红书7月家居家装行业月报
评论
0/150
提交评论