WebApi 重寫 DefaultHttpControllerSelector 實(shí)現(xiàn)路由重定向

背景:
本項(xiàng)目為后臺項(xiàng)目
近期項(xiàng)目組內(nèi)推行前后端分離架構(gòu)捂齐。前端使用vue,后端使用webapi進(jìn)行重構(gòu)拍皮。
因原項(xiàng)目為mvc,所以重構(gòu)對于后臺接口變化不大跑杭。

新建webapi項(xiàng)目铆帽,log4net引入,swagger引入德谅,全局異常處理爹橱,實(shí)現(xiàn)登陸登出功能,實(shí)現(xiàn)登陸過濾器女阀,實(shí)現(xiàn)token安全機(jī)制宅荤,規(guī)范下接口返回模型等等。

前端使用vue后url路由由前端接管浸策,后端只用實(shí)現(xiàn)功能需要的數(shù)據(jù)接口和一個返回前端初始化資源的初始頁面暫定Web/Index冯键。

通常實(shí)現(xiàn)是,登陸后重定向到Web/Index頁面庸汗,Web/Index頁面輸出前端初始化資源惫确,后續(xù)路由跳轉(zhuǎn)由前端接管。

但因?yàn)槭桥f項(xiàng)目重構(gòu)蚯舱,只能一部分一部分切換為vue+webapi的新架構(gòu)改化,需要和mvc的舊項(xiàng)目共用一段時間。通過菜單url的不同來確定跳轉(zhuǎn)到新或者舊項(xiàng)目

這樣就需要額外實(shí)現(xiàn):新舊項(xiàng)目登陸/登出聯(lián)動枉昏,并且保證新舊系統(tǒng)框架樣式(菜單陈肛,頭部,底部)保持一致兄裂。

還引發(fā)一個問題:從舊項(xiàng)目可以跳轉(zhuǎn)到任意一個新項(xiàng)目功能頁面句旱,并且需要輸出前端初始化資源,后續(xù)路由跳轉(zhuǎn)就由前端接管了晰奖。

這樣就需要很多路由規(guī)則都匹配到Web/Index谈撒,然后輸出前端初始化資源

原實(shí)現(xiàn)方式:

using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web.Http;

namespace AppApi.Controllers
{
    /// <summary>
    /// 
    /// </summary>
    public class WebController : ApiController
    {
        #region Public APIs

        /// <summary>
        /// Index
        /// </summary>
        /// <returns></returns>
        [Route("fe/dashboard")]
        [Route("fe/Product/Index")]
        [Route("fe/User/Index")]
        [Route("fe/Order/Index")]
        [Route("fe/System/Menu/Index")]
        [Route("fe/System/Config/Index")]
        [HttpGet]
        public HttpResponseMessage Index()
        {
            //前端資源
            string resourceHtml = "";
            var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(resourceHtml) };
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
            return response;
        }
        #endregion
    }
}

這種方式需要定義大量的路由規(guī)則。

新的實(shí)現(xiàn)方式:

使用重寫DefaultHttpControllerSelector(Controller選擇器)匾南,ApiControllerActionSelector(Action選擇器)實(shí)現(xiàn)

因前端路由都包含 /fe/ 啃匿,所以我們就攔截所有包含 /fe/ 的url

1,重寫 DefaultHttpControllerSelector 的 GetControllerName 方法

新建文件:CustomControllerSelector.cs

using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Dispatcher;

namespace AppApi.App_Start
{
    /// <summary>
    /// 自定義Controller選擇
    /// </summary>
    public class CustomControllerSelector : DefaultHttpControllerSelector
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="configuration"></param>
        public CustomControllerSelector(HttpConfiguration configuration) : base(configuration)
        {
        }

        /// <summary>
        /// 摘要:獲取指定 System.Net.Http.HttpRequestMessage 的控制器的名稱。
        /// </summary>
        /// <param name="request">參數(shù):request:HTTP 請求消息溯乒。</param>
        /// <returns>返回結(jié)果:指定 System.Net.Http.HttpRequestMessage 的控制器的名稱夹厌。</returns>
        public override string GetControllerName(HttpRequestMessage request)
        {
            //Index規(guī)則(/fe/)滿足的話,返回Web/Index
            if (request.RequestUri.AbsoluteUri.Contains("/fe/"))
            {
                return "Web";
            }
            else
            {
                return base.GetControllerName(request);
            }
        }
    }
}

,2橙数,重寫 ApiControllerActionSelector 的 SelectAction 方法

新建文件:CustomActionSelector.cs

