ASP.NET Core 3.0中使用動態控制器路由

原文:Dynamic controller routing in ASP.NET Core 3.0
作者:Filip W
譯文:https://www.cnblogs.com/lwqlun/p/11461657.html
譯者:Lamond Lu

65831-20190904214946373-1517921684.jpg

譯者注

今天在網上看到了這篇關于ASP.NET Core動態路由的文章,感覺蠻有意思的,給大家翻譯一下,雖然文中的例子不一定會在日常編碼中出現,但是也給我們提供了一定的思路。

前言

相對于ASP.NET MVC以及ASP.NET Core MVC中的舊版本路由特性, 在ASP.NET Core 3.0中新增了一個不錯的擴展點,即程序獲取到路由后,可以將其動態指向一個給定的controller/action.

這個功能有非常多的使用場景。如果你正在使用從ASP.NET Core 3.0 Preview 7及更高版本,你就可以在ASP.NET Core 3.0中使用它了。

PS: 官方沒有在Release Notes中提到這一點。

下面就讓我們一起來看一看ASP.NET Core 3.0中的動態路由。

背景

當我們使用MVC路由的時候,最典型的用法是,我們使用路由特性(Route Attributes)來定義路由信息。使用這種方法,我們需要要為每個路由進行顯式的聲明。

public class HomeController : Controller
{[Route("")][Route("Home")][Route("Home/Index")]public IActionResult Index(){return View();}
}

相對的,你可以使用中心化的路由模型,使用這種方式,你就不需要顯式的聲明每一個路由 - 這些路由會自動被所有發現的控制器的自動識別。 然而,這樣做的前提是,所有的控制器首先必須存在。

以下是ASP.NET Core 3.0中使用新語法Endpoint Routing的實現方式。

app.UseEndpoints(endpoints =>{endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");}
);

以上兩種方式的共同點是,所有的路由信息都必須在應用程序啟動時加載。

但是,如果你希望能夠動態定義路由, 并在應用程序運行時添加/刪除它們,該怎么辦?

下面我給大家列舉幾個動態定義路由的使用場景。

  • 多語言路由,以及使用新語言時,針對那些新語言路由的修改。
  • 在CMS類型的系統中,我們可能會動態添加一些新頁面,這些新頁面不需要創建的控制器或者在源碼中硬編碼路由信息。
  • 多租戶應用中,租戶路由可以在運行時動態激活或者取消激活。

這個問題的處理過程應該相當的好理解。我們希望盡早的攔截路由處理,檢查已為其解析的當前路由值,并使用例如數據庫中的數據將它們“轉換”為一組新的路由值,這些新的路由值指向了一個實際存在的控制器。

實例問題 - 多語言翻譯路由問題

在舊版本的ASP.NET Core MVC中, 我們通常通過自定義IRouter接口,來解決這個問題。然而在ASP.NET Core 3.0中這種方式已經行不通了,因為路由已經改由上面提到的Endpoint Routing來處理。值得慶幸的是,ASP.NET Core 3.0 Preview 7以及后續版本中,我們可以通過一個新特性MapDynamicControllRoute以及一個擴展點DynamicRouteValueTransformer, 來支持我們的需求。下面讓我們看一個具體的例子。

想象一下,在你的項目中,有一個OrderController控制器,然后你希望它支持多語言翻譯路由。

public class OrdersController : Controller
{public IActionResult List(){return View();}
}

我們可能希望的請求的URL是這樣的,例如

  • 英語 - /en/orders/list
  • 德語 - /de/bestellungen/liste
  • 波蘭語 - /pl/zamowienia/lista

使用動態路由處理多語言翻譯路由問題

那么我們現在該如何解決這個問題呢?我們可以使用新特性MapDynamicControllerRoute來替代默認的MVC路由, 并將其指向我們自定義的DynamicRouteValueTransformer類, 該類實現了我們之前提到的路由值轉換 。

public class Startup
{public void ConfigureServices(IServiceCollection services){services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Latest);services.AddSingleton<TranslationTransformer>();services.AddSingleton<TranslationDatabase>();}public void Configure(IApplicationBuilder app){app.UseRouting();app.UseEndpoints(endpoints =>{endpoints.MapDynamicControllerRoute<TranslationTransformer>("{language}/{controller}/{action}");});}
}

