【导读】提前预祝各位端午节快乐有时候我们会发现方法名称都正确匹配,但就是找不到对应请求接口,所以本文我们来深入了解下何时会出现接口请求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?相关推荐

  1. ASP.NET Core WebAPI控制器返回类型的最佳选项

    ASP.NET Core WebAPI控制器返回类型的最佳选项 原文:ASP.NET Core WebAPI控制器返回类型的最佳选项 前言 从.NET Core 2.1版开始,到目前为止,控制器操作可 ...

  2. 自动化CodeReview - ASP.NET Core请求参数验证

    自动化CodeReview系列目录 自动化CodeReview - ASP.NET Core依赖注入 自动化CodeReview - ASP.NET Core请求参数验证 参数验证实现 在做服务端开发 ...

  3. 4.1ASP.NET Core请求过程「深入浅出ASP.NET Core系列」

    原文:4.1ASP.NET Core请求过程「深入浅出ASP.NET Core系列」 希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,谢谢关注. HTTP请求过程 这里展示整 ...

  4. Springboot如何利用http请求控制器

    写好了接口,现在想用postman测试一下这个接口是否正确,想请问怎么传入请求参数?先谢谢了! Springboot如何利用http请求控制器 >> java 这个答案描述的挺清楚的: h ...

  5. ThinkPHP6项目基操(4.拦截无效请求 控制器或方法不存在)

    拦截无效请求 控制器或方法不存在 一.默认无效请求 二.显示具体错误信息 方法1.配置`config/app.php` 方法2. 配置`.env`环境变量 三.处理错误 1. 方法不存在 2. 控制器 ...

  6. 面试官:如何在ASP.NET Core里给Action传递参数

    TIP:这篇文章属于入门级的文章,面向的读者是刚刚接触.NET Core的开发人员. 在ASP.NET Core 中给Action传参是在面试和实际开发中必定会遇到和使用到的,那么下面我们就来说说如何 ...

  7. ASP.NET Core MVC 源码学习:详解 Action 的匹配

    前言 在 上一篇 文章中,我们已经学习了 ASP.NET Core MVC 的启动流程,那么 MVC 在启动了之后,当请求到达过来的时候,它是怎么样处理的呢? 又是怎么样把我们的请求准确的传达到我们的 ...

  8. asp.net mvc 使用ajax请求 控制器 (PartialViewResult)分部的action,得到一个分部视图(PartialView)的HTML,进行渲染...

    在asp.net mvc 使用ajax请求获取数据的时候,我们一般是返回json或者xml,然后解析这些数据进行渲染,这样会比较麻烦,可以请求一个 分部action,返回一个分部视图 直接可以渲染,不 ...

  9. SpringMVC 学习系列 (3) 之 URL请求到Action的映射规则

    2019独角兽企业重金招聘Python工程师标准>>> 在系列(2)中我们展示了一个简单的get请求,并返回了一个简单的helloworld页面.本篇我们来学习如何来配置一个acti ...

最新文章

  1. PostgreSQL 编译安装
  2. 分享13个帮助你简化开发的jQuery插件
  3. 从源码分析DEARGUI之动态绘图的两种方法
  4. htc desire 10 pro android 8.0,HTC Desire 10 pro手机:可能是Desire系列最好的手机
  5. mybatisgenerator使用_如何优雅地使用MyBatisplus
  6. Exception in thread “main“ java.io.FileNotFoundException: C:\Temp (拒绝访问。)
  7. usbserialcontroller驱动安装不了_win10-有NVIDIA独显提示未安装控制面板的离线安装方式...
  8. python自己创建模块引用失败_详解Python import方法引入模块的实例 Python怎么import自己写的模块...
  9. UI实用素材|登录和个人资料界面模板
  10. Android Studio中 no module 问题,解决方法
  11. Mapx自带的工具的理解
  12. arcolinux使用i3wm窗口管理器
  13. html页面点击生成图片并可以下载图片
  14. vga转换html转换器接线,绿联HDMI转VGA转换器拆解测评
  15. linux查看nas剩余大小,老徐玩NAS 篇二:我的群晖储存空间哪儿去了——100%破案的教程...
  16. 华为认证云服务架构专家正式发布!
  17. HDU 6447 YJJ's Salesman
  18. flag{e2f34a3a-9972-4ba5-bdeb-ff7d524d87cb} preg_match implode
  19. mysql 计算工作日_MySQL函数查找两个日期之间的工作日数
  20. LVDS接口和LVDS技术

热门文章

  1. iOS SQLite函数总结
  2. [tools]notepad++当前文件路径不是工作路径
  3. (译)如何使用cocos2d制作基于tile地图的游戏教程:第一部分
  4. 智能记忆功能nest_如何设置和安装Nest Protect智能烟雾报警器
  5. html 替代table,Iframe的缺点,div或者table成为替代者
  6. zookeeper学习03 使用场景
  7. 基于DeepConvLSTM的传感器信号分类
  8. python之新式类与经典类
  9. 美国银行将AI应用于企业应收账款处理
  10. Vagrant搭建可移动的PHP开发环境