using System.Linq;
using System.Web.Http.Controllers;

namespace AppApi.App_Start
{
    /// <summary>
    /// 自定義Action選擇
    /// </summary>
    public class CustomActionSelector : ApiControllerActionSelector
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <returns></returns>
        public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
        {
            //Index規(guī)則(/fe/)滿足的話尊流,返回Web/Index
            if (controllerContext.Request.RequestUri.AbsoluteUri.Contains("/fe/"))
            {
                return base.GetActionMapping(controllerContext.ControllerDescriptor).FirstOrDefault(f => f.Key == "Index").FirstOrDefault(d => d.ActionName == "Index");
            }
            else
            {
                return base.SelectAction(controllerContext);
            }
        }
    }
}

3,然后添加路由規(guī)則

// WebIndex路由灯帮,返回前端資源
config.Routes.MapHttpRoute(
    name: "WebIndex",
    routeTemplate: "fe/{*.}",//catch-all
    defaults: new { controller = "Web", action = "Index" }
);

注意:routeTemplate: "fe/{.}",//catch-all
使用 fe/{
.} 不管路由由幾級都可以匹配

4崖技,使自定義ControllerSelector,ActionSelector生效

// 使用自定義ControllerSelector钟哥,ActionSelector
config.Services.Replace(typeof(IHttpControllerSelector), new CustomControllerSelector(config));
config.Services.Replace(typeof(IHttpActionSelector), new CustomActionSelector());

修改文件:WebApiConfig.cs

using AppApi.App_Start;
using Newtonsoft.Json.Serialization;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;

namespace AppApi
{
    /// <summary>
    /// webapi配置
    /// </summary>
    public static class WebApiConfig
    {
        /// <summary>
        /// webapi注冊
        /// </summary>
        /// <param name="config"></param>
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服務(wù)
            config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); //json格式化小駝峰
            config.Formatters.Remove(config.Formatters.XmlFormatter);// 取消XML返回格式

            // 使用自定義ControllerSelector迎献,ActionSelector
            config.Services.Replace(typeof(IHttpControllerSelector), new CustomControllerSelector(config));
            config.Services.Replace(typeof(IHttpActionSelector), new CustomActionSelector());

            // 特性路由(RouteAttribute)
            config.MapHttpAttributeRoutes();

            // Action路由
            config.Routes.MapHttpRoute(
                name: "ActionApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { controller = "Common", action = "GetHttpCode", id = RouteParameter.Optional }
                );

            // WebIndex路由,返回前端資源
            config.Routes.MapHttpRoute(
                name: "WebIndex",
                routeTemplate: "fe/{*.}",//catch-all
                defaults: new { controller = "Web", action = "Index" }
                );
        }
    }
}

這樣只要請求URL中包含 /fe/ 都會返回Web/Index響應(yīng)輸出

參考
https://docs.microsoft.com/zh-cn/aspnet/core/mvc/controllers/routing?view=aspnetcore-2.2#multiple-routes
https://www.cnblogs.com/Code-life/p/7182558.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腻贰,一起剝皮案震驚了整個濱河市吁恍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌播演,老刑警劉巖冀瓦,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異写烤,居然都是意外死亡翼闽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門洲炊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來感局,“玉大人,你說我怎么就攤上這事暂衡⊙ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵狂巢,是天一觀的道長撑毛。 經(jīng)常有香客問我,道長唧领,這世上最難降的妖魔是什么藻雌? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮疹吃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘西雀。我一直安慰自己萨驶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布艇肴。 她就那樣靜靜地躺著腔呜,像睡著了一般叁温。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上核畴,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天膝但,我揣著相機(jī)與錄音,去河邊找鬼谤草。 笑死跟束,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的丑孩。 我是一名探鬼主播冀宴,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼温学!你這毒婦竟也來了略贮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤仗岖,失蹤者是張志新(化名)和其女友劉穎逃延,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轧拄,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揽祥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了紧帕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盔然。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖是嗜,靈堂內(nèi)的尸體忽然破棺而出愈案,到底是詐尸還是另有隱情,我是刑警寧澤鹅搪,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布站绪,位于F島的核電站,受9級特大地震影響丽柿,放射性物質(zhì)發(fā)生泄漏恢准。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一甫题、第九天 我趴在偏房一處隱蔽的房頂上張望馁筐。 院中可真熱鬧,春花似錦坠非、人聲如沸敏沉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盟迟。三九已至秋泳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間攒菠,已是汗流浹背迫皱。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辖众,地道東北人卓起。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像赵辕,于是被迫代替她去往敵國和親既绩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355