這里我們定義了一個TranslationTransformer類,它繼承了DynamicRouteValueTransformer類。這個新類將負責將特定語言路由值,轉換為可以在我們應用可以匹配到controller/action的路由值字典,而這些值通常不能直接和我們應用中的任何controller/action匹配。所以這里簡單點說,就是在德語場景下,controller名會從“Bestellungen”轉換成"Orders", action名"Liste"轉換成"List"。

TranslationTransformer類被作為泛型類型參數,傳入MapDynamicControllerRoute方法中,它必須在依賴注入容器中注冊。這里,我們還需要注冊一個TranslationDatabase類,但是這個類僅僅為了幫助演示,后面我們會需要它。

public class TranslationTransformer : DynamicRouteValueTransformer
{private readonly TranslationDatabase _translationDatabase;public TranslationTransformer(TranslationDatabase translationDatabase){_translationDatabase = translationDatabase;}public override async ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values){if (!values.ContainsKey("language") || !values.ContainsKey("controller") || !values.ContainsKey("action")) return values;var language = (string)values["language"];var controller = await _translationDatabase.Resolve(language, (string)values["controller"]);if (controller == null) return values;values["controller"] = controller;var action = await _translationDatabase.Resolve(language, (string)values["action"]);if (action == null) return values;values["action"] = action;return values;}
}

在這個轉換器中,我們需要嘗試提取3個路由參數, language, controller,action,然后我們需要在模擬用的數據庫類中,找到其對應的翻譯。正如我們之前提到的,你通常會希望從數據庫中查找對應的內容,因為使用這種方式,我們可以在應用程序生命周期的任何時刻,動態的影響路由。為了說明這一點,我們將使用TranslationDatabase類來模擬數據庫操作,這里你可以把它想象成一個真正的數據庫倉儲服務。

public class TranslationDatabase
{private static Dictionary<string, Dictionary<string, string>> Translations = new Dictionary<string, Dictionary<string, string>>{{"en", new Dictionary<string, string>{{ "orders", "orders" },{ "list", "list" }}},{"de", new Dictionary<string, string>{{ "bestellungen", "orders" },{ "liste", "list" }}},{"pl", new Dictionary<string, string>{{ "zamowienia", "order" },{ "lista", "list" }}},};public async Task<string> Resolve(string lang, string value){var normalizedLang = lang.ToLowerInvariant();var normalizedValue = value.ToLowerInvariant();if (Translations.ContainsKey(normalizedLang) && Translations[normalizedLang].ContainsKey(normalizedValue)){return Translations[normalizedLang][normalizedValue];}return null;}
}

到目前為止,我們已經很好的解決了這個問題。這里通過在MVC應用中啟用這個設置,我們就可以向我們之前定義的3個路由發送請求了。

  • 英語 - /en/orders/list
  • 德語 - /de/bestellungen/liste
  • 波蘭語 - /pl/zamowienia/lista

每個請求都會命中OrderController控制器和List方法。當前你可以將這個方法進一步擴展到其他的控制器。但最重要的是,如果新增一種新語言或者新的路由別名映射到現有語言中的controller/actions,你是不需要做任何代碼更改,甚至重啟項目的。

請注意,在本文中,我們只關注路由轉換,這里僅僅是為了演示ASP.NET Core 3.0中的動態路由特性。如果你希望在應用程序中實現本地化,你可能還需要閱讀ASP.NET Core 3.0的本地化指南, 因為你可以需要根據語言的路由值設置正確的CurrentCulture

最后, 我還想再補充一點,在我們之前的例子中,我們在路由模板中顯式的使用了{controller}{action}占位符。這并不是必須的,在其他場景中,你還可以使用"catch-all"路由通配符,并將其轉換為controller/action路由值。

"catch-all"路由通配符是CMS系統中的典型解決方案,你可以使用它來處理不同的動態“頁面”路由。

它看起來可能類似:

endpoints.MapDynamicControllerRoute<PageTransformer>("pages/{**slug}");

