Asp.net core 3.1實現路由Url根據名稱空間自動生成
按Asp.net core
預設的介面寫法,每個介面控制器都得繼承自ControllerBase
類,還需具有ApiController
特性及Route
特性,Route
特性上還得手動寫上路由規則。如下圖所示
我覺得挺麻煩的,可能我比較懶,其實我的寫的大多數的介面路徑都是按一定規則的,一般是以名稱空間Controllers.後面的名稱空間做為路徑字首,然後以[controller]/[action]
路由規則進行匹配。
例如名稱空間LessSharp.WebApi.Controllers.Sys
下面的UserController
控制器下面的Save
介面,那麼根據名稱空間的後面Sys,對應的介面路徑值就為/Sys/User/Save
那麼我希望預設情況下,可以以我上面的規則自動生成路徑,如果有特殊情況的話,那我加個Route
特性,手動寫上我的路由規則,框架就優先按我Route
特性定義的路由路徑值。
我實現的方法主要使用了Asp.net Core
提供的控制器模型約定ControllerModelConvention
功能,再借助ApiConventionController
控制器基類,路由生成只會在系統啟動進行生成,所以對系統性能無任何影響。
以下是ApiConventionController
的程式碼,這個類其實作用不大,主要起個標記作用,只要繼承這個控制器基類的控制器就說明要使用以上的Url生成規則。
namespaceLessSharp.WebApi.Controllers { /// <summary> /// 繼承此控制器後,會自動根據名稱空間結構修改Route增加字首 /// 例如LessSharp.WebApi.Controllers.Sys.A.B名稱空間下的UserController控制器,就會生成Sys/A/B/User這樣的路由 /// 如果派生控制器有自定義Route特性的話,就不會自動增加字首 /// </summary> [Route("[controller]/[action]")] [ApiController] public abstractclass ApiConventionController : ControllerBase { }
以下是這個Url生成功能最核心的類ApiRoutePrefixControllerModelConvention,它實現IControllerModelConvention介面
namespace LessSharp.WebApi.Conventions { public class ApiRoutePrefixControllerModelConvention : IControllerModelConvention { /// <summary> /// 路徑字首 /// </summary> private readonly string _prefix; public ApiRoutePrefixControllerModelConvention(string prefix) { _prefix = prefix; } public void Apply(ControllerModel controller) { //判斷是否是ApiConventionController的派生控制器 if (controller.ControllerType.BaseType != typeof(ApiConventionController)) { return; } //判斷是否有自定義Route特性 if (controller.ControllerType.GetCustomAttributes(typeof(RouteAttribute), false).Length > 0) { return; } string controllerNamespace = controller.ControllerType.Namespace; string temp = "Controllers."; int index = controllerNamespace.IndexOf(temp); string prefix = _prefix.Trim('/'); if (index > -1) { prefix += "/" + controllerNamespace.Substring(index + temp.Length); } if (string.IsNullOrEmpty(prefix)) { return; } if (!string.IsNullOrEmpty(prefix)) { prefix = prefix.Replace(".", "/"); } foreach (var selector in controller.Selectors.Where(s => s.AttributeRouteModel != null)) { selector.AttributeRouteModel.Template = prefix + "/" + selector.AttributeRouteModel.Template; } } } }
最後在Startup的ConfigureServices方法裡新增這個約定。我這裡還添加了根據配置檔案的RoutePrefix值統一新增Url字首的功能
services.AddControllers(o => {//新增約定器,對ApiConventionController的派生類新增路由字首 o.Conventions.Add(new ApiRoutePrefixControllerModelConvention(Configuration.GetValue<string>("RoutePrefix"))); })
最後你只要這麼使用就行了,又省了不少程式碼,哈哈哈