【CSDN 专栏】C# ASP.NET Razor 视图引擎实战:.cshtml 从入门到避坑(图解 + 案例)

AI赋能编程语言挑战赛 10w+人浏览 225人参与

作为ASP.NET开发的核心环节,View 层(UI 渲染)是连接后端逻辑与前端界面的 “桥梁”,而 Razor 视图引擎(.cshtml 文件)则是这座桥梁的 “核心建材”—— 它把 C# 代码和 HTML 标签无缝融合,让开发者既能用 C# 处理业务逻辑,又能通过 HTML 构建界面。但新手在使用.cshtml 时,很容易因语法混淆、逻辑滥用、数据传递不当踩坑。本文从基础认知、代码实战、避坑指南三个维度,把 Razor 视图引擎讲透,让你写.cshtml 既高效又少出错。
在这里插入图片描述

一、先搞懂核心:Razor 视图引擎是什么?(生活类比 + 流程图)

小节:Razor = 前端界面的 “智能模板引擎”

先举个生活例子:你去奶茶店点单,店员会拿着 “点单模板”(固定格式:饮品名称 + 甜度 + 冰度 + 配料),根据你的需求填充具体内容(比如 “珍珠奶茶 + 正常糖 + 少冰 + 加椰果”),最终生成你的专属订单。
Razor 视图引擎(.cshtml)就像这个 “点单模板”:

  • 模板基础框架:HTML 标签(对应订单模板的固定格式);
  • 动态填充内容:C# 代码(对应你自定义的饮品需求);
  • 最终输出:浏览器能识别的纯 HTML 页面(对应最终的订单)。
    Razor 视图渲染流程图
Controller返回ViewResult
指定.cshtml文件路径
Razor引擎解析.cshtml
执行其中的C#代码 处理数据\逻辑
将C#执行结果嵌入HTML标签
生成纯HTML字符串
返回给浏览器渲染展示

Razor 核心语法规则(新手必记):

语法作用示例
@开启 C# 代码块 / 输出变量@Model.UserName、@(1+2)
@{ }多行 C# 代码块@{ var age = 25; if(age>18) {

成年

} }
@if/@for/@foreach流程控制(无需额外闭合符) @foreach(var item in Model.List) {
  • @item
  • }
@Model接收 Controller 传递的模型数据@model WebDemo.Models.UserDto(声明模型)
@HtmlRazor 内置辅助类(生成表单 / 链接等)@Html.TextBoxFor(m => m.Name)

二、代码实战:.cshtml 完整使用示例

小节:从 Controller 传数据到.cshtml 渲染全流程

我们以 “用户信息展示 + 新增用户表单” 为例,覆盖 Razor 最常用的场景:模型绑定、循环渲染、表单生成、条件判断。

步骤 1:定义数据模型(ViewModel)

// Models/UserDto.cs
namespace WebDemo.Models
{
    /// <summary>
    /// 用户数据模型
    /// </summary>
    public class UserDto
    {
        public int Id { get; set; }

        [Display(Name = "用户名")]
        [Required(ErrorMessage = "用户名不能为空")]
        public string UserName { get; set; }

        [Display(Name = "年龄")]
        [Range(18, 100, ErrorMessage = "年龄需在18-100之间")]
        public int Age { get; set; }

        [Display(Name = "手机号")]
        public string Phone { get; set; }
    }

    /// <summary>
    /// 用户列表页面模型
    /// </summary>
    public class UserListViewModel
    {
        public string Title { get; set; } // 页面标题
        public List<UserDto> UserList { get; set; } // 用户列表
    }
}

步骤 2:Controller 传递数据到 View

// Controllers/UserController.cs
using Microsoft.AspNetCore.Mvc;
using WebDemo.Models;

namespace WebDemo.Controllers
{
    public class UserController : Controller
    {
        // 展示用户列表页面
        public IActionResult Index()
        {
            // 模拟从数据库获取用户数据
            var userList = new List<UserDto>
            {
                new UserDto { Id = 1, UserName = "张三", Age = 28, Phone = "13800138000" },
                new UserDto { Id = 2, UserName = "李四", Age = 32, Phone = "13900139000" },
                new UserDto { Id = 3, UserName = "王五", Age = 25, Phone = "13700137000" }
            };

            // 封装页面模型
            var viewModel = new UserListViewModel
            {
                Title = "系统用户列表",
                UserList = userList
            };

            // 将模型传递给View
            return View(viewModel);
        }

        // 新增用户表单页面
        [HttpGet]
        public IActionResult Add()
        {
            return View(new UserDto()); // 传递空模型,用于表单绑定
        }

