歡迎來到第五天的學習。但願第一天到第四天的學習,你都是開心的。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,執行應用。
這裏咱們已經完成了第五天的學習。接下來的第六天學習是最困難的,也是最有意思的。
繼續保持學習的熱情吧!