ASP.NET Core应用程序4:控制器和视图(一)

1 准备工作

添加包:dotnet add package Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation --version 3.1.1

2 开始使用视图

2.1 配置应用程序

HTML响应是使用视图创建的,视图则是混合了HTML元素和C#表达式的文件。
配置Startup来启用HTML响应。

services.AddControllersWithViews().AddRazorRuntimeCompilation();

之前使用AddController方法来启用MVC框架,但它只支持Web服务控制器。这里我们启用AddControllersWithViews方法来支持视图。使用AddRazorRuntimeCompilation方法是为了启用安装包所提供的功能,方便开发过程中使用视图。

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapControllerRoute("Default", "{controller=Home}/{action=Index}/{id?}");
});

在端点路由配置中添加了MapControllerRoute方法,默认页面的路由。

2.2 创建html控制器

    public class HomeController : Controller
    {
        private DataContext _context;

        public HomeController(DataContext ctx)
        {
            _context = ctx;
        }
        public async Task<IActionResult> Index(long id =1)
        {
            return View(await _context.Products.FindAsync(1));
        }
    }

html控制器基类是Controller,它派生自Web服务控制器ControllerBase,并提供用于视图的方法。

(1)理解约定式路由

html控制器依赖于约定式路由,而不是Route特性。约定式路由指的是使用控制器名称和操作方法名称来配置路由系统。

endpoints.MapControllerRoute("Default", "{controller=Home}/{action=Index}/{id?}");

这条语句路由分三段,前面两个指代控制器和操作方法名称,而第三段允许收到一个名为id的参数。对于不包含所有片段的URL默认值将选择Home控制器的Index方法。这个是常用配置,也可以简写为下面这样。

endpoints.MapDefaultControllerRoute();

(2)理解Razor视图约定

当操作方法调用View方法时,将创建一个ViewResult,告诉MVC框架使用默认约定来寻找视图。Razor视图引擎将寻找一个与操作方法同名、且带有cshtml文件扩展名的视图。视图保存在Views文件中,按照关联的控制器进行分组。
因为操作方法时由Home控制器定义,所以首先搜索Views/Home文件夹。如果没有找到Index.cshtml,就检查Views/Shared文件夹,这里包含控制器之间的共享视图。

2.3 创建Razor视图

在Views/Home目录下创建Index.cshtml视图。

<!DOCTYPE html>
<html>
<head>
    <link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
    <h6 class="bg-primary text-white text-center m-2 p-2">Product Table</h6>
    <div class="m-2">
        <table class="table table-sm table-striped table-bordered">
            <tbody>
                <tr><th>Name</th><td>@Model.Name</td></tr>
                <tr><th>Price</th><td>@Model.Price.ToString("c")</td></tr>
                <tr><th>Category ID</th><td>@Model.CategoryId</td></tr>
            </tbody>
        </table>
    </div>
</body>
</html>

2.4 通过名称选择视图

通过View方法提供一个名称Watersports作为参数选择视图,同时创建Watersports.cshtml。

        public async Task<IActionResult> Index(long id = 1)
        {
            var model = await _context.Products.FindAsync(id);
            if (model.CategoryId == 1)
            {
                return View("Watersports", model);
            }
            return View(model);
        }

使用共享视图

在Views/Shared文件夹中添加一个名为Common.cshtml的Razor视图文件。

<!DOCTYPE html>
<html>
<head>
    <link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
    <h6 class="bg-secondary text-white text-center m-2 p-2">Shared View</h6>
</body>
</html>

在HomeController添加一个操作方法,它依赖于使用方法名称作为视图名称。

        public IActionResult Common()
        {
            return View();
        }

添加一个SecondController,它的一个操作方法返回View,参数使用Common。

    public class SecondController : Controller
    {
        public IActionResult Index()
        {
            return View("Common");
        }
    }

可以看到结果,http://localhost:5000/home/common和http://localhost:5000/second都显示的是Common视图。
注意:也可以不用视图引擎选择文件,而自己指定相对路径的完整路径来选择某个视图。

return View("/Views/Shared/Common.cshtml");

3 使用Razor视图

Razor视图包含html表达式和C#表达式。混杂在html元素中,用@字符表示。Razor视图将被转换为C#类,它继承自RazorPage类,像其他C#类一样被编译。
可以通过obj/Debug/netcoreapp3.1/Razor/Views文件夹下内容,看到生成的视图类。
cshtml文件中的一个片段,会被 ExecuteAsync方法转换为一系列C#语句,再把html片段和表达式的计算结果写入响应得到最终html。

