ASP.NET Core 替换 Action 实际执行方法

RequestDelegate

上次,我们在《如何判断当前请求的API类型》中查看endpoints.MapControllers()实现时,最终定位到ActionEndpointFactory.cs,其中有这样一段代码:

private static RequestDelegate CreateRequestDelegate()
{// We don't want to close over the Invoker Factory in ActionEndpointFactory as// that creates cycles in DI. Since we're creating this delegate at startup time// we don't want to create all of the things we use at runtime until the action// actually matches.//// The request delegate is already a closure here because we close over// the action descriptor.IActionInvokerFactory? invokerFactory = null;return (context) =>{var endpoint = context.GetEndpoint()!;var dataTokens = endpoint.Metadata.GetMetadata<IDataTokensMetadata>();var routeData = new RouteData();routeData.PushState(router: null, context.Request.RouteValues, new RouteValueDictionary(dataTokens?.DataTokens));// Don't close over the ActionDescriptor, that's not valid for pages.var action = endpoint.Metadata.GetMetadata<ActionDescriptor>()!;var actionContext = new ActionContext(context, routeData, action);if (invokerFactory == null){invokerFactory = context.RequestServices.GetRequiredService<IActionInvokerFactory>();}var invoker = invokerFactory.CreateInvoker(actionContext);return invoker!.InvokeAsync();};
}

从代码上理解,应该是执行请求时,会创建IActionInvokerFactory实例,由它创建 invoker 执行。

是不是这样呢,我们验证一下!

IActionInvokerFactory

新建CustomActionInvokerFactory.cs,继承IActionInvokerFactory,实现代码如下:

public class CustomActionInvokerFactory : IActionInvokerFactory
{private readonly IActionInvokerProvider[] _actionInvokerProviders;public ActionInvokerFactory(IEnumerable<IActionInvokerProvider> actionInvokerProviders){_actionInvokerProviders = actionInvokerProviders.OrderBy(item => item.Order).ToArray();}public IActionInvoker? CreateInvoker(ActionContext actionContext){var context = new ActionInvokerProviderContext(actionContext);foreach (var provider in _actionInvokerProviders){provider.OnProvidersExecuting(context);}for (var i = _actionInvokerProviders.Length - 1; i >= 0; i--){_actionInvokerProviders[i].OnProvidersExecuted(context);}return context.Result;}
}

代码 Copy 自 ASP.NET Core 内部实现类ActionInvokerFactory。

然后在 Startup.cs 注册实现:

public void ConfigureServices(IServiceCollection services)
{services.AddSingleton<IActionInvokerFactory, CustomActionInvokerFactory>();...
}

打上断点,执行API,发现确实如设想中一样,请求时执行CreateInvoker方法:

d6e0e7e28c5994c1139fb7d431312ce6.png

在其中发现了一个很有意思的属性MethodInfo,正是对应我们执行的 Action 方法。

突发奇想,如果我们替换MethodInfo属性,是不是会执行其他方法呢?

Demo

创建 WeatherForecast2Controller,实现代码如下:

[ApiController]
[Route("[controller]")]
public class WeatherForecast2Controller : ControllerBase
{[HttpGet]public string Get2(){return "My IO";}
}

可以看到这是和原方法完全不同的实现。

现在进行替换:

var actionDescriptor = actionContext.ActionDescriptor as ControllerActionDescriptor;
actionDescriptor.MethodInfo = typeof(WeatherForecast2Controller).GetMethod("Get2");

执行,出现错误提示:

6549ba76d6ecdc8a567c9cc79fb44601.png

查看ControllerActionInvokerCache.cs实现:

var objectMethodExecutor = ObjectMethodExecutor.Create(actionDescriptor.MethodInfo,actionDescriptor.ControllerTypeInfo,parameterDefaultValues);

原来,还要替换actionDescriptor.ControllerTypeInfo:

var actionDescriptor = actionContext.ActionDescriptor as ControllerActionDescriptor;
actionDescriptor.MethodInfo = typeof(WeatherForecast2Controller).GetMethod("Get2");
actionDescriptor.ControllerTypeInfo = typeof(WeatherForecast2Controller).GetTypeInfo();

再次运行,执行成功!

c1b5072e8a930c5abae70d1d4f490ea0.png

结论

替换 Action 实际执行方法,最好的使用场景是定制化开发,比如客户需求和产品实现完全不同,可以保证请求不变的情况下执行客户定制化实现。

想了解更多内容,请关注我的个人公众号”My IO“

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/291233.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最新版富文本编辑器UEditor操作教程

最近项目中使用到了富文本编辑器&#xff0c;选择的是百度的UEditor。所以对其进行了研究&#xff0c;发现最近发布了新版本&#xff0c;与以往的用法有的改变。一下对UEditotr 的是用做一下详细的介绍。 首先是UEditotr的下载&#xff0c;下载地址&#xff1a;http://ueditor.…

LeetCode之Construct the Rectangle

1、题目 For a web developer, it is very important to know how to design a web pages size. So, given a specific rectangular web page’s area, your job by now is to design a rectangular web page, whose length L and width W satisfy the following requirements:…

php ftp 创建文件夹失败,PHP使用FTP函数创建目录

这篇文章主要为大家详细介绍了PHP使用FTP函数创建目录&#xff0c;具有一定的参考价值&#xff0c;可以用来参考一下。经测试代码如下&#xff1a;// create directory through FTP connectionfunction FtpMkdir($path, $newDir) {$serverftp.yourserver.com; // ftp 地址$conn…

Servlet请求转发中文乱码解决

2019独角兽企业重金招聘Python工程师标准>>> 在Servlet的使用过程中&#xff0c;如果在请求转发的同时需要获得输出流并且写出数据的时候&#xff0c;需要设定resp 的编码格式&#xff0c;否则的话&#xff0c;跳转之后的页面很可能会出现中文乱码的问题。 转载于:h…

NodeJs .net core connect Azure service bus

