.NET Core MVC扩展实践
源寶導讀:明源云ERP的底層架構正在向.Net Core跨平臺遷移,我們在過程中遇到了部分不兼容的問題。本文將介紹技術團隊如何解決.Net Core與已有MVC框架不兼容問題的解決方案。
一、背景
? ? 云ERP的建模平臺是基于.NET Framework構建的,在向.NET Core遷移的過程中會遇到各種問題,向下兼容是一定要考慮的,框架本身的特性兼容交給微軟,但是還有很多的特性可能是舊版建模平臺需要支持的特性,比如多參數綁定、服務工廠Controller激活。今天就聊聊在向.NET Core遷移時如何兼容以上兩個特性。
二、概念解釋
服務工廠
云ERP的服務工廠是建模平臺的內部服務管理實現,用于創建ERP各個領域服務類實例,在創建服務對象的過程中會進行加工,根據二開模式(Before/After/Override)動態創建攜帶插件方法的代理類型,以達到易二開的技術特性。
應用服務
應用服務是云ERP的入口,它們是由一系列后綴名為AppService的Class組成的,概念上相當于MVC的Controller,作用也一樣。
自定義路由
云ERP的路由中添加了命名空間地址,官方的模板格式無法滿足,本文利用ControllerModelConvention在Apply時為每一個Action批量配置路由。路由格式:?`api/ {controller.ControllerType.FullName} /{action.ActionName}.aspx`
Controller激活
云ERP也是基于MVC構建的,Controller也是服務,也是需要可擴展,自然需要通過服務工廠去創建,這就需要找到.NET Core MVC中Controller激活的時機,使用服務工廠創建替換掉默認的類實例化過程。
多參數綁定
.NET Core MVC 中天生是不支持將[FromBody]數據源綁定到Action的多個參數上的。這一特性在微軟官方文檔中有解釋(參考:微軟對FromBody的參數綁定限制說明)。由于這個限制,我們必須在向.NET Core MVC遷移時嘗試解決這個問題,思路與Controller激活的差不多,就是找到參數綁定的默認實現,替換掉它。
為了大家能統一語言,請提前了解下.NET Core MVC的基本特性,這里就不再闡述,需要了解的讀者請點擊傳送門。
三、面臨的問題
讓MVC路由到云ERP的AppService
? ? .NET Framework MVC 升級到 .NET Core MVC 在實現原理上有很大不同,由服務管線變成了中間件管道,無法直接使用HttpHandler實現了,必須重新實現Controller路由到激活的過程。
? ? 那么將面臨兩個問題:
自定義路由,首先要能讓MVC認知AppService并能按照云ERP的模板規范進行路由。
路由到AppService后激活的方式得用服務工廠 ServiceFactory來創建,這樣才能兼容二開的插件模式。(注:服務工廠中創建的是AppService的代理類的實例,攜帶二開定義的插件方法)
支撐多參數綁定
? ?云ERP多參數綁定的解決方案是利用的ClownFish.net框架中的? ClownFish. Web.Serializer. JsonnetDataProvider 來解決的(ClownFish.net明源云的架構師FishLi多年前的作品,已在Github上開源)。
? ? 遷移到.NET Core MVC中就需要自己實現了,原理差不多,這里不多講有興趣的可以看源碼。
四、解決思路
要在.NETCore MVC中兼容云ERP的MVC特性,核心要解決的就是以下三點:
自定義路由。
controller激活。
多參數綁定。
我們一個一個來解決。
自定義路由
? ? 首先我們得讓MVC認識AppService,不然無法做后面的事情。創建一個 AppServiceFeatureProvider 繼承 ControllerFeatureProvider 用來將AppService提供給MVC框架作為控制器使用。并且將AppServiceFeatureProvider提供程序加入MVC的特性提供者集合中。最后在 ConfigureServices 中調用 AddClownFish()。
? ? 接下來,就是要給每一個AppService的方法(Action)設置自定義路由。這里利用的是.NET Core MVC的一個Convention 特性,不了解的讀者先閱讀一下微軟文檔。
(https://docs.microsoft.com/zh-cn/aspnet/core/mvc/controllers/application-model?view=aspnetcore-3.0#conventions)。
? ? 創建一個 AppServiceModelConvention 類型 實現 IControllerModelConvention的Apply 接口。為ControllerModel的每一個Action創建屬性路由(AttributeRouteModel),代碼如下,為了保證理解容易,我隱藏了部分不重要的代碼,文末有Demo源代碼鏈接可以下載。在AddClownFish擴展方法中把AppServiceModelConvention加如MVC的約定列表。
Controller激活
所以分解任務就是:
創建 ClownFishControllerActivator 替換默認的Controller激活器實現
實現ERP自定義的激活器,用服務工廠創建AppService實例
把ClownFishControllerActivator加入服務列表中
代碼比較簡單:
? ? 這里值得一提的是,微軟在MVC框架中確實實現了一個默認的激活器實現,但是如果你不去主動使用它,默認他是不使用的,會跳過。避免被坑,我截圖說明了一下:
多參數綁定
? ? 多參數綁定實現起來比較費勁,主要是因為參數綁定的過程是封閉的,這里利用了篡改緩存的實現,用自定義的Lambad表達式構建了一個新的實例來替換掉默認的實現。
思路:
實現 IActionInvokerProvider 替換掉默認實現。
在Action執行時構建一個自定義的Bind函數替換掉緩存中的Bind函數,返回一個新的緩存對象。
自定義的Bind函數中就可以拿到HttpContext了,這樣就可以為所欲為了,自己創建一個JsonTextReader來自由讀取Body然后依次綁定到Controller的arguments列表中。
然后把新的緩存對象塞回緩存字典中。
代碼如下:
四、總結
? ? 閱讀官方文檔發現 .NET Core MVC提供了豐富的擴展機制,這為上層框架的發展提供了可能,通過閱讀MVC源碼可以學習微軟程序員的代碼設計思想,思考并提煉應用到ERP的產品代碼設計中,這也是開源的一種福利吧。
最后附上Demo源碼地址:
https://github.com/zongzijie/study/tree/master/CSharp/SampleForAspNetCoreMvc
------ END ------
作者簡介
伍同學:?研發工程師,目前負責售樓系統的相關設計開發工作。
也許您還想看
ERP緩存實踐經驗分享
.Net最小工作線程對應用程序性能的影響
記一次生產環境CPU100%排查實踐
如何使用有序GUID提升數據庫讀寫性能
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的.NET Core MVC扩展实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【复杂系统迁移 .NET Core平台系
- 下一篇: 成本计算引擎动态规则解析技术详解