ASP.NET Core应用程序5:控制器和视图(二)
1 准备工作
在Startup中启用会话配置。
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.Cookie.IsEssential = true;
});
app.UseSession();
2 使用ViewBag
操作方法使用视图模型提供数据,但有时还需额外信息。可以使用ViewBag提供额外数据。
public async Task<IActionResult> Index(long id = 1)
{
ViewBag.AveragePrice = await _context.Products.AverageAsync(a=>a.Price);
var model = await _context.Products.FindAsync(id);
return View(model);
}
ViewBag属性是从Controller基类继承来的,它返回一个dynameic对象。可以在视图中访问操作方法赋给ViewBag的值。
<tr>
<th>Price</th>
<td>
@Model.Price.ToString("c")
平均值的@((Model.Price / ViewBag.AveragePrice * 100).ToString("F2"))%
</td>
</tr>
3 使用TempData
添加CubedController。
public class CubedController : Controller
{
public IActionResult Index()
{
return View("Cubed");
}
public IActionResult Cube(double num)
{
TempData["value"] = num.ToString();
TempData["result"] = Math.Pow(num, 3).ToString();
return RedirectToAction(nameof(Index));
}
}
定义了一个Index方法返回Cubed视图。Cube方法执行计算,将结果值保存到TempData中,该属性用来存储键值对。当把值存储为临时数据后,Cube方法重定向到Index方法。
在Views/Shard文件夹下添加Cubed.cshtml。
<!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">Cubed</h6>
<form method="get" action="/cubed/cube" class="m-2">
<div class="form-group">
<label>Value</label>
<input name="num" class="form-control" value="@(TempData["value"])" />
</div>
<button class="btn btn-primary" type="submit">Submit</button>
</form>
@if (TempData["result"] != null)
{
<div class="bg-info text-white m-2 p-2">
@TempData["value"]的立方是 @TempData["result"]
</div>
}
</body>
</html>
在本例中使用临时数据设置了一个input元素内容,并显示一个结果摘要。读取一个临时数据并不会立刻删除,同一个视图中就可以重复读取值,只有当处理请求完成后,才会删除标记的值。
4 使用布局
示例视图包含重复元素,为了避免这种重复,Razor支持布局,可通过将公共内容放到一个文件中供视图使用。
通常把布局放到Views/Shared文件夹下。添加_Layout.cshtml。
<!DOCTYPE html>
<html>
<head>
<link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div>
<h6 class="bg-primary text-white text-center m-2 p-2">共享视图</h6>
@RenderBody()
</div>
</body>
</html>
布局包含了供多个视图使用的公共内容。每个视图所特有的内容是通过@RenderBody()方法插入响应,RazorPage
在Views/Home/Index.cshtml中使用布局。
@model Product
@{
Layout = "_Layout";
}
<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")
(平均值的@((Model.Price / ViewBag.AveragePrice * 100).ToString("F2"))%)
</td>
</tr>
<tr><th>Category ID</th><td>@Model.CategoryId</td></tr>
<tr><th>SupplierId</th><td>@Model.SupplierId</td></tr>
</tbody>
</table>
</div>
4.1 使用ViewBag配置布局
视图可为布局提供数据值,从而允许定制视图提供的公共内容。ViewBag属性是在选择布局的代码块中定义的。
@{
Layout = "_Layout";
ViewBag.Title = "产品表";
}
在_Layout.cshtml中用ViewBag。
<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title</title>
<link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div>
<h6 class="bg-primary text-white text-center m-2 p-2">
@(ViewBag.Title ?? "共享视图")
</h6>
@RenderBody()
</div>
</body>
</html>
4.2 使用ViewStart文件
不必在每个视图中设置Layout属性,而是可以在项目中添加一个ViewStart文件,用来提供默认的Layout值。在Views文件下添加_ViewStart.cshtml。
@{
Layout = "_Layout";
}
从Views/Shared文件夹的Common.cshtml文件中删除布局包含内容。
<h6 class="bg-secondary text-white text-center m-2 p-2">共享视图</h6>
4.3 覆盖默认布局
在两种情况下,即使在项目中定义了_ViewStart文件,也可能需要在视图中定义Layout属性。
第一种情况,视图需要的布局和_ViewStart指定的布局不同。在Views/Shared文件夹下添加一个_ImportantLayout.cshtml布局文件。
<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title</title>
<link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div>
<h6 class="bg-primary text-white text-center m-2 p-2">
重要布局
</h6>
@RenderBody()
</div>
</body>
</html>
在Views/Home/Index.cshtm中使用特定布局。Layout将被视图中的值覆盖,从而允许应用不同的布局。
@model Product
@{
Layout = "_ImportantLayout";
//Layout = Model.Price > 100 ? "_ImportantLayout":"_Layout";
ViewBag.Title = ViewBag.Title ?? "产品表";
}
第二种情况,视图包含一个完整的html文件,并不需要一个布局,可将Layout值设置为null。
@{
Layout = null;
}
4.4 使用布局节
视图引擎支持节的概念,从而允许在布局内提供区域内容。
在Home/Index.cshtml中定义节。
}
@section Header{
产品信息
}
<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>
@section Footer{
(平均值的@((Model.Price / ViewBag.AveragePrice * 100).ToString("F2"))%)
}
使用@RenderSection表达式在布局内应用节,应用布局时@RenderSection把指定节内容插入响应,没有包含再节内的由方法插入响应。如果定义了节但布局中没有使用将会报错。
修改_Layout.cshtml文件中使用节。
<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title</title>
<link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="bg-info text-white m-2 p-2">
这是布局的一部分
</div>
<h6 class="bg-primary text-white text-center m-2 p-2">
@RenderSection("Header")
</h6>
<div class="bg-info text-white m-2 p-2">
这是布局的一部分
</div>
<div class="m2">
<table class="table table-sm table-striped table-bordered" data-id="@Model.ProductId">
<tbody>
@RenderBody();
</tbody>
</table>
</div>
<div class="bg-info text-white m-2 p-2">
这是布局的一部分
</div>
<h6 class="bg-primary text-white text-center m-2 p-2">
@RenderSection("Footer")
</h6>
<div class="bg-info text-white m-2 p-2">
这是布局的一部分
</div>
</body>
</html>
节允许视图向布局提供内容片段,而不指定如何使用他们。以下把body和节合并到一个html表格中。
<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title</title>
<link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="m2">
<table class="table table-sm table-striped table-bordered">
<thead>
<tr>
<th class="bg-primary text-white text-center" colspan="2">
@RenderSection("Header")
</th>
</tr>
</thead>
<tbody>
@RenderBody();
</tbody>
<tfoot>
<tr>
<th class="bg-primary text-white text-center" colspan="2">
@RenderSection("Footer")
</th>
</tr>
</tfoot>
</table>
</div>
</body>
</html>
(1)使用可选布局节
@RenderSection第二个实参,只有当视图定义了该节时才渲染该节。
@RenderSection("Header",false)
(2)测试布局节
IsSectionDefined用于判断是否定义了指定节。以下如果没有定义则渲染后备内容。
@if (IsSectionDefined("Summary"))// 判断视图是否定义了节
{
@RenderSection("Summary", false)
}
else
{
<div class="bg-info text-center text-white m-2 p-2">
这是默认摘要
</div>
}
5 使用分部视图
5.1 启动分部视图
通过标签助手可以应用分部视图。
在_ViewImports.cshtml中启用标签助手。
@using MyWebApp.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
5.2 创建分部视图
分部视图也是.cshtml文件,只是使用方式与标准视图区分开。
在Home文件夹下创建_RowPartial.cshtml。
@model Product
<tr>
<td>@Model.Name</td>
<td>@Model.Price</td>
</tr>
5.3 应用分部视图
通过在另一个视图或布局中添加partial元素,可以应用分部视图。
在Home/List.cshtml中使用。
<thead>
<tr><th>Name</th><th>Price</th><th>平均占比</th></tr>
</thead>
<tbody>
@foreach (Product p in Model)
{
<partial name="_RowPartial" model="p" />
}
</tbody>
注:早期版本中使用@Html.Partial("_RowPartial"),现在仍然支持。
(0)使用表达式选择分部视图模型
for特性使用一个应用到视图模型的表达式,设置分部视图模型。
在Views/Home文件夹下添加_CellPartial.cshtml。
@model string
<td class="bg-info text-white" >@Model</td>
在_RowPartial.cshtml中使用。
@model Product
<tr>
@*<td>@Model.Name</td>*@
<partial name="_CellPartial" for="Name" />
<td>@Model.Price</td>
</tr>
6 理解内容编码
Razor视图为内容提供了两种有用功能。html内容编码确保了表达式响应不会修改发送给浏览器的响应结构。json编码功能将对像编码为json并将其插入响应中。
6.1 理解html编码
在HomeController中添加一个方法。
public IActionResult Html()
{
return View((object)"this is a <h3><i>string</i></h3>");
}
在Views/Home文件夹中添加Html.cshtml。
@model string
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="bg-secondary text-white text-center m-2 p-2">@Model</div>
<div class="bg-secondary text-white text-center m-2 p-2">@Html.Raw(Model)</div>
</body>
</html>
调用@Html.Raw(Model),它返回对象实现了IHtmlHeper接口,模型字符串将会被浏览器解释为html一部分。
6.2 理解json编码
在Index.cshtml中使用json编码
@section Summary {
<div class="bg-info text-white m-2 p-2">
@Json.Serialize(Model)
</div>
}
Json属性返回IJsonHelper接口的一个实现,@Json.Serialize(Model)生成对象的json表示。
本文来自博客园,作者:一纸年华,转载请注明原文链接:https://www.cnblogs.com/nullcodeworld/p/18154568