ChildAction部分
类似于ASP.NET Core:PartialView,除了:
调用方式
需使用@Html.Partial(),代码如下所示:
@_LogOnStatus.cshtml和当前页面在同一个文件夹,@ @或者_LogOnStatus.cshtml在Shared文件夹下@ @Html.Partial("_LogOnStatus") @将当前Model的Name,传递给_LogOnStatus.cshtml@ @Html.Partial("_LogOnStatus", Model.Name) @将ViewData["Id"]=32,传递给_LogOnStatus.cshtml@ @Html.Partial("_LogOnStatus", new ViewDataDictionary { { "Id", 32 } }) @_LogOnStatus.cshtml在当前页面所在文件夹的子文件夹Yz下@ @或者_LogOnStatus.cshtml在Shared/Yz文件夹下@ @Html.Partial("Yz/_LogOnStatus") @_LogOnStatus.cshtml在~/Views/User/下,注意.cshtml后缀不能省略@ @Html.Partial("~/Views/User/_LogOnStatus.cshtml")
ChildAction部分
类似于:ASP.NET Core:View Component,除了:
调用方式
使用@Html.Action(),比如:
@Html.Action("_Reminder", "Register", new { id = 32 })
其中:
- Reminder:action name,必填
- Register:controller name,可选,默认为当前Controller
- new { id = 32 }:route data,可选,通常使用匿名对象
然后,在上述指定的Controller中,添加一个Action
public PartialViewResult _Reminder(int id) //惯例:片段Html的Action和View都前缀下划线 { return PartialView(); }
通过return PartialView() 返回的是一个部分页面(PartialViewResult),它和普通ViewResult最大的区别是:不受_ViewStart.cshtml内容控制(通常是自动引入_Layout)
Action中就可以写需要的后台逻辑,这就是ChildAction和Partial的最大区别!
执行顺序
- 首先进入父Action
- 父Action执行完成,然后进入View页面执行
- 直到@Html.Action()调用进入ChildAction
断点演示:注意route data(id)的传值
[ChildActionOnly]特性
在Action上可以添加 [ChildActionOnly],使其只能被其他View调用,不能独立响应HTTP请求。
换言之,如果没有[ChildActionOnly],该Action就可以被直接调用。
(演示:浏览器输入ChildAction的url访问……)
Filter影响
和RazorPage不同,MVC中的Filter是会影响ChildAction。这给我们带来便利的同事,也带来一些麻烦。
首先是要结合ChildAction的执行顺序明白Filter的执行顺序:
Index()
-- ActionExecuted()
-- ResultExecuting()
@ Index.cshtml
@Html.Action("_Index")
--ActionExecuting()
ChildAction()
--ActionExecuted()
--ResultExecuting()
--ResultExecuted()
-- ResultExecuted()
然后MVC在FilterContext中,为我们提供IsChildAction属性:
if (!filterContext.IsChildAction)
应用详见:ContextPerRequest
Editor部分
如果我们的PartialView或ChildAction包含Form表单内容,对应一个可重用的Model,比如:
namespace ViewModel.Register { public class IndexModel { public InviterModel Inviter { get; set; }
public class InviterModel { public string UserName { get; set; } public string Code { get; set; } }
注册用的IndexModel包含了邀请人相关的InviterModel,相应的View也变成:
@model ViewModel.Register.InviterModel
那么,在Register.cshtml页面应该如何调用呢?
如果使用:
PartialView
POST的时候,Register.IndexModel.InviterModel为null值_(断点演示)_
@想一想@:为什么?
ChildAction
POST的时候:
- 首先进入父Action,且此时Register.IndexModel.InviterModel仍然为null值
- 此后在子ChildAction时,InviterModel可以有值
但是,注意:
所以,最佳做法是使用:
EditorTemplate
首先,把对应的.cshtml文件(如:Inviter.cshtml)放在:
- ~/Shared/EditorTemplates文件夹下,或者
- 父页面所在文件夹的EditorTemplates文件夹下,如 ~/Register/EditorTemplates
然后,在父页面中调用:
@Html.EditorFor(m => m.Inviter, "Inviter")
演示:__EditorFor的三个重载方法
注意参数templateName可以:
- 省略,这时候MVC默认会在EditorTemplates下寻找和model同名的.cshtml文件做template,比如InviterModel,注意Model后缀
- 使用绝对路径:
同名的