<tr><th>Name</th><td>@Model.Name</td></tr>
WriteLiteral("<tr><th>Name</th><td>");
Write(Model.Name);
WriteLiteral("</td></tr>");

设置视图模型类型

为Watersports.cshtml文件生成的类派生自RazorPage<T>,但是Razor不知道操作方法为视图模型使用什么类型,所以选择了RazorPage<dynamic>作为泛型类型实参。这样即便写一个不存在的属性编译也不会报错,直到运行时才会报错。
为在开发中检查表达式,可使用model关键字指定Model对象类型。这样当生成C#类时将使用RazorPage<Product>这样作为泛型实参。

@model MyWebApp.Models.Product
<!DOCTYPE html>
......

使用视图导入文件

通过在项目中添加视图导入文件,能够指定在一组名称空间中搜索类型。视图导入文件的名称为_ViewImports.cshtml,包含在Views文件夹中。

@using MyWebApp.Models

通过使用@using表达式,并在后面加上名称空间,可以指定哪些名称空间中搜索Razor视图中使用的类,该名称空间包含Watersports.cshtml,就不用加MyWebApp.Models了。

@model Product
<!DOCTYPE html>
......

4 理解Razor语法

4.1 理解指令

指令是向Razor视图引擎发送命令的表达式。

  • @model:指定视图模型的类型;
  • @using:导入名称空间
  • @page:指示Razor Page。
  • @section:指示布局节。
  • @addTagHelper:在视图中添加标签助手。
  • @namespace:设置从视图生成C#类的名称空间。
  • @functions:向从视图生成的C#类添加属性和方法,常用于Razor Page中。
  • @attribute:向从视图生成的C#类添加特性。
  • @implements:声明从视图生成的C#类继承某个接口,或派生自某个基类。
  • @inherits:设置了从视图生成的C#类的基类。
  • @inject:使视图能通过依赖注入直接访问某个服务。

4.2 理解内容表达式

Razor内容表达式生成的内容将包含在视图生成的输出中。

  • @<expression>:这是基本的Razor表达式,其计算结果将被插入响应中。
  • @if@switch:条件表达式。
  • @foreach:为序列中每个元素生成内容。
  • @{...}:定义一个代码块。
  • @::指示没有包含在html中的内容。
  • @try:用于捕获异常。
  • @await:用于执行异步操作,结果将被插入响应中。

4.3 设置元素内容

视图可包含更复杂表达式,但要求把这些表达式放到括号内,以便区分代码和静态内容。

<tr><th>Tax</th><td>@Model.Price * 0.2m</td></tr>
<tr><th>Tax</th><td>@(Model.Price * 0.2m)</td></tr>

4.4 设置特性值

表达式可用于设置元素特性的值。

<table class="table table-sm table-striped table-bordered" data-id="@Model.ProductId">

4.5 使用条件表达式

使用@if。

@if (Model.Price > 200)
{
    <tr><th>Name</th><td>Luxury @Model.Name</td></tr>
}
else
{
    <tr><th>Name</th><td>Basic @Model.Name</td></tr>
}

使用@switch,@:前缀来处理未包含在html元素中的字面量值

<tr>
    <th>Name</th>
    <td>
        @switch (Model.Name)
        {
            case "Kayak":
                @:Small Boat       
                break;
            case "Lifejacket":
                @:Flotation Aid
                break;
            default:
                @Model.Name
                break;
        }
    </td>
</tr>

4.6 枚举序列

HomeController中添加List方法。

public IActionResult List()
{
    return View(_context.Products); 
}

添加List.cshtml.

@model IEnumerable<Product>
<!DOCTYPE html>
<html>
<head>
    <link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
    <h6 class="bg-secondary text-white text-center m-2 p-2">Products</h6>
    <div class="m-2">
        <table class="table table-sm table-striped table-bordered">
            <thead>
                <tr><th>Name</th><th>Price</th><th></th></tr>
            </thead>
            <tbody>
                @foreach (Product p in Model)
                {
                    <tr>
                        <td>@p.Name</td>
                        <td>@p.Price</td>
                    </tr>
                }
            </tbody>
        </table>
    </div>
</body>
</html>

4.7 使用Razor代码块

代码块是一段C#代码,它不生成内容,但能够为那些生成内容的表达式提供支持。

@{
    decimal average = Model.Average(a => a.Price);
}
<td>平均值的@((p.Price / average * 100).ToString("F1"))% </td>
posted @ 2024-04-24 10:42  一纸年华  阅读(22)  评论(0编辑  收藏  举报