asp net core mvc
ASP.NET Core MVC 的请求管道里,一个 HTTP 请求从进入 Kestrel 到最终输出响应,中间要穿过路由、中间件、过滤器、动作方法、模型绑定、视图渲染这几道关卡。很多人写了半年控制器,仍然说不清 app.UseRouting() 和 app.UseEndpoints() 之间到底发生了什么。这不是小问题——搞不清楚执行顺序,排查 404 或者授权失效时就只能靠猜。
先看一个具体的例子。假设你在 Startup.cs 里写了这么一段:
app.UseAuthentication(); app.UseAuthorization(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{ controller=Home}/{ action=Index}/{ id?}"); }); 这段代码能跑,但认证和授权中间件放在路由之前,意味着它们对所有请求生效,包括静态文件。静态文件请求也要走一遍认证逻辑,白白浪费性能。正确的顺序是 UseRouting 在前,UseAuthentication 和 UseAuthorization 在后,UseEndpoints 收尾。路由先确定请求该交给哪个端点,认证和授权再针对性地处理。顺序错了,功能可能还在,但效率和行为都会出偏差。
控制器里的 Action 方法不是直接执行的。请求到达 Action 之前,框架会依次触发授权过滤器、资源过滤器、动作过滤器、异常过滤器、结果过滤器。这个顺序是固定的,但很多人把逻辑塞进构造函数或者 OnActionExecuting 里,结果发现 HttpContext.User 还是空的。原因很简单——认证中间件还没跑完,你就想拿用户信息,当然拿不到。
模型绑定这块也容易踩坑。表单提交一个 DateTime 类型的字段,浏览器发过来的是字符串,绑定时依赖当前线程的区域设置。服务器区域设置和用户浏览器不一致,日期解析就可能失败或者错位。我见过一个项目,开发环境用 en-US,部署到 zh-CN 的服务器上,03/04/2024 直接被解析成 3 月 4 日,而用户以为是 4 月 3 日。加一个 [DataType(DataType.Date)] 或者自定义 IModelBinder 就能解决,但不知道问题根源的话,改起来很痛苦。
视图渲染阶段,_ViewStart.cshtml 和 _ViewImports.cshtml 的执行顺序也值得注意。_ViewStart 先于具体视图执行,用来指定布局页;_ViewImports 则负责引入命名空间和注入依赖。两者名字像,作用完全不同。有人在 _ViewImports 里写布局逻辑,发现不生效,就是因为执行时机不对。
Tag Helper 是 MVC 里被低估的功能。asp-for、asp-action、asp-controller 这些属性在编译时生成 HTML,比手写 href 和 name 属性可靠得多。改路由规则时,Tag Helper 自动跟着变,手写的链接就断了。但 Tag Helper 的智能提示依赖 _ViewImports.cshtml 里的 @addTagHelper 指令,漏写这一行,Visual Studio 里就没有提示,很多人以为是工具坏了。
依赖注入在控制器里的用法也有讲究。构造函数注入是标准做法,但有人图省事用 HttpContext.RequestServices.GetService<T>(),这等于把服务定位器模式又请回来了。控制器构造函数注入配合 AddScoped、AddTransient 的生命周期管理,才是框架设计的本意。生命周期选错,比如把 DbContext 注册成单例,并发请求下必然出问题。
ASP.NET Core MVC 的文档很全,但文档不会告诉你哪些坑最常见。上面这些点,每一个都是我实际调试过或者见别人踩过的。框架本身设计得不错,只是细节多,不亲手写几遍、不遇到几个运行时异常,很难真正记住。
(责任编辑:休闲)














