.NET Core请求控制器Action方法正确匹配,但为何404?
【导读】提前预祝各位端午节快乐。有时候我们会发现方法名称都正确匹配,但就是找不到对应请求接口,所以本文我们来深入了解下何时会出现接口请求404的情况。
匹配控制器Action方法(404)
首先我们创建一个web api应用程序,我们给出如下示例控制器代码
[ApiController]
[Route("[controller]/[action]")]
public class WeatherController : ControllerBase
{[HttpGet]string Get(){return "Hello World";}
}
当我们进行如上请求时会发现接口请求不到,这是为何呢?细心的你应该可能发现了,对于请求方法是私有,而不是公共的,当我们加上public就可以请求到了接口
匹配控制器Action方法本质
经过如上示例,那么对于Action方法的到底要满足怎样的定义才能够不至于请求不到呢?接下来我们看看源码怎么讲。我们找到DefaultApplicationModelProvider类,在此类中有一个OnProvidersExecuting方法用来构建控制器和Action方法模型,当我们构建完毕所有满足条件的控制器模型后,紧接着势必会遍历控制器模型去获取对应控制器模型下的Action方法,这里只截取获取Action方法片段,源码如下:
foreach (var controllerType in context.ControllerTypes)
{ //获取控制器模型下的Action方法foreach (var methodInfo in controllerType.AsType().GetMethods()){var actionModel = CreateActionModel(controllerType, methodInfo);if (actionModel == null){continue;}actionModel.Controller = controllerModel;controllerModel.Actions.Add(actionModel); }
}
上述红色标记则是创建Action模型的重点,我们继续往下看到底满足哪些条件才创建Action模型呢?
protected virtual ActionModel CreateActionModel(TypeInfo typeInfo, MethodInfo methodInfo)
{if (typeInfo == null){throw new ArgumentNullException(nameof(typeInfo));}if (methodInfo == null){throw new ArgumentNullException(nameof(methodInfo));}if (!IsAction(typeInfo, methodInfo)){return null;} ......
}
到了这个方法里面,我们找到了如何确定一个方法为Action方法的源头,由于该方法有点长,这里我采用文字叙述来作为判断逻辑,如下:
protected virtual bool IsAction(TypeInfo typeInfo, MethodInfo methodInfo)
{//如果有属性访问器(无效)//如果有NonAction特性标识无效)//如果重写Equals(Object), GetHashCode()方法(无效)//如果实现Dispose方法(无效)//如果是静态方法(无效)//如果是抽象方法(无效)//如果是构造函数(无效)//如果是泛型方法(无效)//必须为公共方法return methodInfo.IsPublic;
}
如上是从方法定义的角度来过滤而获取Action方法,除此之外,我们请求方法的名称还可以自定义,比如通过路由、ActionName特性指定,那么二者是否存在优先级呢?比如如下示例:
[ApiController]
[Route("[controller]/[action]")]
public class WeatherController : ControllerBase
{[HttpGet][ActionName("get1")]public string get(){var routeValue = HttpContext.Request.RouteValues.FirstOrDefault();return routeValue.Value.ToString();}
}
我们可以看到此时将以ActionName特性作为方法名称。所以在上述过滤方法定义后开始构建方法模型,在此之后还会再做一步操作,那就是查找该方法是否通过ActionName特性标识,若存在则以ActionName特性标识给定的名称作为请求方法名称,否则以方法定义名称为准,源码如下:
var actionModel = new ActionModel(methodInfo, attributes);AddRange(actionModel.Filters, attributes.OfType<IFilterMetadata>());var actionName = attributes.OfType<ActionNameAttribute>().FirstOrDefault();
if (actionName?.Name != null)
{actionModel.ActionName = actionName.Name;
}
else
{actionModel.ActionName = methodInfo.Name;
}
还没完,若是将路由特性放到Action方法上,如下,此时请求接口应该是weather/get还是weather/get1呢?
[ApiController]
public class WeatherController : ControllerBase
{[HttpGet][Route("weather/get")][ActionName("get1")]public string get(){var routeValue = HttpContext.Request.RouteValues.FirstOrDefault();return routeValue.Value.ToString();}
}
此时若我们以weather/get1请求将出现404,还是以路由特性模板给定为准进行请求,但最终会将路由上Action方法名称通过ActionName特性上的名称赋值给Action模型中的ActionName进行覆盖,源码如下,所以上述我们得到的action名称为get1,当然这么做没有任何实际意义。
public static void AddRouteValues(
ControllerActionDescriptor actionDescriptor,
ControllerModel controller,ActionModel action)
{foreach (var kvp in action.RouteValues){if (!actionDescriptor.RouteValues.ContainsKey(kvp.Key)){actionDescriptor.RouteValues.Add(kvp.Key, kvp.Value);}}if (!actionDescriptor.RouteValues.ContainsKey("action")){actionDescriptor.RouteValues.Add("action", action.ActionName ?? string.Empty);}if (!actionDescriptor.RouteValues.ContainsKey("controller")){actionDescriptor.RouteValues.Add("controller", controller.ControllerName);}
}
本文我们只是单独针对查找Action方法名称匹配问题做了进一步的探讨,了解其本质。根据源码分析,对Acion方法名称指定会做以下3步操作:
第一:根据方法定义进行过滤筛选
第二:若方法通过AcionName特性标识则以其所给名称为准,否则以方法名称为准,最终赋值给ActionModel上的ActionName属性
第三:将ActionModel上的ActionName值赋值给路由集合中的键Action
.NET Core请求控制器Action方法正确匹配,但为何404?相关推荐
- ASP.NET Core WebAPI控制器返回类型的最佳选项
ASP.NET Core WebAPI控制器返回类型的最佳选项 原文:ASP.NET Core WebAPI控制器返回类型的最佳选项 前言 从.NET Core 2.1版开始,到目前为止,控制器操作可 ...
- 自动化CodeReview - ASP.NET Core请求参数验证
自动化CodeReview系列目录 自动化CodeReview - ASP.NET Core依赖注入 自动化CodeReview - ASP.NET Core请求参数验证 参数验证实现 在做服务端开发 ...
- 4.1ASP.NET Core请求过程「深入浅出ASP.NET Core系列」
原文:4.1ASP.NET Core请求过程「深入浅出ASP.NET Core系列」 希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,谢谢关注. HTTP请求过程 这里展示整 ...
- Springboot如何利用http请求控制器
写好了接口,现在想用postman测试一下这个接口是否正确,想请问怎么传入请求参数?先谢谢了! Springboot如何利用http请求控制器 >> java 这个答案描述的挺清楚的: h ...
- ThinkPHP6项目基操(4.拦截无效请求 控制器或方法不存在)
拦截无效请求 控制器或方法不存在 一.默认无效请求 二.显示具体错误信息 方法1.配置`config/app.php` 方法2. 配置`.env`环境变量 三.处理错误 1. 方法不存在 2. 控制器 ...
- 面试官:如何在ASP.NET Core里给Action传递参数
TIP:这篇文章属于入门级的文章,面向的读者是刚刚接触.NET Core的开发人员. 在ASP.NET Core 中给Action传参是在面试和实际开发中必定会遇到和使用到的,那么下面我们就来说说如何 ...
- ASP.NET Core MVC 源码学习:详解 Action 的匹配
前言 在 上一篇 文章中,我们已经学习了 ASP.NET Core MVC 的启动流程,那么 MVC 在启动了之后,当请求到达过来的时候,它是怎么样处理的呢? 又是怎么样把我们的请求准确的传达到我们的 ...
- asp.net mvc 使用ajax请求 控制器 (PartialViewResult)分部的action,得到一个分部视图(PartialView)的HTML,进行渲染...
在asp.net mvc 使用ajax请求获取数据的时候,我们一般是返回json或者xml,然后解析这些数据进行渲染,这样会比较麻烦,可以请求一个 分部action,返回一个分部视图 直接可以渲染,不 ...
- SpringMVC 学习系列 (3) 之 URL请求到Action的映射规则
2019独角兽企业重金招聘Python工程师标准>>> 在系列(2)中我们展示了一个简单的get请求,并返回了一个简单的helloworld页面.本篇我们来学习如何来配置一个acti ...
最新文章
- PostgreSQL 编译安装
- 分享13个帮助你简化开发的jQuery插件
- 从源码分析DEARGUI之动态绘图的两种方法
- htc desire 10 pro android 8.0,HTC Desire 10 pro手机:可能是Desire系列最好的手机
- mybatisgenerator使用_如何优雅地使用MyBatisplus
- Exception in thread “main“ java.io.FileNotFoundException: C:\Temp (拒绝访问。)
- usbserialcontroller驱动安装不了_win10-有NVIDIA独显提示未安装控制面板的离线安装方式...
- python自己创建模块引用失败_详解Python import方法引入模块的实例 Python怎么import自己写的模块...
- UI实用素材|登录和个人资料界面模板
- Android Studio中 no module 问题,解决方法
- Mapx自带的工具的理解
- arcolinux使用i3wm窗口管理器
- html页面点击生成图片并可以下载图片
- vga转换html转换器接线,绿联HDMI转VGA转换器拆解测评
- linux查看nas剩余大小,老徐玩NAS 篇二:我的群晖储存空间哪儿去了——100%破案的教程...
- 华为认证云服务架构专家正式发布!
- HDU 6447 YJJ's Salesman
- flag{e2f34a3a-9972-4ba5-bdeb-ff7d524d87cb} preg_match implode
- mysql 计算工作日_MySQL函数查找两个日期之间的工作日数
- LVDS接口和LVDS技术