然后,你需要將pages之后的整個URL參數轉換為現有可執行控制器的內容 - 通常URL/路由的映射是保存在數據庫中的。

希望你會發現這篇文章很有用 - 所有的演示源代碼都可以在Github上找到。

轉載于:https://www.cnblogs.com/lwqlun/p/11461657.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/248161.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/248161.shtml
英文地址,請注明出處:http://en.pswp.cn/news/248161.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Petrozavodsk Winter Camp, Warsaw U, 2014, A The Carpet

一個地圖上有若干障礙&#xff0c;問允許出現一個障礙的最大子矩形為多大&#xff1f; 最大子矩形改編 #include<bits/stdc.h> using namespace std; #define rep(i, j, k) for (int i int(j); i < int(k); i) #define dwn(i, j, k) for (int i int(j); i > int…

d3.js 教程 模仿echarts折線圖

今天我們來仿echarts折線圖,這個圖在echarts是折線圖堆疊&#xff0c;但是我用d3改造成了普通的折線圖&#xff0c;只為了大家學習&#xff08;其實在簡單的寫一個布局就可以&#xff09;。廢話不多說商行代碼。 1 制作 Line 類 class Line {constructor() {this._width 1100;…

vue中v-for的使用

本人正在開始學習Vue,每天寫寫基礎的記錄,希望對大家有幫助,如有錯誤還望指出,我也是一個小白,也希望大家能一起進步 v-for指令的使用: 1.循環普通數組 item in list 中的item是自己個想寫什么名寫什么名 另一種寫法 i 表示索引值 2.循環對象數組 3.循環普通對象 4.迭代數字 注…

js高級第一天

JavaScript面向對象 1.1兩大編程思想&#xff1a; 1、面向過程 ? 面向過程&#xff1a;POP(Process-oriented programming) 面向過程就是分析出解決問題所需要的步驟&#xff0c;然后用函數把這些步驟一步一步實現&#xff0c;使用的時候再一個一個的依次調用就可以了。 ?…

d3.js 教程 模仿echarts legend功能

上一節記錄沒有加上echarts的legend功能&#xff0c;這一小節補一下。 1. 數據 我們可以從echarts中看出&#xff0c;折線數據并不是我們傳進入的原始數據&#xff08;多數情況下我們也不會修改原始數據&#xff09;&#xff0c;而是原始數組的一個備份而已。備份數組的方法有很…

小程序2-基本架構講解(一)WXSS樣式

項目里邊生成了不同類型的文件: .json 后綴的 JSON 配置文件.wxml 后綴的 WXML 模板文件.wxss 后綴的 WXSS 樣式文件.js 后綴的 JS 腳本邏輯文件WXSS 樣式 WXSS (WeiXin Style Sheets)是一套樣式語言&#xff0c;用于描述 WXML 的組件樣式。WXSS 具有 CSS 大部分的特性 新增了尺…

js高級—tab欄切換(面向對象做法)

<main><h4>Js 面向對象 動態添加標簽頁</h4><div class"tabsbox" id"tab"><!-- tab 標簽 --><nav class"fisrstnav"><ul><li class"liactive"><span>測試1</span><sp…

MFC的sendmessage和postmessage 以及sendmessagetimeout

PostMessage只負責將消息放到消息隊列中&#xff0c;不確定何時及是否處理&#xff0c;相當于異步操作&#xff0c;執行后馬上返回SendMessage要等到受到消息處理的返回碼&#xff08;DWord類型&#xff09;后才繼續&#xff0c;相當于同步操作&#xff0c;一直在等待&#xff…

python PIL圖像處理-框選

框選圖中位置 代碼 from PIL import Image,ImageDraw,ImageFont,ImageFilter import random#------------------------------------- #filepath,[837,103][942,208]#圖片處理&#xff0c;框選 def pic_rectangle(filepath,bound):image Image.open(filepath)draw ImageDraw.D…

Win10卸載python總是提示error2503失敗各種解決辦法

