ASP.NET Core MVC 是官方推荐的、开箱即用的 MVC 实现,不是靠手写三个类模拟出来的“伪 MVC”。直接用框架,别自己造轮子。
为什么不用手动实现 Controller/Model/View 分层
手写
Controller基类、
IView接口、
ViewEngine解析逻辑,看似“理解本质”,实际会卡在路由绑定、模型绑定、依赖注入、生命周期管理、异步支持等底层细节上。ASP.NET Core 已把 MVC 拆成可替换的组件(如
MvcOptions、
IActionResult、
ViewResult),你只需要按约定组织代码。 控制器必须继承
Controller或
ControllerBase,方法返回
IActionResult类型 模型类只需是普通 C# 类(POCO),无需继承特定基类或打属性标记(除非需要验证) 视图文件必须放在
Views/{ControllerName}/{ActionName}.cshtml 路径下,且使用 @model声明类型
最简可行的 MVC 三件套写法
以一个显示用户列表的场景为例,不引入数据库或服务层,聚焦结构本身:
@* Views/Home/Index.cshtml *@
@model List<User>
<p><h2>用户列表</h2>
<ul>
@foreach (var user in Model)
{
<li>@user.Name (@user.Email)</li>
}
</ul>// Controllers/HomeController.cs
public class HomeController : Controller
{
public IActionResult Index()
{
var users = new List<User>
{
new User { Name = "张三", Email = "zhang@example.com" },
new User { Name = "李四", Email = "li@example.com" }
};
return View(users); // 自动查找 Views/Home/Index.cshtml
}
}// Models/User.cs
public class User
{
public string Name { get; set; }
public string Email { get; set; }
}常见踩坑点:View 和 Controller 不匹配
错误现象:
The view 'Index' was not found.或
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Collections.Generic.List`1[MyApp.Models.User]', but this ViewDataDictionary instance requires a model item of type 'MyApp.Models.User'.
return View(users)传的是
List<user></user>,但视图里写了
@model User→ 必须改成
@model List<user></user>视图文件名拼错,比如写成
Index.cshtm(少了个 l)或放在
Views/Shared/Index.cshtml却没加
[ViewLocationFormats](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.razor.razorviewengineoptions.viewlocationformats)配置 控制器方法名不是
public IActionResult Index(),而是
public void Index()→ 框架无法识别为 Action,也不会触发视图查找
需要自定义行为时,优先扩展而非重写
比如想统一处理未授权请求,不要重写整个
Controller基类,而是用过滤器:
// Filters/RequireAuthFilter.cs
public class RequireAuthFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
if (!context.HttpContext.User.Identity.IsAuthenticated)
{
context.Result = new RedirectToActionResult("Login", "Account", null);
}
}
}然后在控制器上加
[TypeFilter<requireauthfilter>]</requireauthfilter>,或全局注册到
services.AddControllersWithViews(options => options.Filters.Add<requireauthfilter>());</requireauthfilter>
真正难的从来不是“怎么分三层”,而是路由怎么配、模型绑定怎么调、ViewComponent 怎么复用、TagHelper 怎么写——这些才是日常高频问题。MVC 结构只是骨架,血肉全在配置和约定里。
