日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

ASP.NET Core 3.0 自动挡换手动挡:在 Middleware 中执行 Controller Action

發(fā)布時(shí)間:2023/12/4 asp.net 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET Core 3.0 自动挡换手动挡:在 Middleware 中执行 Controller Action 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最近由于發(fā)現(xiàn)奇怪的 System.Data.SqlClient 性能問題(詳見之前的博文),被迫提前了向 .NET Core 3.0 的升級工作(3.0 Preview 5 中問題已被修復(fù))。郁悶的是,在剛開始對部分項(xiàng)目進(jìn)行升級的時(shí)候就遇到了一個(gè)障礙,我們基于 Razor Class Library 實(shí)現(xiàn)的自定義錯(cuò)誤頁面由于屬性路由問題無法在 ASP.NET Core 3.0 Preview 5 中正常工作(詳見博問),一番排查后也沒找到解決方法。

為了不影響升級進(jìn)展,我們被迫采用了一種不常用的解決方法 —— 在中間件中直接調(diào)用 Controller Action 渲染視圖顯示自定義錯(cuò)誤頁面,也就是將原先由 ASP.NET Core Runtime 自動執(zhí)行的 Controller Action (自動擋)改為手工執(zhí)行(手動擋)。

原以為不就是比踩油門多了踩離合器和掛擋嗎,應(yīng)該不會很難。哪知點(diǎn)火后,掛擋都不知道在哪掛。Action 方法非常特殊,調(diào)用它要做很多準(zhǔn)備工作,就如掛擋之前要先自己給車安裝離合器和掛擋裝置,再加上是手動擋新手,開始都不知道從哪下手。

幸虧在 ASP.NET Core 3.0 的源碼中翻到了一本小冊子 ——?ControllerActionDescriptorBuilder.cs?中的?CreateActionDescriptor 方法,才有了點(diǎn)參考。

private static ControllerActionDescriptor CreateActionDescriptor(...)
{
var actionDescriptor = new ControllerActionDescriptor
{
ActionName
= action.ActionName,
MethodInfo
= action.ActionMethod,
};

actionDescriptor.ControllerName
= controller.ControllerName;
actionDescriptor.ControllerTypeInfo
= controller.ControllerType;
AddControllerPropertyDescriptors(actionDescriptor, controller);

AddActionConstraints(actionDescriptor, selector);
AddEndpointMetadata(actionDescriptor, selector);
AddAttributeRoute(actionDescriptor, selector);
AddParameterDescriptors(actionDescriptor, action);
AddActionFilters(actionDescriptor, action.Filters, controller.Filters, application.Filters);
AddApiExplorerInfo(actionDescriptor, application, controller, action);
AddRouteValues(actionDescriptor, controller, action);
AddProperties(actionDescriptor, action, controller, application);

return actionDescriptor;
}

在這本小手冊的指導(dǎo)下,經(jīng)過無數(shù)次熄火(NullReferenceException) 后,總算把用手動擋把車開了起來,于是有了這篇隨筆分享一點(diǎn)駕車小經(jīng)驗(yàn)。

手動擋的操作桿主要有:RouteData,?ActionDescriptor,?ActionContext,?ActionInvokerFactory,?ControllerActionInvoker

其中最難操作的也是最重要的是?ActionDescriptor ,絕大多數(shù)的熄火都是在操作它時(shí)發(fā)生的,它有8個(gè)屬性需要賦值,有些屬性即使沒用到也要進(jìn)行初始化賦值,不然立馬熄火(null引用異常)。

ActionDescriptor 的操作方法如下

private static ActionDescriptor CreateActionDescriptor<TController>(string actionName, RouteData routeData)
{
var controllerType = typeof(TController);
var actionDesciptor = new ControllerActionDescriptor()
{
ControllerName
= controllerType.Name,
ActionName
= actionName,
FilterDescriptors
= new List<FilterDescriptor>(),
MethodInfo
= controllerType.GetMethod(actionName, BindingFlags.Public | BindingFlags.Instance),
ControllerTypeInfo
= controllerType.GetTypeInfo(),
Parameters
= new List<ParameterDescriptor>(),
Properties
= new Dictionary<object, object>(),
BoundProperties
= new List<ParameterDescriptor>()
};

//...
}

