【导读】提前预祝各位端午节快乐有时候我们会发现方法名称都正确匹配,但就是找不到对应请求接口,所以本文我们来深入了解下何时会出现接口请求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. Matlab心得及学习方法(不断更新)
  2. hdfs.DFSClient: Exception in createBlockOutputStre
  3. 【单页应用】全局控制器app应该干些什么?
  4. Review meeting还开不开?
  5. SQL Server 2005中, 创建维护计划时出现错误信息: 创建维护计划 失败
  6. oracle11g里sqldeveloper不能打开的问题
  7. 博客新家(agiledon.github.com)
  8. matlab find
  9. LeetCode: Merge k Sorted Lists
  10. canvas 粒子效果 - 手残实践纪录
  11. RecycleView添加适配器的监听事件
  12. 如何格式化电脑_如何将c盘格式化,垃圾文件太多,不知道怎么办
  13. 大数据之-Hadoop3.x_Yarn_基础架构---大数据之hadoop3.x工作笔记0141
  14. AR引擎vuforia源码分析、中文注释(2)用手势控制来与模型简单交互
  15. 台式机XP系统调节屏幕亮度
  16. mysql备份命令_mysql命令行备份方法
  17. 在到达胜利之前无法回头
  18. 毒品犯罪论文的英文文献去哪找?
  19. 已解决error: Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft C++ Build Tools“:
  20. liteos中sem的使用

热门文章

  1. TP框架表单验证 【包含ajax方法】
  2. 媒体层图形技术之AssetsLibrary 学习笔记
  3. 用AzureFunction开发最简单的Teams Bot
  4. excel导入csv文件_如何将包含以0开头的列的CSV文件导入Excel
  5. twitter api使用_使用P2创建自己的Twitter风格的组博客
  6. MATLAB中求矩阵非零元的坐标
  7. [转]Multiple outputs from T4 made easy
  8. SqlDataReader对象的NextResult方法读取存储过程多个结果集
  9. [转]让Linux的tty界面支持中文
  10. js 操作cookies 方法