.NET?6開(kāi)發(fā)TodoList應(yīng)用之實(shí)現(xiàn)DELETE請(qǐng)求與HTTP請(qǐng)求冪等性
需求
先說(shuō)明一下關(guān)于原本想要去更新的PATCH請(qǐng)求的文章,從目前試驗(yàn)的情況來(lái)看,如果是按照.NET 6的項(xiàng)目結(jié)構(gòu)(即只使用一個(gè)Program.cs完成程序初始化),那微軟官方給出的文檔目前還沒(méi)有對(duì)應(yīng)地更新,按照之前的方式進(jìn)行JsonPatch的配置是不行的,目前已經(jīng)有人在Github微軟的官方文檔Repo下提了ISSUE: .NET 6: JsonPatch in ASP.NET Core web API。并且因?yàn)镻ATCH的使用頻率并不高,所以我暫時(shí)跳過(guò)那篇,先把進(jìn)度繼續(xù)往后走,看微軟什么時(shí)候把這個(gè)issue解決一下我再看情況把PATCH那一節(jié)補(bǔ)上。
本文我們來(lái)看最后一個(gè)常用HTTP請(qǐng)求類(lèi)型:DELETE。
目標(biāo)
實(shí)現(xiàn)并驗(yàn)證應(yīng)用正確處理DELETE請(qǐng)求。并對(duì)HTTP請(qǐng)求的冪等性做簡(jiǎn)單的介紹。
原理與思路
經(jīng)過(guò)關(guān)于Create、Update、Get的實(shí)現(xiàn),對(duì)于Delete的實(shí)現(xiàn)我們的思路是很清晰的。我們需要?jiǎng)?chuàng)建Delete的Command及其Handler,然后在Controller中通過(guò)Mediatr發(fā)送請(qǐng)求即可。
實(shí)現(xiàn)
在Application/TodoList下新建DeleteTodoList文件夾,并新建DeleteTodoListCommand:
DeleteTodoListCommand.cs
using MediatR; using TodoList.Application.Common.Exceptions; using TodoList.Application.Common.Interfaces; namespace TodoList.Application.TodoLists.Commands.DeleteTodoList; public class DeleteTodoListCommand : IRequest { public Guid Id { get; set; } } public class DeleteTodoListCommandHandler : IRequestHandler<DeleteTodoListCommand> { private readonly IRepository<Domain.Entities.TodoList> _repository; public DeleteTodoListCommandHandler(IRepository<Domain.Entities.TodoList> repository) { _repository = repository; } public async Task<Unit> Handle(DeleteTodoListCommand request, CancellationToken cancellationToken) { var entity = await _repository.GetAsync(request.Id); if (entity == null) { throw new NotFoundException(nameof(TodoList), request.Id); } await _repository.DeleteAsync(entity,cancellationToken); // 對(duì)于Delete操作,演示中并不返回任何實(shí)際的對(duì)象,可以結(jié)合實(shí)際需要返回特定的對(duì)象。Unit對(duì)象在MediatR中表示Void return Unit.Value; } }
在Controller中添加Delete的接口處理:
TodoListController.cs
// 省略其他... [HttpDelete("{id:guid}")] public async Task<ApiResponse<object>> Delete(Guid id) { return ApiResponse<object>.Success(await _mediator.Send(new DeleteTodoListCommand { Id = id })); }
這里可能值得強(qiáng)調(diào)的是關(guān)于EntityFrameworkCore中對(duì)于關(guān)聯(lián)實(shí)體DELETE操作的處理方式:
打開(kāi)Infrastructure/Migrations文件夾,我們可以在遷移領(lǐng)域?qū)嶓w的那次Migration生成的.Designer.cs文件中發(fā)現(xiàn)這樣一段配置:
// 省略其他... modelBuilder.Entity("TodoList.Domain.Entities.TodoItem", b => { b.HasOne("TodoList.Domain.Entities.TodoList", "List") .WithMany("Items") .HasForeignKey("ListId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("List"); });
可以看到在OnDelete中配置的是DeleteBehavior.Cascade行為模式,關(guān)于DeleteBehavior,可以參考Referential Constraint Action Options。實(shí)際上總共有七種可以設(shè)置的行為模式:
- DeleteBehavior.Cascade
- DeleteBehavior.NoAction
- DeleteBehavior.Restrict
- DeleteBehavior.SetNull
- DeleteBehavior.ClientCascade
- DeleteBehavior.ClientNoAction
- DeleteBehavior.ClientSetNull
關(guān)于這七種DeleteBehavior,可以參考這篇博文:Entity Framework Core 關(guān)聯(lián)刪除,博主在其中進(jìn)行了比較詳細(xì)的實(shí)驗(yàn)和總結(jié)。
可以根據(jù)實(shí)際需要去顯式地配置DeleteBehavior。另外,習(xí)慣觀察生成的Migrations文件,也是學(xué)習(xí)EFCore一些慣例或者說(shuō)默認(rèn)配置的很好的方法。
驗(yàn)證
啟動(dòng)Api項(xiàng)目,發(fā)送DELETE請(qǐng)求:
請(qǐng)求
響應(yīng)
并且從數(shù)據(jù)庫(kù)里我們以可以發(fā)現(xiàn),這條TodoList下包含的TodoItem也被一同刪除了。
總結(jié)
到此為止HTTP常用的四大請(qǐng)求我們已經(jīng)通過(guò)幾個(gè)例子講完了,關(guān)于HEAD請(qǐng)求OPTION請(qǐng)求以及遺留的PATCH請(qǐng)求后面會(huì)寫(xiě)完。下一篇文章開(kāi)始我們一起學(xué)習(xí)如何使用FluentValidation來(lái)進(jìn)行請(qǐng)求參數(shù)校驗(yàn)。
關(guān)于HTTP請(qǐng)求冪等性的介紹
首先明確兩個(gè)概念:
1.什么叫做HTTP請(qǐng)求是否安全:如果我們執(zhí)行請(qǐng)求后,對(duì)應(yīng)的資源實(shí)體不發(fā)生改變,我們稱(chēng)這個(gè)請(qǐng)求是安全的;
2.什么叫做HTTP請(qǐng)求是否冪等:對(duì)于執(zhí)行請(qǐng)求后產(chǎn)生的副作用(即指如果請(qǐng)求不安全,則稱(chēng)其會(huì)產(chǎn)生副作用),請(qǐng)求執(zhí)行一次和執(zhí)行多次的副作用是相同的,我們稱(chēng)這個(gè)請(qǐng)求是冪等的,很顯然安全的請(qǐng)求一定是冪等的。
了解了這兩個(gè)概念后,我們直接來(lái)看這張表格,快速地對(duì)HTTP請(qǐng)求的安全性和冪等性有一個(gè)認(rèn)識(shí)。
鑒于PATCH方法并不常用,那么重點(diǎn)需要關(guān)注的主要就是POST請(qǐng)求,以及一部分的PUT請(qǐng)求(比如更新的字段是在當(dāng)前字段值的基礎(chǔ)上進(jìn)行計(jì)算而新得出這種場(chǎng)景,實(shí)際就不是冪等的,但是我們一般不推薦在Update時(shí)做這種類(lèi)型的操作,更推薦的是把計(jì)算邏輯前置到接口響應(yīng)處理前,以整體設(shè)置值的方式去Update實(shí)體)。一般而言POST請(qǐng)求是用來(lái)創(chuàng)建資源的,如果不采取某種方式來(lái)保證執(zhí)行結(jié)果的實(shí)際冪等性,那么該請(qǐng)求產(chǎn)生的副作用將是難以控制和處理的。
如何保證接口的冪等性?
正式因?yàn)椴⒎撬械腍TTP請(qǐng)求(在這里我們可以泛化到任意類(lèi)型的接口請(qǐng)求)都是冪等的,而不管是應(yīng)用程序內(nèi)的容錯(cuò)還是服務(wù)之間因?yàn)榉謪^(qū)導(dǎo)致的對(duì)請(qǐng)求的冪等性更為嚴(yán)格的要求(尤其是在分布式系統(tǒng)中,對(duì)于分區(qū)導(dǎo)致的請(qǐng)求重試的場(chǎng)景),我們需要在設(shè)計(jì)和實(shí)現(xiàn)接口的時(shí)候,把冪等性設(shè)計(jì)考慮進(jìn)來(lái),提高接口的魯棒性。
總體來(lái)說(shuō),實(shí)現(xiàn)接口的冪等性有兩種思路:一種是通過(guò)代碼邏輯去限制重復(fù)調(diào)用出現(xiàn)的副作用;第二種是通過(guò)Token唯一性來(lái)保證同一個(gè)請(qǐng)求不會(huì)被調(diào)用多次。
通過(guò)代碼邏輯去限制副作用的實(shí)現(xiàn)方式有很多種:從前端/界面的層次上去人為限制請(qǐng)求的重復(fù)發(fā)送(比如按鈕置灰禁止點(diǎn)擊之類(lèi)的),通過(guò)在數(shù)據(jù)庫(kù)層面應(yīng)用鎖或使用唯一索引,通過(guò)在邏輯執(zhí)行過(guò)程中應(yīng)用鎖等方式。這種方式只能針對(duì)一些通過(guò)滿足某些判斷進(jìn)行的邏輯實(shí)現(xiàn),有其局限性。
通過(guò)Token唯一性保證冪等的思路大致是這樣:生成全局唯一的Token保存下來(lái),并在前端頁(yè)面獲取保存,發(fā)送請(qǐng)求時(shí)連同Token一起發(fā)到后端,后端先進(jìn)行Token校驗(yàn),校驗(yàn)通過(guò)發(fā)送實(shí)際請(qǐng)求或執(zhí)行邏輯,完成后刪除舊Token并生成新Token,那么前端下次攜帶保存的舊Token來(lái)請(qǐng)求時(shí),因?yàn)門(mén)oken校驗(yàn)不通過(guò)而拒絕繼續(xù)執(zhí)行。這種方式就好比短信驗(yàn)證碼,只有第一次攜帶這個(gè)驗(yàn)證碼請(qǐng)求時(shí)會(huì)成功,后端判斷第一次請(qǐng)求有效后就會(huì)把這個(gè)驗(yàn)證碼置為無(wú)效,下次你就無(wú)法攜帶相同的驗(yàn)證碼繼續(xù)發(fā)起請(qǐng)求了。例子不是特別恰當(dāng),但是可以類(lèi)比著進(jìn)行理解。?
到此這篇關(guān)于.NET 6開(kāi)發(fā)TodoList應(yīng)用之實(shí)現(xiàn)DELETE請(qǐng)求與HTTP請(qǐng)求冪等性的文章就介紹到這了,更多相關(guān).NET 6實(shí)現(xiàn)DELETE請(qǐng)求與HTTP請(qǐng)求冪等性內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- .NET 6開(kāi)發(fā)TodoList應(yīng)用之實(shí)現(xiàn)查詢分頁(yè)
- .NET 6開(kāi)發(fā)TodoList應(yīng)用之實(shí)現(xiàn)ActionFilter
- .NET 6開(kāi)發(fā)TodoList應(yīng)用之實(shí)現(xiàn)接口請(qǐng)求驗(yàn)證
- .NET 6開(kāi)發(fā)TodoList應(yīng)用之實(shí)現(xiàn)PUT請(qǐng)求
- .NET 6開(kāi)發(fā)TodoList應(yīng)用之實(shí)現(xiàn)全局異常處理
- .NET 6開(kāi)發(fā)TodoList應(yīng)用之使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求
- .NET?6開(kāi)發(fā)TodoList應(yīng)用之實(shí)現(xiàn)Repository模式
- .NET?6開(kāi)發(fā)TodoList應(yīng)用之使用MediatR實(shí)現(xiàn)POST請(qǐng)求
- .NET 6開(kāi)發(fā)TodoList應(yīng)用引入數(shù)據(jù)存儲(chǔ)
- .NET?6開(kāi)發(fā)TodoList應(yīng)用引入第三方日志庫(kù)
- .NET 6開(kāi)發(fā)TodoList應(yīng)用實(shí)現(xiàn)結(jié)構(gòu)搭建
- .NET?6開(kāi)發(fā)TodoList應(yīng)用實(shí)現(xiàn)系列背景
- 使用.NET?6開(kāi)發(fā)TodoList應(yīng)用之引入數(shù)據(jù)存儲(chǔ)的思路詳解
- 使用.NET?6開(kāi)發(fā)TodoList應(yīng)用之領(lǐng)域?qū)嶓w創(chuàng)建原理和思路
- .NET?6開(kāi)發(fā)TodoList應(yīng)用之請(qǐng)求日志組件HttpLogging介紹
相關(guān)文章
Entity Framework使用DbModelBuilder API創(chuàng)建表結(jié)構(gòu)
這篇文章介紹了Entity Framework使用DbModelBuilder API創(chuàng)建表結(jié)構(gòu)的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-03-03Visual Studio(VS2017)配置C/C++ PostgreSQL9.6.3開(kāi)發(fā)環(huán)境
這篇文章主要為大家詳細(xì)介紹了Visual Studio(VS2017)配置C/C++,PostgreSQL9.6.3開(kāi)發(fā)環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07ASP.NET Mvc開(kāi)發(fā)之刪除修改數(shù)據(jù)
這篇文章主要介紹了ASP.NET Mvc開(kāi)發(fā)中的刪除修改數(shù)據(jù)功能,感興趣的小伙伴們可以參考一下2016-03-03MVC+EasyUI+三層新聞網(wǎng)站建立 實(shí)現(xiàn)登錄功能(四)
這篇文章主要為大家詳細(xì)介紹了MVC+EasyUI+三層新聞網(wǎng)站建立的第四篇,教大家實(shí)現(xiàn)登錄功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07.NET Core利用動(dòng)態(tài)代理實(shí)現(xiàn)AOP(面向切面編程)
用動(dòng)態(tài)代理可以做AOP(面向切面編程),進(jìn)行無(wú)入侵式實(shí)現(xiàn)自己的擴(kuò)展業(yè)務(wù),調(diào)用者和被調(diào)用者之間的解耦,提高代碼的靈活性和可擴(kuò)展性。本文將為大家詳細(xì)介紹實(shí)現(xiàn)的方法,感興趣的可以學(xué)習(xí)一下2022-01-01SQL Server 2008 R2:error 26 開(kāi)啟遠(yuǎn)程連接詳解
本篇文章小編為大家介紹,SQL Server 2008 R2:error 26 開(kāi)啟遠(yuǎn)程連接詳解。需要的朋友參考下2013-04-04.NET下通過(guò)HttpListener實(shí)現(xiàn)簡(jiǎn)單的Http服務(wù)
這篇文章主要為大家詳細(xì)介紹了.NET下通過(guò)HttpListener實(shí)現(xiàn)簡(jiǎn)單Http服務(wù)的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-09-09