        // 提交新增用户数据
        [HttpPost]
        public IActionResult Add(UserDto user)
        {
            if (!ModelState.IsValid)
            {
                // 模型验证失败,返回表单页面并显示错误
                return View(user);
            }

            // 模拟保存用户数据到数据库
            return RedirectToAction("Index");
        }
    }
}

步骤 3:编写.cshtml 视图文件(核心)

1. 用户列表页面(Index.cshtml)
@* 声明页面接收的模型类型(必须放在第一行) *@
@model WebDemo.Models.UserListViewModel

@{
    // 多行C#代码块:定义页面变量、处理逻辑
    ViewData["Title"] = Model.Title; // 设置页面标题(兼容传统ViewData方式)
    var adultCount = Model.UserList.Count(u => u.Age >= 18); // 统计成年用户数
}

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewData["Title"]</title>
    <style>
        table { border-collapse: collapse; width: 80%; margin: 20px auto; }
        th, td { border: 1px solid #ccc; padding: 8px; text-align: center; }
        th { background-color: #f5f5f5; }
        .adult { color: green; font-weight: bold; }
        .teen { color: red; }
    </style>
</head>
<body>
    <h1 style="text-align: center;">@Model.Title</h1>
    <p style="text-align: center;">成年用户数量:<span class="adult">@adultCount</span> / 总用户数:@Model.UserList.Count</p>

    <table>
        <tr>
            <th>ID</th>
            <th>用户名</th>
            <th>年龄</th>
            <th>手机号</th>
            <th>状态</th>
        </tr>
        @* 循环渲染用户列表 *@
        @foreach (var user in Model.UserList)
        {
            <tr>
                <td>@user.Id</td>
                <td>@user.UserName</td>
                <td>@user.Age</td>
                <td>@user.Phone</td>
                <td>
                    @* 条件判断 *@
                    @if (user.Age >= 18)
                    {
                        <span class="adult">成年</span>
                    }
                    else
                    {
                        <span class="teen">未成年</span>
                    }
                </td>
            </tr>
        }
    </table>

    <div style="text-align: center; margin-top: 20px;">
        @* Razor辅助类生成链接 *@
        @Html.ActionLink("新增用户", "Add", "User", null, new { style = "text-decoration: none; color: white; background-color: #007bff; padding: 8px 16px; border-radius: 4px;" })
    </div>
</body>
</html>

2. 新增用户表单页面(Add.cshtml)

@model WebDemo.Models.UserDto

@{
    ViewData["Title"] = "新增用户";
}

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewData["Title"]</title>
    <style>
        .form-container { width: 50%; margin: 20px auto; }
        .form-group { margin-bottom: 15px; }
        label { display: inline-block; width: 100px; }
        input { width: 300px; padding: 5px; }
        .error { color: red; font-size: 12px; margin-left: 105px; }
        button { padding: 8px 20px; background-color: #28a745; color: white; border: none; border-radius: 4px; cursor: pointer; }
    </style>
</head>
<body>
    <div class="form-container">
        <h2>新增用户</h2>
        @* Razor辅助类生成表单(自动绑定模型) *@
        @using (Html.BeginForm("Add", "User", FormMethod.Post))
        {
            <div class="form-group">
                @* 生成标签 + 输入框 + 验证错误提示 *@
                @Html.LabelFor(m => m.UserName)
                @Html.TextBoxFor(m => m.UserName, new { placeholder = "请输入用户名" })
                @Html.ValidationMessageFor(m => m.UserName, "", new { @class = "error" })
            </div>

            <div class="form-group">
                @Html.LabelFor(m => m.Age)
                @Html.TextBoxFor(m => m.Age, new { placeholder = "请输入年龄" })
                @Html.ValidationMessageFor(m => m.Age, "", new { @class = "error" })
            </div>

            <div class="form-group">
                @Html.LabelFor(m => m.Phone)
                @Html.TextBoxFor(m => m.Phone, new { placeholder = "请输入手机号" })
                @Html.ValidationMessageFor(m => m.Phone, "", new { @class = "error" })
            </div>

            <div class="form-group">
                <button type="submit">提交</button>
            </div>
        }

        <div>
            @Html.ActionLink("返回列表", "Index", "User")
        </div>
    </div>

    @* 引入验证脚本(必须加,否则客户端验证不生效) *@
    @Scripts.Render("~/bundles/jqueryval")
</body>
</html>

步骤 4:运行效果

1.访问/User/Index:展示用户列表,统计成年用户数,支持条件渲染用户状态;
2.点击 “新增用户”:跳转到表单页面,输入不符合规则的内容(如年龄 17),提交后会显示验证错误;
3.输入合法数据提交:跳回用户列表页面。

三、常踩的坑(附解决方案 + 生活类比)

小节:避开这些坑,.cshtml 开发不踩雷

新手写.cshtml 最容易踩以下 7 个坑,每个坑都配生活类比和解决方案:

坑点生活类比解决方案
1.忘记声明 @model 或声明位置错误奶茶店店员拿到订单模板,却没看模板要求的填写格式,导致填错内容1. @model必须放在.cshtml 第一行;2. 模型类型要写完整命名空间(如@model WebDemo.Models.UserListViewModel);3. 区分@model(声明类型)和@Model(使用实例)的大小写
2.C# 代码与 HTML 混写时语法错误(如缺少 @、大括号不匹配)写作文时中英文标点混用、段落没有闭合,导致读者看不懂1. 单行输出变量必须加@(如@user.Name);2. 多行 C# 代码必须用@{ }包裹;3. 流程控制(if/for)后直接跟 HTML,无需额外闭合符;4. 使用 VS 的语法高亮和错误提示排查
3.模型验证不生效(客户端无提示)奶茶店设置了 “甜度只能选正常 / 少糖 / 无糖”,但顾客选了 “超甜” 却没提示,直到结账才发现1. 确保模型加了验证特性(如[Required]);2. 表单页面引入验证脚本@Scripts.Render(“~/bundles/jqueryval”);3. Controller 中判断ModelState.IsValid
4.循环渲染时复用变量导致数据错乱店员给多个顾客点餐时,把上一个顾客的配料写到下一个订单里1. 循环内变量命名唯一(如foreach(var user in Model.UserList)中的user);2. 避免在循环外定义临时变量供循环内使用;3. 复杂循环可拆分为局部视图(PartialView)
5.滥用 C# 逻辑(把业务逻辑写在.cshtml)奶茶店店员不只是填订单,还自己决定奶茶的配方、定价(越权)1. .cshtml 只做 “数据展示 + 简单逻辑”(如条件 / 循环);2. 复杂业务逻辑(如数据过滤、计算)放在 Controller/Service 层;3. 可使用 ViewBag/ViewData 传递简单临时数据,复杂数据用 ViewModel
6.静态资源(CSS/JS)路径错误顾客按地址找奶茶店,却因地址写错找不到1. 使用~表示网站根目录(如);2. 避免相对路径(如…/css/style.css),尤其是多级目录的视图;3. 配置静态文件中间件(app.UseStaticFiles())
7.PartialView(局部视图)传参失败餐厅把凉菜的配料单传给后厨,但传错了单子,导致凉菜做错1. 渲染局部视图时指定模型:@Html.Partial(“_UserItem”, user);2. 局部视图声明@model接收参数;3. 避免在局部视图中使用 ViewData/ViewBag(易受父视图影响)
坑点实战示例(解决 “静态资源路径错误”)
错误写法(相对路径,多级目录视图会失效):
<link href="../css/style.css" rel="stylesheet" />

正确写法(根路径,适配所有视图目录):

<link href="~/css/style.css" rel="stylesheet" />

同时确保Program.cs中配置静态文件中间件:

var app = builder.Build();

// 启用静态文件(必须加,否则无法访问CSS/JS/图片)
app.UseStaticFiles();

app.UseRouting();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

四、总结

Razor 视图引擎(.cshtml)是ASP.NET View 层的核心,其核心价值是 “动静结合”—— 用 HTML 构建界面骨架,用 C# 填充动态数据。新手掌握 “模型绑定、语法规则、数据渲染” 三大核心,避开 “语法错误、逻辑滥用、路径错误” 等坑,就能写出清晰、易维护的视图代码。
记住一个原则:.cshtml 的职责是 “展示数据”,而不是 “处理数据”,把业务逻辑交给 Controller/Service 层,视图只做最精简的渲染逻辑,这是保证项目可维护性的关键。

留言互动
你在项目中用.cshtml 实现过哪些复杂场景?(比如分页、表格筛选、动态表单等)有没有遇到过本文没提到的坑?欢迎在评论区分享你的解决方案,一起交流进阶技巧~
专栏说明: 本文聚焦 Razor 视图引擎核心实战,后续会更新 PartialView(局部视图)、ViewComponent(视图组件)、Razor Pages 等进阶内容,关注我,持续解锁ASP.NET View 层干货~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值