1. 程式人生 > >ASP.NET Core Web API下事件驅動型架構的實現(一):一個簡單的實現

ASP.NET Core Web API下事件驅動型架構的實現(一):一個簡單的實現

很長一段時間以來,我都在思考如何在ASP.NET Core的框架下,實現一套完整的事件驅動型架構。這個問題看上去有點大,其實主要目標是為了實現一個基於ASP.NET Core的微服務,它能夠非常簡單地訂閱來自於某個渠道的事件訊息,並對接收到的訊息進行處理,於此同時,它還能夠向該渠道傳送事件訊息,以便訂閱該事件訊息的消費者能夠對訊息資料做進一步處理。讓我們回顧一下微服務之間通訊的幾種方式,分為同步和非同步兩種。同步通訊最常見的就是RESTful API,而且非常簡單輕量,一個Request/Response迴環就結束了;非同步通訊最常見的就是通過訊息渠道,將載有特殊意義的資料的事件訊息傳送到訊息渠道,而對某種型別訊息感興趣的消費者,就可以獲取訊息中所帶資訊並執行相應操作,這也是我們比較熟知的事件驅動架構的一種表現形式。雖然事件驅動型架構看起來非常複雜,從微服務的實現來看顯得有些繁重,但它的應用範圍確實很廣,也為服務間通訊提供了新的思路。瞭解DDD的朋友相信一定知道CQRS體系結構模式,它就是一種事件驅動型架構。事實上,實現一套完整的、安全的、穩定的、正確的事件驅動架構並不簡單,由於非同步特性帶來的一致性問題會非常棘手,甚至需要藉助一些基礎結構層工具(比如關係型資料庫,不錯!只能是關係型資料庫)來解決一些特殊問題。本文就打算帶領大家一起探探路,基於ASP.NET Core Web API實現一個相對比較簡單的事件驅動架構,然後引出一些有待深入思考的問題,留在今後的文章中繼續討論。或許,本文所引入的原始碼無法直接用於生產環境,但我希望本文介紹的內容能夠給到讀者一些啟發,並能夠幫助解決實際中遇到的問題。

術語約定

本文會涉及一些相關的專業術語,在此先作約定:

  • 事件:在某一特定時刻發生在某件事物上的一件事情,例如:在我撰寫本文的時候,電話鈴響了

  • 訊息:承載事件資料的實體。事件的序列化/反序列化和傳輸都以訊息的形式進行

  • 訊息通訊渠道:一種帶有訊息路由功能的資料傳輸機制,用以在訊息的派發器和訂閱器之間進行資料傳輸

注意:為了迎合描述的需要,在下文中可能會混用事件和訊息兩個概念。

一個簡單的設計

先從簡單的設計開始,基本上事件驅動型架構會有事件訊息(Events)、事件訂閱器(Event Subscriber)、事件派發器(Event Publisher)、事件處理器(Event Handler)以及事件匯流排(Event Bus)等主要元件,它們之間的關係大致如下:

0?wx_fmt=png

首先,IEvent介面定義了事件訊息(更確切地說,資料)的基本結構,幾乎所有的事件都會有一個唯一識別符號(Id)和一個事件發生的時間(Timestamp),這個時間通常使用UTC時間作為標準。IEventHandler定義了事件處理器介面,顯而易見,它包含兩個方法:CanHandle方法,用以確定傳入的事件物件是否可被當前處理器所處理,以及Handle方法,它定義了事件的處理過程。IEvent和IEventHandler構成了事件處理的基本元素。

然後就是IEventSubscriber與IEventPublisher介面。前者表示實現該介面的型別為事件訂閱器,它負責事件處理器的註冊,並偵聽來自事件通訊渠道上的訊息,一旦所獲得的訊息能夠被某個處理器處理,它就會指派該處理器對接收到的訊息進行處理。因此,IEventSubscriber會保持著對事件處理器的引用;而對於實現了IEventPublisher介面的事件派發器而言,它的主要任務就是將事件訊息傳送到訊息通訊渠道,以便訂閱端能夠獲得訊息並進行處理。