最近win10的電腦裝了python的3.4&#xff0c;然后想卸載&#xff0c;就總是提示error 2053&#xff0c;類似于這種&#xff1a; 下面是我的坎坷解決之路&#xff1a; 1、網上說&#xff0c;任務管理器 --> 詳細信息 --> explorer.exe結束任務&#xff0c;結束資源管理器&…

js高級—查詢商品案例

<div class"search">按照價格查詢&#xff1a;<input type"text" class"start"> - <input type"text" class"end"><button class"search-price">搜索</button> 按照商品名稱查詢&a…

[Codeforces702F]T-Shirts——非旋轉treap+貪心

題目鏈接&#xff1a; Codeforces702F 題目大意&#xff1a;有$n$種T恤&#xff0c;每種有一個價格$c_{i}$和品質$q_{i}$且每種數量無限。現在有$m$個人&#xff0c;第$i$個人有$v_{i}$元&#xff0c;每人每次會買他能買得起的品質最高的一件T恤(當兩件T恤品質相同時優先買價格…

js高級第二天

構造函數和原型 構造函數和原型 在典型的OOP 的語言中&#xff08;如Java&#xff09;&#xff0c;都存在類的概念&#xff0c;類就是對象的模板&#xff0c;對象就是類的實例&#xff0c;但在ES6之前&#xff0c;JS 中并沒用引入類的概念。ES6&#xff0c;全稱ECMAScript6.0…

操作系統原理之文件系統(第五章)

一、文件 1、?件系統的?戶接?包括?件的命名、類型、屬性和對?件的操作 2、?件命名&#xff1a;所有操作系統都允許?1&#xff5e;8個字?組成的字符串 3、?件擴展名&#xff1a;多數操作系統都?持?件名?圓點隔開分為兩部分&#xff0c;圓點后?的部分稱為?件擴展名…

第三次作業------52李金鎮

---恢復內容開始--- 習題1&#xff1a; **1.初始化一個數據集&#xff0c;包括5-10位同學的成績數據&#xff08;數據類型不限&#xff09;&#xff0c;數據格式如下&#xff1a; **學號 姓名 Java C語言 Python2017XXXX 小白 87 68 922017XXXX 小黃 80 76 832017XXXX 小王 75 …

js高級第三天

原型鏈 作用&#xff1a;提供一個成員的查找機制&#xff0c;或者查找規則含義&#xff1a;由原型所串聯起來的鏈裝結構JavaScript 的成員查找機制(規則) 當訪問一個對象的屬性&#xff08;包括方法&#xff09;時&#xff0c;首先查找這個對象自身有沒有該屬性。如果沒有就查…

為什么大學的計算機老師技術那么厲害,卻不愿意當程序員?

不知道大家有多少是從事跟計算機有關的工作的&#xff0c;每次想到大學時的計算機考試&#xff0c;都能令小小編心驚膽戰呀&#xff0c;各式代碼和計算機語言&#xff0c;真的是很令人頭痛了。不過呢&#xff0c;也有很多大神&#xff0c;大學學著其他的專業&#xff0c;卻在畢…

DDG全家桶之3022

本篇文章主要根據360Netlab新出的DDG分析文檔來復現新變種3022&#xff0c;會涉及部分分析和清除的方法&#xff0c;本篇文章只用于學習交流&#xff0c;為廣大受害者提供清除思路 &#xff0c;請勿用于非法用途&#xff0c;產生一切后果與作者無關 詳情請參考文檔&#xff1a;…

js高級第四天

課程回顧&#xff1a; ? 原型鏈&#xff1a;由原型構成鏈狀結構&#xff0c;提供成員查找機制 ? 繼承&#xff1a;組合繼承&#xff1a;構造函數和原型對象 ? 屬性&#xff1a;調用父構造函數的時候用call改變this指向 ? 方法&#xff1a;父實例對象賦值給子原型對象&a…

d3.js 制作簡單的俄羅斯方塊

d3.js是一個不錯的可視化框架&#xff0c;同時對于操作dom也是十分方便的。今天我們使用d3.js配合es6的類來制作一個童年小游戲--俄羅斯方塊。話不多說先上圖片。 1. js tetris類 由于方法拆分的比較細所以加上了一些備注&#xff08;這不是我的風格&#xff01;&#xff09; c…