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

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

概述由于遭遇 System.Data.SqlClient 的性能问题(详见之前的博文),向 .NET Core 3.0 的升级工作被迫提前了。在升级过程中遇到了一个问题,我们在 Razor Class Library 中实现的自定义错误页面无法在 ASP.NET Core 3.0 Preview 5 中正常工作,问题原因详见博问 Razor Class Library 中的属性路由在 ASP.NET

由于遭遇 System.Data.sqlClIEnt 的性能问题(详见之前的博文),向 .NET Core 3.0 的升级工作被迫提前了。在升级过程中遇到了一个问题,我们在 Razor Class library 中实现的自定义错误页面无法在 ASP.NET Core 3.0 PrevIEw 5 中正常工作,问题原因详见博问 Razor Class Library 中的属性路由在 ASP.NET Core 3.0 中不起作用 。

由于属性路由不起作用的问题没找到解决方法,于是被迫采用了另外一种解决方法 —— 在中间件中调用 Razor Class library 中的 Controller Action 显示自定义错误页面。这就需要将原先由 ASP.NET Core Runtime 自动执行的 Controller Action (自动挡)改为手工执行(手动挡),之前没玩过,借此机会试一试。

不试不知道,一试吓一跳,手动 *** 作好麻烦,这不是自动挡换手动挡,这是自动挡换拖拉机。

开始寸步难行,挂挡都不知道在哪挂,后来在 ASP.NET Core 3.0 的源码中找到了 ControllerActionDescriptorBuilder.cs 中的 CreateActionDescriptor 方法,才有了参考。

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,action);    AddPropertIEs(actionDescriptor,action,application);    return actionDescriptor;}

带上参考小手册,开始试驾。。。经过无数次熄火(NullReferenceException) 后,总算用手动挡开车上路,于是就有了这篇随笔分享手动挡驾驶小经验。

手动挡的 *** 作杆主要有:RouteData, ActionDescriptor, ActionContext, ActionInvokerFactory, ControllerActionInvoker

其中最难 *** 作的也是最重要的是 ActionDescriptor ,绝大多数的熄火都是在 *** 作它时发生的,它有8个属性需要赋值,有些属性即使没用到也要进行初始化赋值,不然立马熄火(null引用异常)。

ActionDescriptor 的 *** 作方法如下

var actionDesciptor = new ControllerActionDescriptor(){    Controllername = controllerType.name,Actionname = actionname,FilterDescriptors = new List<FilterDescriptor>(),MethodInfo = typeof(HomeController).getmethod(actionname,BindingFlags.Public | BindingFlags.Instance),ControllerTypeInfo = controllerType.GetTypeInfo(),Parameters = new List<ParameterDescriptor>(),PropertIEs = new Dictionary<object,object>(),BoundPropertIEs = new List<ParameterDescriptor>()                };

ControllerActionDescriptor 继承自 ActionDescriptor ,上面的赋值 *** 作中真正传递有价值数据的是 Controllername, Actionname,MethodInfo, ControllerTypeInfo 。一开始不知道要对哪些属性赋值,只能一步一步试,根据熄火情况一个一个添加,最终得到了上面的最少赋值 *** 作。

第二重要的是 RouteData ,它是数据传输带,不仅要通过它向 ActionDescriptor 传送 BindingInfo 以及 Action 方法通过它获取参数值,而且要向视图引擎(比如VIEwEngineResult,VIEwResultExecutor)传送 controller 与 action 的名称,不然视图引擎找不到视图文件。

RouteData 的 *** 作方法如下

//For searching VIEwrouteData.Values.Add("controller",actionDesciptor.Controllername.Replace("Controller",""));routeData.Values.Add("action",actionDesciptor.Actionname);//For binding action parametersforeach (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 之后,只需4步 *** 作,可以把车开起来了。

var actionContext = new ActionContext(context,routeData,actionDesciptor);                    var actionInvokerFactory = app.@[email protected]<IActionInvokerFactory>(); //ActionInvokerFactoryvar invoker = actionInvokerFactory.CreateInvoker(actionContext); //ControllerActionInvokerawait invoker.InvokeAsync();

但车没有跑在高速上,而是通过 ASP.NET Core 3.0 的 EndpointRouting 跑在了 mIDdleware 中。

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

看看手动挡开车的效果,Contorller 的示例代码如下

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

运行结果

手动挡驾驶 ASP.NET Core 3.0 PrevIEw 5 版 Contoller Action 型新车成功!

完整代码见 github 上的 Startup.cs 

总结

以上是内存溢出为你收集整理的自动挡换手动挡:在 ASP.NET Core 3.0 Middleware 中手动执行 Controller Action全部内容,希望文章能够帮你解决自动挡换手动挡:在 ASP.NET Core 3.0 Middleware 中手动执行 Controller Action所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1233568.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存