背景:
本項(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