ControllerActionDescriptor 繼承自?ActionDescriptor ,上面的賦值操作中真正傳遞有價(jià)值數(shù)據(jù)的是?ControllerName,?ActionName, MethodInfo,?ControllerTypeInfo 。一開始不知道要對哪些屬性賦值,只能一步一步試,根據(jù)熄火情況一個(gè)一個(gè)添加,最終得到了上面的最少賦值操作。

第二重要的是?RouteData ,它是數(shù)據(jù)傳輸帶,不僅要通過它向 ActionDescriptor 傳送?BindingInfo 以及向 Action 方法傳遞參數(shù)值,而且要向視圖引擎(比如ViewEngineResult,ViewResultExecutor)傳送 controller 與 action 的名稱,不然視圖引擎找不到視圖文件。

RouteData 的操作方法如下

//For searching View
routeData.Values.Add("controller", actionDesciptor.ControllerName.Replace("Controller", ""));
routeData.Values.Add(
"action", actionDesciptor.ActionName);

//For binding action parameters
foreach (var routeValue in routeData.Values)
{
var parameter = new ParameterDescriptor();
parameter.Name
= routeValue.Key;
var attributes = new object[]
{
new FromRouteAttribute { Name = parameter.Name },
};
parameter.BindingInfo
= BindingInfo.GetBindingInfo(attributes);
parameter.ParameterType
= routeValue.Value.GetType();
actionDesciptor.Parameters.Add(parameter);
}

有了?ActionDescriptor 與?RouteData 之后,只需3步操作:

1)ActionContext 把離合器和掛擋裝置組合起來;

2)ActionInvokerFactory 將?ActionContext 安裝到車上并提供了掛擋桿?ControllerActionInvoker;

3)拉動 InvokeAsync 異步掛擋。

就可以把車開起來。

var actionContext = new ActionContext(context, routeData, actionDesciptor);
var actionInvokerFactory = app.ApplicationServices.GetRequiredService<IActionInvokerFactory>(); //ActionInvokerFactory
var invoker = actionInvokerFactory.CreateInvoker(actionContext); //ControllerActionInvoker
await invoker.InvokeAsync();

但車沒有跑在高速上,而是通過 ASP.NET Core 3.0 的 Endpoint Routing 跑在了中間件(middleware)中。

app.UseEndpoints(endpoints =>
{
endpoints.MapGet(
"/", async context =>
{
var routeData = new RouteData();
routeData.Values.Add(
"message", "Hello World!");
await DriveControllerAction(context, routeData, app);
});
});

Contorller Action 的示例代碼如下,就是將參數(shù)值傳遞給視圖顯示出來。

public class HomeController : Controller
{
public IActionResult Index(string message)
{
ViewBag.Message
= message;
return View();
}
}

當(dāng)程序一運(yùn)行,瀏覽器請求一發(fā)出, DriveControllerAction 就開始手動擋操作,將車開起來,開車效果如下:

雖然開手動擋比自動擋麻煩很多,但駕駛時(shí)那種自主把控的感覺還是不錯(cuò)的,更重要的是這樣的自主解決了我們的實(shí)際問題。雖然大多數(shù)情況下都只要開自動擋,但會開手動擋會給你在解決問題時(shí)多一種選擇。

完整代碼見 github 上的?Startup.cs?

原文地址:https://www.cnblogs.com/dudu/p/10885094.html

.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總?http://www.csharpkit.com?


總結(jié)

以上是生活随笔為你收集整理的ASP.NET Core 3.0 自动挡换手动挡:在 Middleware 中执行 Controller Action的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。