最近有个项目需要使用nodejs 使用语言是Typescript 发送消息给Azure service bus消息格式是XML.但是发送到queue中并不是xml格式,而是string.string格式的消息直到看到azure/service-bus sdk 接口的定义才发现.如果接收消息应用不是javascript sdk框架(因为使用是.net sdk框架接…

Angular 2 Decorators - 1

在我们深入了解 Angular 2 中 NgModule、Component、Injectable 等常见的装饰器之前&#xff0c;我们要先了解 TypeScript 中的装饰器。装饰器是一个非常酷的特性&#xff0c;最早出现在 Google 的 AtScript 中&#xff0c;它出现的目的是为了让开发者&#xff0c;开发出更容易…

LeetCode之Relative Ranks

1、题目 Given scores of N athletes, find their relative ranks and the people with the top three highest scores, who will be awarded medals: "Gold Medal", "Silver Medal" and "Bronze Medal". Example 1: Input: [5, 4, 3, 2, 1] Out…

php yii 插入,Yii2 批量插入、更新数据实例

在使用yii2开发项目时,有时候会遇到这样的情况:向后台发送多条数据,其中一些数据已经存在记录,只需要对其部分字段的值进行修改;而另一部分的数据则需要新添加进去.这就需要对添加的数据进行判断,其中一些执行update,剩下的执行insert代码如下,不对的地方请指教://批量更新,并将…

c++代码寻找USB00端口并添加打印机

USB00*端口的背景 插入USB端口的打印机&#xff0c;安装打印机驱动&#xff0c;在控制面板设备与打印机处的打印机对象上右击&#xff0c;可以看到打印机端口。对于不少型号&#xff0c;这个端口是USB001或USB002之类的。 经观察&#xff0c;这些USB00*端口并不是打印机驱动所…

WCF中使用控件的委托,线程中的UI委托

UI界面&#xff1a; <Window x:Class"InheritDemo.Window1"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"Title"Window1" Height"300" Widt…

.NET6之MiniAPI(十七):缓存

缓存是空间换时间的一种做法&#xff0c;可以有效的提升响应时间&#xff0c;asp.net core引入了本地内存缓存和分布式缓存。先看一下本地内存缓存&#xff1a;using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Internal;var builder WebApplication.C…

Android之机端安装apk出现INSTALL_FAILED_INSUFFICIENT_STORAGE错误的解决方法

1、错误 INSTALL_FAILED_INSUFFICIENT_STORAGE 2、解决办法 是由于手机存储不足了&#xff0c;删除一些app,给手机留下足够的空间即可。

IOS调用WCF提供的服务方法,但是方法的参数是WCF那边自定义的对象,这样有办法调用么,如果可以IOS应该怎么传参呢?请问有了解的么,...

最近做一个项目后端使用WCF接收Android手机拍照并带其它参数保存到服务器里&#xff1b;刚好把最近学习的WCF利用上&#xff0c;本以为是个比较简单的功能应该很好实现&#xff0c;没想到其中碰到不少问题&#xff0c;在网上搜索很久一直没有想到的解决方案&#xff0c;最后实现…

php数据表格的重载,layui数据表格实现重载数据表格功能(搜索功能)

layui数据表格实现重载数据表格功能&#xff0c;以搜索功能为例加载数据表格实现搜索功能和数据表格重载全部代码加载数据表格按照layui官方文档示例HTML部分JavaScript部分var table layui.table;//执行渲染table.render({elem: #demo //指定原始表格元素选择器(推荐id选择器…

python读取windows系统的文件后print乱码问题的解决

我用的是2.7 先文件头用老办法 import sysreload(sys)sys.setdefaultencoding("utf-8") 后 print filename.decode(gbk).encode(utf-8)转载于:https://www.cnblogs.com/leomo/p/6528064.html

JAVA学习博客---2015.5

上一次的学习博客写的和流水账差不多&#xff0c;有点生硬的和背目录一样&#xff0c;所以既然学习的目的是程序&#xff0c;那么这个月的学习博客就用程序来说点东西吧。这个月看了一些C和JAVA的视频&#xff0c;开始看别人写的程序&#xff0c;能看的懂但是自己去写的话前后逻…

ABP vNext微服务架构详细教程——项目部署

1基础配置在之前的文章中&#xff0c;我们已经配置了Kubernetes集群并安装了管理工具Kubesphere&#xff0c;文章地址为&#xff1a;https://mp.weixin.qq.com/s/MgpdMv5A-fYxN7XY8N9Djw登录Kubesphere页面&#xff0c;打开工作台&#xff0c;在平台资源选项卡中点击“企业空间…

LeetCode之Sqrt(x)

1、题目 Implement int sqrt(int x). Compute and return the square root of x. Subscribe to see which companies asked this question. 2、代码实现 public class Solution {public int mySqrt(int x) {if (x < 0)return -1;if (x 0)return 0; if (x 1) return 1;int …

offsetTop和scrollTop的差别

近期想写个组件&#xff0c;结果被这两个属性搞的有点晕&#xff0c;查了下文档和资料&#xff0c;对这两个属性总结例如以下&#xff1a; 一直以来对offsetLeft&#xff0c;offsetTop&#xff0c;scrollLeft&#xff0c;scrollTop这几个方法非常迷糊&#xff0c;花了一天的时间…

php post授权编写,php模拟post行为代码总结(POST方式不是绝对安全)

GET行为比较简单&#xff0c;POST比较复杂一些。这里提供两种方法供选择&#xff1a;第一&#xff1a;手写代码。第二&#xff1a;利用HttpClient php类库第一种方法&#xff1a;PHP代码$flag 0;//要post的数据$argv array(var1>abc,var2>你好吗);//构造要post的字符串…