欢迎来到第五天的学习。但愿第一天到第四天的学习,你都是开心的。html
在这个实验中,咱们将会向 Employee 页面添加 Footer。本次实验的目标是理解分部视图(Partial Views)。安全
什么是「Partial Views」?mvc
逻辑上讲,分部视图(Partial Views) 是一个可重用的视图,它不会被直接显示。它会被其它视图所包含,而后做为该视图的一部分来显示。它相似于 ASP.NET Web Forms 中的用户控件,可是没有后台代码。ide
第一步:为 Partial View 建立 ViewModel函数
右击 ViewModel 文件夹,而后建立一个类,命名为 FooterViewModel。布局
public class FooterViewModel { public string CompanyName { get; set; } public string Year { get; set; } }
第二步:建立 Partial Viewpost
右击「~/Views/Shared」文件夹,选择 Add -> View。学习
设置视图的名称为 Footer。选中「Create as a partial view」复选框,而后点击「Add」。测试
注意:咱们已经在第一天的学习中谈论了 Shared 文件夹。Shared 文件夹包含了视图,这些视图不会属于一个特定的控制器。在 Shared 文件夹下的视图适用于全部控制器。ui
第三步:在 Partial View 中显示数据
打开 Footer.cshtml,而后放置以下代码。
@using WebApplication1.ViewModels @model FooterViewModel <div style="text-align:right;background-color: silver;color: darkcyan;border: 1px solid gray;margin-top:2px;padding-right:10px;"> @Model.CompanyName © @Model.Year </div>
第四步:在 Main ViewModel 中包含 Footer 数据
打开 EmployeeListViewModel 类,而后增长一个新的属性来承载 Footer 数据。
public class EmployeeListViewModel { public List<EmployeeViewModel> Employees { get; set; } public string UserName { get; set; } public FooterViewModel FooterData { get; set; }//New Property }
在咱们的例子中,Footer 视图将会做为 Index 视图的一部分展现。
咱们将会在 Index 视图中向 Footer 传输必要数据。
Index 视图是一个 EmployeeListViewModel 的强类型视图,所以 Footer 中须要的数据都应该被封装在 EmployeeListViewModel 类中。
第五步:设置 Footer 数据
打开 EmployeeController,而后在 Index 行为方法中设定 FooterData 属性值。
public ActionResult Index() { ... ... employeeListViewModel.FooterData = new FooterViewModel(); employeeListViewModel.FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value employeeListViewModel.FooterData.Year = DateTime.Now.Year.ToString(); return View("Index", employeeListViewModel); }
第六步:展现 Footer
打开 Index.cshtml 文件,而后在 Table 标签后展现 Footer 视图。
</table> @{ Html.RenderPartial("Footer", Model.FooterData); } </div> </body> </html>
第七步:执行并测试
按下 F5。导航到 Index 视图。
Html.Partial 是用来作什么的?
它相似于 Html.RenderPartial,Html.Partial 用于在视图中展现 Partial View。
它的语法以下。很是简单。
@Html.Partial("Footer", Model.FooterData);
二者的区别是什么?
Html.RenderPartial 将会把 Partial View 的结果写入 HTTP 响应流中,而 Html.Partial 将会以 MvcHtmlString 的格式返回结果。
什么是 MvcHtmlString,为何 Html.Partial 返回的是 MvcHtmlString,而不是字符串?
首先让咱们理解下什么是 MvcHtmlString。
MSDN 的定义是「MvcHtmlString 表明一个 HTML 编码的字符串,这种字符串不该该再次编码」。
更好地理解这个定义,请查看下面代码。
@{ string MyString = "My Simple String"; } @MyString
它将会产生以下输出。
正如你所看见的,Razor 展现了全部的内容。可能许多人会觉得将输出加粗的字符串,可是 Razor Html 在展现以前对内容进行了编码,这就是为何咱们得到的是纯内容,而不是加粗的字符串。
当咱们不想用 Razor 编码时,咱们可使用 MvcHtmlString。MvcHtmlString 是 Razor 的一种表示,即「字符串已经编码了,再也不须要额外编码」。
例如咱们能够看下面的代码。
@{ string MyString = "My Simple String"; } @MvcHtmlString.Create(MyString)
它将会产生以下输出。
为何 Html.Partial 返回的是 MvcHtmlString,而不是字符串呢?
咱们已经理解了「Razor 将会编码字符串,可是不会对 MvcHtmlString 编码」这一事实。若是 Partial View 内容被认为是像它展现的那样的纯字符串,便没有意义。咱们但愿它被当成是一个 HTML 内容,这样咱们就须要中止 Razor 编码,所以 Partial 方法被设计为返回 MvcHtmlString。
哪一个更加推崇,Html.RenderPartial 仍是 Html.Partial ?
Html.RenderPartial 更被推崇,由于它更快。
何时运用 Html.Partial 更好?
当咱们想在展现以前改变 Partial View 返回的结果,推荐使用 Html.Partial。
打开 Index.cshtml,而后打开 Footer,放置以下代码。
@{ MvcHtmlString result = Html.Partial ("Footer", Model.FooterData); string finalResult = result.ToHtmlString().Replace("2015", "20000"); } @MvcHtmlString.Create(finalResult)
如今页脚展现以下。
为何将 Partial View 放置在 Shared 文件夹下?
由于 Partial View 意味着能够重复利用的资源,所以放置它们的地点是 Shared 文件夹下。
咱们不能将 Partial View 放置到一个特殊的控制器文件夹内吗?例如 Employee 或者 Authentication?
咱们能够这样作,可是在这种场景下,它将不会适用于指定控制器。
例如:当咱们将 Partial View 放置到 Employee 文件夹下,它将不会适用于 AuthenticationController 或者适用于 AuthenticationController 相关的视图。
为何 Partial View 的定义包含「逻辑」词汇?
在定义中,咱们已经知道 Partial View 是一个可重用的视图,可是它不能经过本身执行。它须要放置到其它视图中,而后做为这些视图的一部分来展现。
咱们所说的 Partial View 可重用是事实,可是咱们提到的执行在逻辑上是事实。技术上而言,这不是一个正确的解释。咱们能够建立一个行为方法,来返回以下的视图结果。
public ActionResult MyFooter() { FooterViewModel FooterData = new FooterViewModel(); FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value FooterData.Year = DateTime.Now.Year.ToString(); return View("Footer", FooterData); }
它将会展现以下的输出。
尽管在逻辑上没有意义,可是技术上是可行的。Footer.cshtml 不会包含正确的结构性 HTML。它意味着做为视图的一部分来展现。由于咱们说「逻辑上是没有意义的」。
为何要建立 Partial View,而不是直接在视图底部添加内容?
这样作有两个优点。
可重用性。咱们能够将一个 Partial View 运用到多个视图中去。
代码保留。将其放置为一个分割的文件,使其管理和操纵都很是方便。
为何在 Partial View 中没有建立 Header?
做为最佳实践,咱们须要为 Partial View 建立 Header,可是为了保持最初实验简单化,咱们并无这样作。
在本次实验中,咱们将会实现 Admin 和 Non-Admin 两种登陆功能。
需求是很简单的。即「Non-Admin 用户不能建立 Employees」。
经过这个实验,咱们将会理解 MVC 中的两个主题。
Session
Action Filters
如今咱们开始进行实验。为了简单化,咱们将实验分为两部分。
第一步:建立标识 UserStatus 的枚举
右击 Models 文件夹,选择「Add New Item」。
在对话框中选择「Code File」选项。
在名称栏中输入「UserStatus」,而后点击添加。「Code File」的选项将会建立一个空白的「.cs」文件。
建立一个枚举,命名为 UserStatus,代码以下。
namespace WebApplication1.Models { public enum UserStatus { AuthenticatedAdmin, AuthentucatedUser, NonAuthenticatedUser } }
第二步:更改业务层功能
删除 IsValidUser 功能,而后建立一个新的功能,命名为 GetUserValidity。
public UserStatus GetUserValidity(UserDetails u) { if (u.UserName == "Admin" && u.Password == "Admin") { return UserStatus.AuthenticatedAdmin; } else if (u.UserName == "Sukesh" && u.Password == "Sukesh") { return UserStatus.AuthentucatedUser; } else { return UserStatus.NonAuthenticatedUser; } }
第三步:更改 DoLogin 行为方法
打开 AuthenticationController,而后更改 DoLogin 行为方法以下。
[HttpPost] public ActionResult DoLogin(UserDetails u) { if (ModelState.IsValid) { EmployeeBusinessLayer bal = new EmployeeBusinessLayer(); //New Code Start UserStatus status = bal.GetUserValidity(u); bool IsAdmin = false; if (status==UserStatus.AuthenticatedAdmin) { IsAdmin = true; } else if (status == UserStatus.AuthentucatedUser) { IsAdmin = false; } else { ModelState.AddModelError("CredentialError", "Invalid Username or Password"); return View("Login"); } FormsAuthentication.SetAuthCookie(u.UserName, false); Session["IsAdmin"] = IsAdmin; return RedirectToAction("Index", "Employee"); //New Code End } else { return View("Login"); } }
正如你所看见的,咱们运用 Session 变量来识别用户是 Admin 用户仍是 non-Admin 用户。
不知道什么是 Session?
Session 是 ASP.NET 的一个功能,在 ASP.NET MVC 中被重用。
咱们运用 Session 变量来承载用户相关的数据。Session 的生命周期取决于用户的生命周期。它将一直可用直到当前的 Session 结束。
第四步:删除已经存在的 AddNew 连接
在「~/Views/Employee」文件夹下打开 Index.cshtml 视图,而后彻底删除「Add New」超连接。
<!-- Remove following line from Index.cshtml --> <a href="/Employee/AddNew">Add New</a>
第五步:建立 Partial View
右击「~/Views/Employee」文件夹,而后选择 Add -> View。设置视图的名称为「AddNewLink」,而后确保选择「Create as a partial view」复选框。
第六步:在 Partial View 中放置内容
在刚建立的 Partial View 中放置以下内容。
<a href="/Employee/AddNew">Add New</a>
第七步:建立行为方法
打开 EmployeeController 而后建立一个新的行为方法,命名为「GetAddNewLink」。
public ActionResult GetAddNewLink() { if (Convert.ToBoolean(Session["IsAdmin"])) { return Partial View("AddNewLink"); } else { return new EmptyResult(); } }
第八步:展现 AddNew 连接
打开 Index.html,而后放置以下代码。
<a href="/Authentication/Logout">Logout</a> </div> <hr /> @{ Html.RenderAction("GetAddNewLink"); } <div> <table border="1"> <tr>
Html.RenderAction 执行行为方法,而后向响应流中直接写入结果。
第九步:执行并测试
按下 F5,而后执行应用。
按照上述的逻辑,一件事是能够确保的。即如今 non-Admin 用户不能经过超连接导航到 AddNew 行为。
这样就够了吗?
答案是否认的,这还不够。若是一个 non-Admin 用户直接经过 URL 试图导航到 AddNew 行为会发生什么呢。
正如你在上述例子中所看见的,一个 non-Admin 用户依然能够访问 AddNew 行为。
为了解决这个问题,咱们须要运用 MVC 中的 Action Filters。Action Filters 让咱们向行为方法中添加一些预处理和后处理的逻辑。在本实验中,咱们将着重于 Action Filters 的预处理功能,在后面的实验中,咱们再着重于后处理功能。
第一步:设置过滤器
在项目下建立一个新的文件夹,命名为 Filters,而后建立一个新的类,命名为 AdminFilter。
第二步:建立过滤器
升级简单的 AdminFilter 类到 ActionFilter,经过将其继承 ActionFilterAttribute 类,代码以下。
public class AdminFilter:ActionFilterAttribute { }
注:为了运用 ActionFilterAttribute,你须要在顶部引用 System.Web.Mvc。
第三步:增长安全认证逻辑
在 ActionFilter 中重写 OnActionExecuting 方法。
public override void OnActionExecuting(ActionExecutingContext filterContext) { if (!Convert.ToBoolean(filterContext.HttpContext.Session["IsAdmin"])) { filterContext.Result = new ContentResult() { Content="Unauthorized to access specified resource." }; } }
第四步:附加过滤器
向 AddNew 和 SaveEmployee 行为方法添加过滤器。
[AdminFilter] public ActionResult AddNew() { return View("CreateEmployee",new Employee()); } ... ... [AdminFilter] public ActionResult SaveEmployee(Employee e, string BtnSubmit) { switch (BtnSubmit) { case "Save Employee": if (ModelState.IsValid) { EmployeeBusinessLayer empBal = new EmployeeBusinessLayer(); .... ....
第五步:执行和测试
按下 F5,而后执行应用。运用 non-Admin 身份登陆,而后试图经过 AddNew 行为的 URL 导航到 AddNew 行为方法。
正如你所看见的,如今你的行为方法处于彻底安全状态。
咱们能够经过地址栏直接触发 GetAddNewLink 吗?
答案是确定的,咱们已经在「Talk on Lab 22」部分讨论了这个行为。
直接中止执行 GetAddNewLink 有可能吗?
能够直接在 GetAddNewLink 中添加 ChildActionOnly 属性。
[ChildActionOnly] public ActionResult GetAddNewLink() { if (Convert.ToBoolean(Session["IsAdmin"])) {
Html.Action 是用来作什么的?
就相似于 Html.RenderAction,Html.Action 将会执行行为方法用于呈现视图的结果。下面是语法。
@Html.Action("GetAddNewLink");
能够看出,语法相对来讲简单多了。
二者的区别是什么?
Html.RenderAction 将会把行为方法的执行结果直接写入 HTTP 响应流,而 Html.Action 将会返回 MvcHtmlString 结果。
哪一个更推崇?是 Html.RenderAction 仍是 Html.Action?
更推崇 Html.RenderAction,由于它更快。
何时用 Html.Action 更好?
当咱们想在呈现以前改变行为方法执行的结果时,用 Html.Action 更好。
什么是 ActionFilter?
就相似于 AuthenticationFilter,ActionFilter 是 ASP.NET MVC 的一种过滤器类型。它容许咱们向行为方法添加预处理和后处理逻辑。
从视图的安全性方面出发,咱们还须要在项目中处理 CSRF 攻击。这里我将再也不作过多指导,你须要本身手动完成。
我建议你阅读下述文章,而后实现方法。
在 ASP.NET 领域中,一致性的布局意味着母版页(MasterPage)。
但 ASP.NET MVC 是区别于此的。在 Razor 中,母版页被称为布局页(Layout Pages)。
在正式开始试验以前,咱们先来讨论一下在母版页中咱们须要放置哪些元素。
1.带有欢迎信息的 Header。
2.带有页脚数据的 Footer。
最大的问题是什么?
页脚和页眉的数据做为 ViewModel 的一部分从控制器传输到视图中。
如今最大的问题即是,当页眉和页脚移动到布局页后,数据如何从视图传输到布局页。
解决方案 — 继承
在这里咱们能够简单地遵循面向对象继承准则。让咱们经过一个小实验来理解。
第一步:建立 ViewModel 的基类
在 ViewModel 文件夹下建立一个新的 ViewModel 类,称为 BaseViewModel 类。
public class BaseViewModel { public string UserName { get; set; } public FooterViewModel FooterData { get; set; }//New Property }
正如你所看见的,BaseViewModel 封装了 Layout 页所需的全部元素。
第二步:准备 EmployeeListViewModel
从 EmployeeListViewModel 类中移除 UserName 和 FooterData 属性,而后让它继承 BaseViewModel 类。
public class EmployeeListViewModel:BaseViewModel { public List<EmployeeViewModel> Employees { get; set; } }
第三步:建立布局页
右击 Shared 文件夹,选择 Add -> MVC 5 Layout Page。输入名称为 MyLayout,而后点击肯定。
它将会建立一个以下格式的代码。
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> </head> <body> <div> @RenderBody() </div> </body> </html>
第四步:转换布局页为强类型布局
在布局页的上方放置以下的简单声明,使其变为强类型布局。
@using WebApplication1.ViewModels @model BaseViewModel
第五步:设计布局页
在布局页添加页眉,页脚和内容三部分。
<html> <head> <meta name="viewport" content="width=device-width" /> <title>@RenderSection("TitleSection")</title> @RenderSection("HeaderSection",false) </head> <body> <div style="text-align:right"> Hello, @Model.UserName <a href="/Authentication/Logout">Logout</a> </div> <hr /> <div> @RenderSection("ContentBody") </div> @Html.Partial("Footer",Model.FooterData) </body> </html>
正如你所看见的,咱们已经为布局页建立了三块。Title 部分,Header 部分和Content 部分。内容页面将会用到这三部分来定义合适的内容。
第六步:向 Index 视图附上 Layout 页面
打开 Index.cshtml 页面,在顶部会发现以下代码。
@{ Layout = null; }
将这段代码改成以下代码。
@{ Layout = "~/Views/Shared/MyLayout.cshtml"; }
第七步:设计 Index 视图
完整的视图将会以下所示。
@using WebApplication1.ViewModels @model EmployeeListViewModel @{ Layout = "~/Views/Shared/MyLayout.cshtml"; } @section TitleSection{ MyView } @section ContentBody{ <div> @{ Html.RenderAction("GetAddNewLink"); } <table border="1"> <tr> <th>Employee Name</th> <th>Salary</th> </tr> @foreach (EmployeeViewModel item in Model.Employees) { <tr> <td>@item.EmployeeName</td> <td style="background-color:@item.SalaryColor">@item.Salary</td> </tr> } </table> </div> }
正如你所看见的,视图中全部的元素都定义在指定的位置上。
第八步:执行并测试
按下 F5,而后执行应用。导航到 Index 行为上。
第九步:在 CreateEmployee 视图中附上 Layout 页面
打开 Index.cshtml 页面,在顶部会发现以下代码。
@{ Layout = null; }
将其改成以下代码。
@{ Layout = "~/Views/Shared/MyLayout.cshtml"; }
第十步:设计 CreateEmployee 视图
像第七步的步骤同样,定义 CreateEmployee 视图的区域。这一次会增长一点。咱们将会定义 Header 部分。
完整的 HTML 代码以下。
@using WebApplication1.Models @model Employee @{ Layout = "~/Views/Shared/MyLayout.cshtml"; } @section TitleSection{ CreateEmployee } @section HeaderSection{ <script src="~/Scripts/Validations.js"></script> <script> function ResetForm() { document.getElementById('TxtFName').value = ""; document.getElementById('TxtLName').value = ""; document.getElementById('TxtSalary').value = ""; } </script> } @section ContentBody{ <div> <form action="/Employee/SaveEmployee" method="post" id="EmployeeForm"> <table> <tr> <td> First Name: </td> <td> <input type="text" id="TxtFName" name="FirstName" value="@Model.FirstName" /> </td> </tr> <tr> <td colspan="2" align="right"> @Html.ValidationMessage("FirstName") </td> </tr> <tr> <td> Last Name: </td> <td> <input type="text" id="TxtLName" name="LastName" value="@Model.LastName" /> </td> </tr> <tr> <td colspan="2" align="right"> @Html.ValidationMessage("LastName") </td> </tr> <tr> <td> Salary: </td> <td> <input type="text" id="TxtSalary" name="Salary" value="@Model.Salary" /> </td> </tr> <tr> <td colspan="2" align="right"> @Html.ValidationMessage("Salary") </td> </tr> <tr> <td colspan="2"> <input type="submit" name="BtnSubmit" value="Save Employee" onclick="return IsValid();" /> <input type="submit" name="BtnSubmit" value="Cancel" /> <input type="button" name="BtnReset" value="Reset" onclick="ResetForm();" /> </td> </tr> </table> </div> }
第十一步:执行并测试
按下 F5,而后执行应用。经过尝试超连接来导航到 AddNew 行为上。
Index 视图是 EmployeeListViewModel 的强类型视图,EmployeeListViewModel 又是 BaseViewModel 的子类,因此 Index 视图能够运转。可是 CreateEmployee 视图是 CreateEmployeeViewModel 的强类型视图,而 CreateEmployeeViewModel 不是 BaseViewModel 的子类,因此 CreateEmployee 出现了这样的错误。
第十二步:准备 CreateEmployeeViewModel
让 CreateEmployeeViewModel 继承 BaseViewModel,代码以下。
public class CreateEmployeeViewModel:BaseViewModel { ...
第十三步:执行并测试
再一次测试。
此次的错误看起来与以前的不同。错误真正的缘由是,咱们在 AddNew 行为中没有初始化 Header 和 Footer 的数据。
第十四步:初始化 Header 和 Footer 数据
将 AddNew 行为方法的代码改成以下所示。
public ActionResult AddNew() { CreateEmployeeViewModel employeeListViewModel = new CreateEmployeeViewModel(); employeeListViewModel.FooterData = new FooterViewModel(); employeeListViewModel.FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value employeeListViewModel.FooterData.Year = DateTime.Now.Year.ToString(); employeeListViewModel.UserName = User.Identity.Name; //New Line return View("CreateEmployee", employeeListViewModel); }
第十五步:在 SaveEmployee 中初始化 Header 和 Footer 数据
相似于 SaveEmployee 行为方法同样,咱们更改其代码以下。
public ActionResult SaveEmployee(Employee e, string BtnSubmit) { switch (BtnSubmit) { case "Save Employee": if (ModelState.IsValid) { ... } else { CreateEmployeeViewModel vm = new CreateEmployeeViewModel(); ... vm.FooterData = new FooterViewModel(); vm.FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value vm.FooterData.Year = DateTime.Now.Year.ToString(); vm.UserName = User.Identity.Name; //New Line return View("CreateEmployee", vm); // Day 4 Change - Passing e here } case "Cancel": return RedirectToAction("Index"); } return new EmptyResult(); }
第十六步:执行并测试
按下 F5,而后执行应用。
RenderBody 是用于作什么的?
当咱们第一次建立 Layout 页面时,咱们有一个 Razor 声明以下。
@Html.RenderBody()
如今让咱们来理解下它是作什么的。在内容页面上,咱们正常地定义区域,这些区域在布局页声明。
可是奇怪的是,Razor 容许咱们在区域外定义一些内容。在内容页面上,全部非区域内的内容将会被 RenderBody 函数呈现。
下图将会更好地进行解释。
咱们有嵌套的布局吗?
答案是确定的。咱们能建立一个嵌套了其它布局页的布局页。语法是同样的。
在每个视图中都指定布局页是必须的吗?
你可以在 Views 文件夹下发现一个特殊的布局页,称为「__ ViewStart.cshtml」。在其内部设定定义,将会应用于全部视图。
例如,在「__ ViewStart.cshtml」中放置以下的代码,将会使「_Layout.cshtml」适用于全部视图的布局。
@{ Layout = "~/Views/Shared/_Layout.cshtml"; }
在每个行为方法中,是否都须要放置 Header 和 Footer 的数据代码?
答案是否认的。咱们能够运用 Action 过滤器来避免这种重复。咱们将会在接下来的实验中实践。
在子视图中定义全部区域是不是必须的?
答案是确定的。若是 Section 的声明为必须的,那么默认值是 True。
@RenderSection("HeaderSection",false) // Not required @RenderSection("HeaderSection",true) // required @RenderSection("HeaderSection") // required
在 Lab 23 中,咱们已经知道了 ActionFilter 的优点,如今咱们来看它的第二点优点。
第一步:从行为方法中删除冗余代码
从 Index,AddNew 和 SaveEmployee 方法中删除 Header 和 Footer 数据的代码。
Header 代码以下。
bvm.UserName = HttpContext.Current.User.Identity.Name;
Footer 代码以下。
bvm.FooterData = new FooterViewModel(); bvm.FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value bvm.FooterData.Year = DateTime.Now.Year.ToString();
第二步:建立 HeaderFooterFilter
在 Filters 文件夹下建立一个类,命名为 HeaderFooterFilter,而后经过将它继承 ActionFilterAttribute 类来将其升级 Action 过滤器。
第三步:升级 ViewModel
在 HeaderFooterFilter 类中重写 OnActionExecuted。在这个方法中咱们将会获得当前的视图模型,而后将其附上 Header 和 Footer 数据。
public class HeaderFooterFilter : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext filterContext) { ViewResult v = filterContext.Result as ViewResult; if(v!=null) // v will null when v is not a ViewResult { BaseViewModel bvm = v.Model as BaseViewModel; if(bvm!=null)//bvm will be null when we want a view without Header and footer { bvm.UserName = HttpContext.Current.User.Identity.Name; bvm.FooterData = new FooterViewModel(); bvm.FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value bvm.FooterData.Year = DateTime.Now.Year.ToString(); } } } }
OnActionExecuted 方法用于添加行为方法执行的逻辑操做。
第四步:附上过滤器
在 Index,AddNew 和 SaveEmployee 方法中附上 HeaderFooterFilter。
[HeaderFooterFilter] public ActionResult Index() { EmployeeListViewModel employeeListViewModel = new EmployeeListViewModel(); ... } ... [AdminFilter] [HeaderFooterFilter] public ActionResult AddNew() { CreateEmployeeViewModel employeeListViewModel = new CreateEmployeeViewModel(); //employeeListViewModel.FooterData = new FooterViewModel(); //employeeListViewModel.FooterData.CompanyName = "StepByStepSchools"; ... } ... [AdminFilter] [HeaderFooterFilter] public ActionResult SaveEmployee(Employee e, string BtnSubmit) { switch (BtnSubmit) { ...
第五步:执行并测试
按下 F5,执行应用。
这里咱们已经完成了第五天的学习。接下来的第六天学习是最困难的,也是最有意思的。
继续保持学习的热情吧!