IEventBus介面表示訊息通訊渠道,也就是大家所熟知的訊息匯流排的概念。它不僅具有訊息訂閱的功能,而且還具有訊息派發的能力,因此,它會同時繼承於IEventSubscriber和IEventPublisher介面。在上面的設計中,通過介面分離訊息匯流排的訂閱器和派發器的角色是很有必要的,因為兩種角色的各自職責不一樣,這樣的設計同時滿足SOLID中的SRP和ISP兩個準則。

基於以上基礎模型,我們可以很快地將這個物件關係模型轉換為C#程式碼:

public interface IEvent{Guid Id { get; }DateTime Timestamp { get; }}public interface IEventHandler{Task<bool> HandleAsync(IEvent @event, CancellationToken cancellationToken = default);bool CanHandle(IEvent @event);}public interface IEventHandler<in T> : IEventHandlerwhere T : IEvent{Task<bool> HandleAsync(T @event, CancellationToken cancellationToken = default);}public interface IEventPublisher : IDisposable{Task PublishAsync<TEvent>(TEvent @event, CancellationToken cancellationToken = default)where TEvent : IEvent;}public interface IEventSubscriber : IDisposable{void Subscribe();}public interface IEventBus : IEventPublisher, IEventSubscriber { }

短短30行程式碼,就把我們的基本物件關係描述清楚了。對於上面的程式碼我們需要注意以下幾點:

  1. 這段程式碼使用了C# 7.1的新特性(default關鍵字)

  2. Publish以及Handle方法被替換為支援非同步呼叫的PublishAsync和HandleAsync方法,它們會返回Task物件,這樣可以方便使用C#中async/await的程式設計模型

  3. 由於我們的這個模型可以作為實現訊息系統的通用模型,並且會需要用到ASP.NET Core的專案中,因此,建議將這些介面的定義放在一個獨立的NetStandard的Class Library中,方便今後重用和擴充套件

OK,介面定義好了。實現呢?下面,我們實現一個非常簡單的訊息匯流排:PassThroughEventBus。在今後的文章中,我還會介紹如何基於RabbitMQ和Azure Service Bus實現不一樣的訊息匯流排。

PassThroughEventBus

顧名思義,PassThroughEventBus表示當有訊息被派發到訊息匯流排時,訊息匯流排將不做任何處理與路由,而是直接將訊息推送到訂閱方。在訂閱方的事件監聽函式中,會通過已經註冊的事件處理器對接收到的訊息進行處理。整個過程並不會依賴於任何外部元件,不需要引用額外的開發庫,只是利用現有的.NET資料結構來模擬訊息的派發和訂閱過程。因此,PassThroughEventBus不具備容錯和訊息重發功能,不具備訊息儲存和路由功能,我們先實現這樣一個簡單的訊息匯流排,來體驗事件驅動型架構的設計過程。

我們可以使用.NET中的Queue或者ConcurrentQueue等基本資料結構來作為訊息佇列的實現,與這些基本的資料結構相比,訊息佇列本身有它自己的職責,它需要在訊息被推送進佇列的同時通知呼叫方。當然,PassThroughEventBus不需要依賴於Queue或者ConcurrentQueue,它所要做的事情就是模擬一個訊息佇列,當訊息推送進來的時候,立刻通知訂閱方進行處理。同樣,為了分離職責,我們可以引入一個EventQueue的實現(如下),從而將訊息推送和路由的職責(基礎結構層的職責)從訊息匯流排中分離出來。

?

12345678910111213internal sealed class EventQueue{public event System.EventHandler<EventProcessedEventArgs> EventPushed;public EventQueue() { }public void Push(IEvent @event){OnMessagePushed(new EventProcessedEventArgs(@event));}private void OnMessagePushed(EventProcessedEventArgs e) => this.EventPushed?.Invoke(this, e);}

EventQueue中最主要的方法就是Push方法,從上面的程式碼可以看到,當EventQueue的Push方法被呼叫時,它將立刻觸發EventPushed事件,它是一個.NET事件,用以通知EventQueue物件的訂閱者,訊息已經被派發。整個EventQueue的實現非常簡單,我們僅專注於事件的路由,完全沒有考慮任何額外的事情。

