31-视图的理解
视图是用来呈现页面给用户和用户交互的地方。视图用于生成 HTML,使用 Razor 语法。
视图中使用 C# 代码:
@{
//这里面的是C#代码
ViewData["Title"] = "Home Page";
int age = 12;
}Code language: JavaScript (javascript)
然后在下面就可以使用这个 age:
<li data-target="#myCarousel" data-slide-to="3">@age</li>Code language: HTML, XML (xml)
创建视图:默认视图是靠视图引擎自动寻找,也可以直接指定视图。
public IActionResult Index()
{
//return View();//默认去HOME文件夹下面找inde视图(和action名称同名) 找不到则去shared下面
//return View("about");//默认去home下面找about视图 不区分大小写 找不则去shared
//如果在需要使用的视图是在非Home 非shared下面的 则需要制定绝对路径
return View("~/Views/User/about.cshtml");
}Code language: PHP (php)
31-视图的理解-IActionResult
ActionResult 的理解:这里用到了接口、多态,也就是统一返回的都是 IActionResult 的实现类。就比如我们的这个 View() 方法,返回的是 ViewResult。
它们的关系:
ViewResult : ActionResult : IActionResultViewResult最后会呈现视图,也就是输出 HTML 代码
返回 JSON 对象(ajax 的时候经常用到):
//return new JsonResult(1);
//return Json(1);
return Json(new { Age = 12, Name = "特朗普" });Code language: JavaScript (javascript)
返回内容:
//content.Content = "中国必胜";
//return content;
return Content("<div>中国必胜</div>"); //里面的html标签 不会解析的 直接转义输出Code language: JavaScript (javascript)
其他的一些 xxxxResult。
32-action给视图传递数据-1
直接通过 View(model) 视图指定 @model。有一类模型叫视图模型 ViewModel,上面叫强类型视图。下面我们还有一种叫弱类型视图。
var person = new Person();
person.Name = "腊肠";
//return View(person); 这个person传到视图 但是没有index的视图
return View("~/Views/User/about.cshtml", person);Code language: JavaScript (javascript)
视图代码:
@model ViewDemo.Controllers.Person
@{
ViewData["Title"] = "About";
}
<h2>@ViewData["Title"]</h2>
<h3>@ViewData["Message"]</h3>
<p>Use this area to provide additional information.</p>
<div>@Model.Name</div>Code language: HTML, XML (xml)
弱类型视图:通过 ViewData 和 ViewBag 传递数据,这里是视图没有指定 @model。
32-action给视图传递数据-2
运行出现这个问题:
An error occurred during the compilation of a resource required to process this request. Please review the following specific error details and modify your source code appropriately.
Generated CodeCode language: JavaScript (javascript)
解决办法:把我们的 public class Person 改为 public。以及 ViewData["SubTitle"]。
33-布局
布局好比模板,里面可以填充内容。通过 RenderBody 可以填充内容进去,通过 RenderSection 可以填充部分内容进去。视图中通过 Layout 可以指定使用哪个布局。
Shared 一般存放公共文件,布局文件一般定义在这个目录。
布局页 _Layout.cshtml:
<!DOCTYPE html>
<html>
<head>
<title>@ViewData["Title"] - ViewDemo</title>
</head>
<body>
@RenderBody()
@RenderSection("Scripts", required: false)
</body>
</html>Code language: HTML, XML (xml)
@RenderBody()是把视图中(不是布局视图,而是普通的 action 视图)非 section 的视图填充到这个位置。RenderSection是填充一部分 HTML 标签,它有个名字,第二个参数是是否必须的意思。如果设为true,则普通视图使用这个布局视图则必须含有这个名字的 section。
在 _ViewStart.cshtml 这个视图里面有指定 Layout 的值:
@{
Layout = "_Layout";
}Code language: JavaScript (javascript)
_ViewStart.cshtml 它是所有的普通 action 视图的前置执行视图。
如果 action 视图不想使用布局页,则需要指定 Layout 属性:
@{
Layout = null;
}Code language: JavaScript (javascript)
指定为空,也就是抵消掉 ViewStart 里面设置的 Layout。
RenderBody 会把所有非 section 的 HTML 代码替换到它的这个位置。RenderSection 则把跟它对应名称的 section 替换到它的这个位置,不管它在哪里。
布局页示例:
<!DOCTYPE html>
<html>
<head>
<title>@ViewData["Title"] - ViewDemo</title>
</head>
<body>
@RenderBody()
<hr/>
@RenderSection("Scripts", required: false)
</body>
</html>Code language: HTML, XML (xml)
普通视图示例:
@model ViewDemo.Controllers.Person
@{
ViewData["Title"] = "About";
}
<h2>@ViewData["Title"]</h2>
<h3>@ViewData["Message"]</h3>
@section Scripts
{
<h1>这是部分代码</h1>
}
<p>Use this area to provide additional information.</p>
<div>@Model.Name</div>
@ViewBag.Title
@ViewData["SubTitle"]Code language: HTML, XML (xml)
33-_ViewImports.cshtml文件
这个文件可以导入命名空间或者执行依赖注入。以前的配置命名空间是在视图所在目录下的 web.config 配置的,现在不使用 web.config 文件了,改为在 _ViewImports 里面配置。
@model Person 比如我们的 about 视图,如果去掉 Person 的命名空间则会报错。现在我们可以在 _ViewImports 里面 using:
@using ViewDemo.Models
@using ViewDemo.Controllers
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpersCode language: CSS (css)
34-标签助手TagHelper
使服务器端代码能参与 Razor 中呈现 HTML 代码,就是在视图中调用服务器代码,服务器代码返回 HTML 标记。
参考:https://www.cnblogs.com/shenba/p/6697024.html
实现一个 Email TagHelper:
public class EmailTagHelper : TagHelper
{
public string Content { set; get; }
public string EmailAddress { set; get; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
//输出<a href="mailto:name@email.com">内容</a>
output.TagName = "a";
output.Attributes.SetAttribute("href", "mailto:" + EmailAddress);
output.Content.SetContent(Content);
}
}Code language: HTML, XML (xml)
注册标签:在 _ViewImports.cshtml 中注册自定义的标签。红色是我们自己的,* 匹配所有,后面的是程序集。
@using EfcoreSqlite
@using EfcoreSqlite.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, EfcoreSqliteCode language: CSS (css)
第二个参数 EfcoreSqlite 是程序集的名称(EfcoreSqlite.dll)。如果只是想加入我们的 Email:
@addTagHelper EfcoreSqlite.EmailTagHelper*, EfcoreSqliteCode language: CSS (css)
前面是命名空间,后面是程序集名。最后在视图中我们可以使用:
<email content="就是想发邮件" EmailAddress="admin@FoxDevelop.com"></email>
<email></email>Code language: HTML, XML (xml)
下面的使用默认值,视图中也会有智能提示 email。
35-局部视图
可以在多个不同的视图中使用一个公共的视图,通常一些侧栏 HTML 代码比较多用。
引入部分视图:
@await Html.PartialAsync("HotNews")
@Html.RenderPartial("HotNews")
@Html.Partial("_HotNews")Code language: JavaScript (javascript)
36-视图组件ViewComponent
这是 ASP.NET Core MVC 的新特性,以前的 MVC 是没有的,类似部分视图。
特点:
- 呈现块而不是整个响应
- 包含在控制器和试图之间发现的相同的关注点和可测试性
- 拥有参数和业务逻辑
- 通常从布局页面调用
视图组件可以用在任何需要重复逻辑且对局部视图来说过于复杂的情况,例如:
- 动态导航菜单
- 标签云(要查数据库)
- 登录面板
- 购物车
- 最近发表的文章
- 典型博客上的侧边栏内容
- 将在每个页面呈现的登录面板,根据用户的登录状态显示注销或登录的链接
创建视图组件类:派生自 ViewComponent,必须是 public、非嵌套、非抽象。
//[ViewComponent(Name = "ArticleList")]
//public class ABC //还可以通过特性的方式
public class ArticleList : ViewComponent
{
//构造函数中可以传入参数 比如数据库上下文 缓存等 然后在Invoke中可以使用
//private dbconten db;
//public ArticleList(dbconte db)
//{
// this.db = db;
//}
/// <summary>
/// 返回数据
/// </summary>
/// <param name="val"></param>
/// <returns></returns>
public IViewComponentResult Invoke(int val)
{
var items = new List<Person>();
items.Add(new Person() { Name = "xxx" });
items.Add(new Person() { Name = "yyy" });
return View(items);
}
}Code language: HTML, XML (xml)
创建视图组件的视图:在 Shared 目录下面创建 Components,然后再创建一个自定义的 Components 类名同名的目录(比如 ArticleList),在里面添加一个 Default 的视图:
@model List<Person>
<div>
@foreach (var item in Model)
{
<h1>@item.Name</h1>
}
</div>Code language: HTML, XML (xml)
视图中调用:
@await Component.InvokeAsync("ArticleList", 1)Code language: JavaScript (javascript)
第一个参数是视图组件的名称,第二个参数是视图组件的 Invoke 方法的参数。
37-过滤器IActionFilter
过滤器允许在执行管道中的特定节点之前或者之后运行代码。可以对全局也可以对每个控制器或者每个操作配置过滤器。
定义过滤器类:
public class MyActionFilter : IActionFilter
{
/// <summary>
/// 我们的控制器的action执行后才执行这里的代码
/// </summary>
/// <param name="context"></param>
public void OnActionExecuted(ActionExecutedContext context)
{
// throw new NotImplementedException();
}
/// <summary>
/// 我们的控制器的action执行前先执行这里的代码
/// </summary>
/// <param name="context"></param>
public void OnActionExecuting(ActionExecutingContext context)
{
//throw new NotImplementedException();
}
}Code language: HTML, XML (xml)
在 Startup 中注册:
public void ConfigureServices(IServiceCollection services)
{
//services.AddMvc();
services.AddMvc(options => {
options.Filters.Add(new MyActionFilter());
}); //在service服务里面 注入我们的过滤器
}Code language: JavaScript (javascript)
控制器本身也有 OnActionExecuted 和 OnActionExecuting:
/// <summary>
/// 我们的controller本身就有一个OnActionxxxxx 方法
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuted(ActionExecutedContext context)
{
// throw new NotImplementedException();
}
/// <summary>
/// 我们的控制器的action执行前先执行这里的代码
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuting(ActionExecutingContext context)
{
//throw new NotImplementedException();
}Code language: JavaScript (javascript)