接下來,就是利用EventQueue來實現PassThroughEventBus。毫無懸念,PassThroughEventBus需要實現IEventBus介面,它的兩個基本操作分別是Publish和Subscribe。在Publish方法中,會將傳入的事件訊息轉發到EventQueue上,而Subscribe方法則會訂閱EventQueue.EventPushed事件(.NET事件),而在EventPushed事件處理過程中,會從所有已註冊的事件處理器(Event Handlers)中找到能夠處理所接收到的事件,並對其進行處理。整個流程還是非常清晰的。以下便是PassThroughEventBus的實現程式碼:

?

12345678910111213141516171819202122232425262728293031323334353637383940public sealed class PassThroughEventBus : IEventBus{private readonly EventQueue eventQueue = new EventQueue();private readonly IEnumerable<IEventHandler> eventHandlers;public PassThroughEventBus(IEnumerable<IEventHandler> eventHandlers){this.eventHandlers = eventHandlers;}private void EventQueue_EventPushed(object sender, EventProcessedEventArgs e)=> (from eh in this.eventHandlerswhere eh.CanHandle(e.Event)select eh).ToList().ForEach(async eh => await eh.HandleAsync(e.Event));public Task PublishAsync<TEvent>(TEvent @event, CancellationToken cancellationToken = default)where TEvent : IEvent=> Task.Factory.StartNew(() => eventQueue.Push(@event));public void Subscribe()=> eventQueue.EventPushed += EventQueue_EventPushed;#region IDisposable Supportprivate bool disposedValue = false; // To detect redundant callsvoid Dispose(bool disposing){if (!disposedValue){if (disposing){this.eventQueue.EventPushed -= EventQueue_EventPushed;}disposedValue = true;}}public void Dispose() => Dispose(true);#endregion}

實現過程非常簡單,當然,從這些程式碼也可以更清楚地瞭解到,PassThroughEventBus不做任何路由處理,更不會依賴於一個基礎結構設施(比如實現了AMQP的訊息佇列),因此,不要指望能夠在生產環境中使用它。不過,目前來看,它對於我們接下來要討論的事情還是會很有幫助的,至少在我們引入基於RabbitMQ等實現的訊息匯流排之前。

同樣地,請將PassThroughEventBus實現在另一個NetStandard的Class Library中,雖然它不需要額外的依賴,但它畢竟是眾多訊息匯流排中的一種,將它從介面定義的程式集中剝離開來,好處有兩點:第一,保證了定義介面的程式集的純淨度,使得該程式集不需要依賴任何外部元件,並確保了該程式集的職責單一性,即為訊息系統的實現提供基礎類庫;第二,將PassThroughEventBus置於獨立的程式集中,有利於呼叫方針對IEventBus進行技術選擇,比如,如果開發者選擇使用基於RabbitMQ的實現,那麼,只需要引用基於RabbitMQ實現IEventBus介面的程式集就可以了,而無需引用包含了PassThroughEventBus的程式集。這一點我覺得可以歸納為框架設計中“隔離依賴關係(Dependency Segregation)”的準則。

好了,基本元件都定義好了,接下來,讓我們一起基於ASP.NET Core Web API來做一個RESTful服務,並接入上面的訊息匯流排機制,實現訊息的派發和訂閱。

Customer RESTful API

我們仍然以客戶管理的RESTful API為例子,不過,我們不會過多地討論如何去實現管理客戶資訊的RESTful服務,那並不是本文的重點。作為一個案例,我使用ASP.NET Core 2.0 Web API建立了這個服務,使用Visual Studio 2017 15.5做開發,並在CustomersController中使用Dapper來對客戶資訊CRUD。後臺基於SQL Server 2017 Express Edition,使用SQL Server Management Studio能夠讓我方便地檢視資料庫操作的結果。

RESTful API的實現

假設我們的客戶資訊只包含客戶ID和名稱,下面的CustomersController程式碼展示了我們的RESTful服務是如何儲存並讀取客戶資訊的。當然,我已經將本文的程式碼通過Github開源,開源協議為MIT,雖然商業友好,但畢竟是案例程式碼沒有經過測試,所以請謹慎使用。本文原始碼的使用我會在文末介紹。

?

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950[Route("api/[controller]")]public class CustomersController : Controller{private readonly IConfiguration configuration;private readonly string connectionString;public CustomersController(IConfiguration configuration){this.configuration = configuration;this.connectionString = configuration["mssql:connectionString"];}// 獲取指定ID的客戶資訊[HttpGet("{id}")]public async Task<IActionResult> Get(Guid id){const string sql = "SELECT [CustomerId] AS Id, [CustomerName] AS Name FROM [dbo].[Customers] WHERE [CustomerId][email protected]";using (var connection = new SqlConnection(connectionString)){var customer = await connection.QueryFirstOrDefaultAsync<Model.Customer>(sql, new { id });if (customer == null){return NotFound();}return Ok(customer);}}// 建立新的客戶資訊[HttpPost]public async Task<IActionResult> Create([FromBody] dynamic model){var name = (string)model.Name;if (string.IsNullOrEmpty(name)){return BadRequest();}const string sql = "INSERT INTO [dbo].[Customers] ([CustomerId], [CustomerName]) VALUES (@Id, @Name)";using (var connection = new SqlConnection(connectionString)){var customer = new Model.Customer(name);await connection.ExecuteAsync(sql, customer);return Created(Url.Action("Get", new { id = customer.Id }), customer.Id);}}}

程式碼一如既往的簡單,Web API控制器通過Dapper簡單地實現了客戶資訊的建立和返回。我們不妨測試一下,使用下面的Invoke-RestMethod PowerShell指令,傳送Post請求,通過上面的Create方法建立一個使用者:

0?wx_fmt=png

可以看到,response中已經返回了新建客戶的ID號。接下來,繼續使用Invoke-RestMethod來獲取新建客戶的詳細資訊:

0?wx_fmt=png

OK,API除錯完全沒有問題。下面,我們將這個案例再擴充一下,我們希望這個API在完成客戶資訊建立的同時,向外界傳送一條“客戶資訊已建立”的事件,並設定一個事件處理器,負責將該事件的詳細內容儲存到資料庫中。

加入事件匯流排和訊息處理機制

首先,我們在ASP.NET Core Web API專案上,新增對以上兩個程式集的引用,然後,按常規做法,在ConfigureServices方法中,將PassThroughEventBus新增到IoC容器中:

?

12345public void ConfigureServices(IServiceCollection services){services.AddMvc();services.AddSingleton<IEventBus, PassThroughEventBus>();}

在此,將事件匯流排註冊為單例(Singleton)服務,是因為它不儲存狀態。理論上講,使用單例服務時,需要特別注意服務例項物件的生命週期管理,因為它的生命週期是整個應用程式級別,在程式執行的過程中,由其引用的物件資源將無法釋放,因此,當程式結束執行時,需要合理地將這些資源dispose掉。好在ASP.NET Core的依賴注入框架中已經幫我們處理過了,因此,對於上面的PassThroughEventBus單例註冊,我們不需要過多擔心,程式執行結束並正常退出時,依賴注入框架會自動幫我們dispose掉PassThroughEventBus的單例例項。那麼對於單例例項來說,我們是否只需要通過AddSingleton方法進行註冊就可以了,而無需關注它是否真的被dispose了呢?答案是否定的,有興趣的讀者可以參考微軟的官方文件,在下一篇文章中我會對這部分內容做些介紹。

接下來,我們需要定義一個CustomerCreatedEvent物件,表示“客戶資訊已經建立”這一事件資訊,同時,再定義一個CustomerCreatedEventHandler事件處理器,用來處理從PassThroughEventBus接收到的事件訊息。程式碼如下,當然也很簡單:

?

1234567891011121314151617181920212223242526272829public class CustomerCreatedEvent : IEvent{public CustomerCreatedEvent(string customerName){this.Id = Guid.NewGuid();this.Timestamp = DateTime.UtcNow;this.CustomerName = customerName;}public Guid Id { get; }public DateTime Timestamp { get; }public string CustomerName { get; }}public class CustomerCreatedEventHandler : IEventHandler<CustomerCreatedEvent>{public bool CanHandle(IEvent @event)=> @event.GetType().Equals(typeof(CustomerCreatedEvent));public Task<bool> HandleAsync(CustomerCreatedEvent @event, CancellationToken cancellationToken = default){return Task.FromResult(true);public Task<bool> HandleAsync(IEvent @event, CancellationToken cancellationToken = default)=> CanHandle(@event) ? HandleAsync((CustomerCreatedEvent)@event, cancellationToken) : Task.FromResult(false);}

兩者分別實現了我們最開始定義好的IEvent和IEventHandler介面。在CustomerCreatedEventHandler類的第一個HandleAsync過載方法中,我們暫且讓它簡單地返回一個true值,表示事件處理成功。下面要做的事情就是,在客戶資訊建立成功後,向事件匯流排傳送CustomerCreatedEvent事件,以及在ASP.NET Core Web API程式啟動的時候,註冊CustomerCreatedEventHandler例項,並呼叫事件匯流排的Subscribe方法,使其開始偵聽事件的派發行為。

於是,CustomerController需要依賴IEventBus,並且在CustomerController.Create方法中,需要通過呼叫IEventBus的Publish方法將事件傳送出去。現對CustomerController的實現做一些調整,調整後代碼如下:

?

123456789101112131415161718192021222324252627282930313233343536373839[Route("api/[controller]")]public class CustomersController : Controller{private readonly IConfiguration configuration;private readonly string connectionString;private readonly IEventBus eventBus;public CustomersController(IConfiguration configuration,IEventBus eventBus){this.configuration = configuration;this.connectionString = configuration["mssql:connectionString"];this.eventBus = eventBus;}// 建立新的客戶資訊[HttpPost]public async Task<IActionResult> Create([FromBody] dynamic model){var name = (string)model.Name;if (string.IsNullOrEmpty(name)){return BadRequest();}const string sql = "INSERT INTO [dbo].[Customers] ([CustomerId], [CustomerName]) VALUES (@Id, @Name)";using (var connection = new SqlConnection(connectionString)){var customer = new Model.Customer(name);await connection.ExecuteAsync(sql, customer);await this.eventBus.PublishAsync(new CustomerCreatedEvent(name));return Created(Url.Action("Get", new { id = customer.Id }), customer.Id);}}// Get方法暫且省略}

然後,修改Startup.cs中的ConfigureServices方法,將CustomerCreatedEventHandler註冊進來:

?

1234567public void ConfigureServices(IServiceCollection services){services.AddMvc();services.AddTransient<IEventHandler, CustomerCreatedEventHandler>();services.AddSingleton<IEventBus, PassThroughEventBus>();}

並且呼叫Subscribe方法,開始偵聽訊息匯流排:

?

123456789101112public void Configure(IApplicationBuilder app, IHostingEnvironment env){var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();eventBus.Subscribe();if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseMvc();}

OK,現在讓我們在CustomerCreatedEventHandler的HandleAsync方法上設定個斷點,按下F5啟用Visual Studio 2017除錯,然後重新使用Invoke-RestMethod命令傳送一個Post請求,可以看到,HandleAsync方法上的斷點被命中,同時事件已被正確派發:

0?wx_fmt=png

資料庫中的資料也被正確更新:

0?wx_fmt=png

目前還差最後一小步,就是在HandleAsync中,將CustomerCreatedEvent物件的資料序列化並儲存到資料庫中。當然這也不難,同樣可以考慮使用Dapper,或者直接使用ADO.NET,甚至使用比較重量級的Entity Framework Core,都可以實現。那就在此將這個問題留給感興趣的讀者朋友自己搞定啦。

小結

到這裡基本上本文的內容也就告一段落了,回顧一下,本文一開始就提出了一種相對簡單的訊息系統和事件驅動型架構的設計模型,並實現了一個最簡單的事件匯流排:PassThroughEventBus。隨後,結合一個實際的ASP.NET Core Web API案例,瞭解了在RESTful API中實現事件訊息派發和訂閱的過程,並實現了在事件處理器中,對獲得的事件訊息進行處理。

然而,我們還有很多問題需要更深入地思考,比如:

  • 如果事件處理器需要依賴基礎結構層元件,依賴關係如何管理?元件生命週期如何管理?

  • 如何實現基於RabbitMQ或者Azure Service Bus的事件匯流排?

  • 如果在資料庫更新成功後,事件傳送失敗怎麼辦?

  • 如何保證事件處理的順序?

等等。。。在接下來的文章中,我會盡力做更詳細的介紹。

原始碼的使用

本系列文章的原始碼在https://github.com/daxnet/edasample這個Github Repo裡,通過不同的release tag來區分針對不同章節的原始碼。本文的原始碼請參考chapter_1這個tag,如下:

0?wx_fmt=png

接下來還將會有chapter_2、chapter_3等這些tag,對應本系列文章的第二部分、第三部分等等。敬請期待。

原文地址:http://www.cnblogs.com/daxnet/p/8082694.html

.NET社群新聞,深度好文,歡迎訪問公眾號文章彙總 http://www.csharpkit.com

640?wx_fmt=jpeg

相關推薦

ASP.NET Core Web API事件驅動架構實現一個簡單實現

很長一段時間以來,我都在思考如何在ASP.NET Core的框架下,實現一套完整的事件驅動型架構

Azure AD呼叫受Microsoft 標識平臺保護的 ASP.NET Core Web API

一,引言   上一節講到如何在我們的專案中整合Azure AD 保護我們的API資源,以及在專案中整合Swagger,並且如何把Swagger作為一個客戶端進行認證和授權去訪問我們的WebApi資源的?本節就接著講如何在我們的專案中整合 Azure AD 保護我們的API資源,使用其他幾種授權模式進行授權認證

Asp.net core 2.0.1 Razor 的使用學習筆記

提升 完成後 安全 provider razor 官方 one text .cn 環境:vs2017 版本:15.5.6 這裏說明下, Razor頁面模式跟mvc出現了嚴重的不同。正如微軟官方說的一樣“Razor 頁面是 ASP.NET Core MVC 的一

ASP.NET Core Web API 專案裡無法訪問wwwroot的檔案

解決辦法:在“ Startup.cs ” 檔案裡的 Configur方法裡新增一句程式碼“ app.UseStaticFiles() ”,這樣就可以訪問wwwroot下的檔案了。 - 方法程式碼是

ASP.NET Core Web API 最小化項目

asp新建項目打開VS2017 新建一個ASP.NET Core 應用程序 (.NET Core)項目,命名為miniwebapi。確定後選擇Web API 模板,並將“身份驗證”設置為“不進行身份驗證”。然後確定就創建好了項目,默認項目的csproj 文件內容如下:<Project Sdk="Micr

品嘗阿裏雲容器服務初步嘗試ASP.NET Core Web API站點的Docker自動化部署

asp.net title build 阿裏雲服務器 arm web 容器服務 倉庫 acs 部署場景是這樣的,我們基於 ASP.NET Core 2.0 Preview 1 開發了一個用於管理緩存的 Web API ,想通過阿裏雲容器服務基於 Docker 部署為內網服務

使用 Swagger 自動生成 ASP.NET Core Web API 的文檔、在線幫助測試文檔ASP.NET Core Web API 自動生成文檔

地址 .cn 名稱 cor 生成文檔 def pos 構建 回車 對於開發人員來說,構建一個消費應用程序時去了解各種各樣的 API 是一個巨大的挑戰。在你的 Web API 項目中使用 Swagger 的 .NET Core 封裝 Swashbuckle 可以幫助你創建良好

如何在ASP.NET Core Web API測試中使用Postman

e30 googl 選項卡 for 並運行 讓我 結合 pos lis 使用Postman進行手動測試 如果您是開發人員,測試人員或管理人員,則在構建和使用應用程序時,有時了解各種API方法可能是一個挑戰。 使用帶有.NET Core的Postman為您的Web API生

ASP.NET CORE WEB API DEMO 01

dsi del turn adr arch pda host result arc using System; using System.Collections.Concurrent; using System.Collections.Generic; namespac

ASP.NET Core Web API實現圖片下載

前端訪問下載圖片API下載圖片。 一、ASP.NET Core Web API程式碼 方案一: [Route("api/[controller]")] [ApiController

ASP.NET Core 實戰使用 ASP.NET Core Web API 和 Vue.js,搭建前後端分離框架

前言         這幾年前端的發展速度就像坐上了火箭,各種的框架一個接一個的出現,需要學習的東西越來越多,分工也越來越細,作為一個 .NET Web 程式猿,多瞭解瞭解行業的發展,讓自己擴展出新的技能樹,對自己的職業發展還是

Asp.Net Core Web Api圖片上傳()整合MongoDB儲存例項教程

Asp.Net Core Web Api圖片上傳及MongoDB儲存例項教程(一) 圖片或者檔案上傳相信大家在開發中應該都會用到吧,有的時候還要對圖片生成縮圖。那麼如何在Asp.Net Core Web Api實現圖片上傳儲存以及生成縮圖呢?今天我就使用MongoDB作為圖片儲存,然後使用SixLabors

加速ASP.NET Core WEB API應用程式——第2部分

目錄 應用程式生產力 非同步設計模式 資料規範化與SQL查詢效率 NCHAR與NVARCHAR 使用MSSQL伺服器的全文引擎 儲存過程 優化儲存過程 預編譯和重用儲存過程執行計劃 使用Entity Framework Core進行全文搜尋 Entity

加速ASP.NET Core WEB API應用程式——第1部分

目錄 介紹 建立測試RESTful WEB API服務 應用程式架構 資料庫 建立ASP.NET核心WEB API應用程式 使用實體框架核心進行資料庫訪問 非同步設計模式 儲存庫 儲存庫實現 服務 服務介面 服務的實現 產品和價格表之間的資料完

【譯】使用Jwt身份認證保護 Asp Net Core Web Api

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

ASP.NET Core Web API 索引 (更新ASPNET Core和EF Core視訊)

GraphQL [視訊] 使用ASP.NET Core 開發 GraphQL 伺服器  GraphQL其它 RESTful API Identity Server 4 Identity Server 4 - Hybrid Flow ASP.NET Core

ASP.NET Core Web API 整合測試中使用 Bearer Token

在 ASP.NET Core Web API 整合測試一文中, 我介紹了ASP.NET Core Web API的整合測試.  在那裡我使用了測試專用的Startup類, 裡面的配置和開發時有一些區別, 例如裡面去掉了使用者身份驗證相關的中介軟體. 但是有些被測試的行為裡面需要用到身份/授權資訊. 所以

ASP.NET Core Web API 整合測試

本文需要您瞭解ASP.NET Core Web API 和 xUnit的相關知識. 整合測試 vs 單元測試 測試金字塔, 但它只是一個指導性的概念. 如果所單元測試是對一個元件進行隔離測試的話, 那麼整合測試則是測試多個元件共同協作產生出期待的結果. 單元測試通常很快. 而整合測試則

Gitlab CI 自動部署 asp.net core web api 到Docker容器

然後可以到官網下載net core 1.1 on MacOS,完成之後可以在命令列輸入 dotnet --version 來檢測當前的版本。 初始化專案並執行 通過3個命領我們可以完成初始化專案並執行的全過程: dotnet new|restore|run。 dotnet 框架預設提供一些初始化的專案模板,

支援多個版本的ASP.NET Core Web API

基本配置及說明 版本控制有助於及時推出功能,而不會破壞現有系統。 它還可以幫助為選定的客戶提供額外的功能。 API版本可以通過不同的方式完成,例如在URL中新增版本或通過自定義標頭和通過Accept-Header作為查詢字串引數。 在這篇文章中,我們來看看如何支援多版本的A