7 天玩轉 ASP.NET MVC — 第 5 天

目錄

0. 前言

歡迎來到第五天的學習。但願第一天到第四天的學習,你都是開心的。html

1. Lab 22 — 增長 Footer

在這個實驗中,咱們將會向 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。學習

7 天玩轉 ASP.NET MVC — 第 5 天

設置視圖的名稱爲 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 &copy; @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 視圖。

7 天玩轉 ASP.NET MVC — 第 5 天

Lab 22 的 Q&A

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

它將會產生以下輸出。

7 天玩轉 ASP.NET MVC — 第 5 天

正如你所看見的,Razor 展現了全部的內容。可能許多人會覺得將輸出加粗的字符串,可是 Razor Html 在展現以前對內容進行了編碼,這就是爲何咱們得到的是純內容,而不是加粗的字符串。

當咱們不想用 Razor 編碼時,咱們可使用 MvcHtmlString。MvcHtmlString 是 Razor 的一種表示,即「字符串已經編碼了,再也不須要額外編碼」。

例如咱們能夠看下面的代碼。

@{
   string MyString = "My Simple String";
}
@MvcHtmlString.Create(MyString)

它將會產生以下輸出。

7 天玩轉 ASP.NET MVC — 第 5 天

爲何 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)

如今頁腳展現以下。

7 天玩轉 ASP.NET MVC — 第 5 天

爲何將 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);
}

它將會展現以下的輸出。

7 天玩轉 ASP.NET MVC — 第 5 天

儘管在邏輯上沒有意義,可是技術上是可行的。Footer.cshtml 不會包含正確的結構性 HTML。它意味着做爲視圖的一部分來展現。由於咱們說「邏輯上是沒有意義的」。

爲何要建立 Partial View,而不是直接在視圖底部添加內容?

這樣作有兩個優點。

  1. 可重用性。咱們能夠將一個 Partial View 運用到多個視圖中去。

  2. 代碼保留。將其放置爲一個分割的文件,使其管理和操縱都很是方便。

爲何在 Partial View 中沒有建立 Header?

做爲最佳實踐,咱們須要爲 Partial View 建立 Header,可是爲了保持最初實驗簡單化,咱們並無這樣作。

2. Lab 23 — 實現基於角色的安全性

在本次實驗中,咱們將會實現 Admin 和 Non-Admin 兩種登陸功能。

需求是很簡單的。即「Non-Admin 用戶不能建立 Employees」。

經過這個實驗,咱們將會理解 MVC 中的兩個主題。

  • Session

  • Action Filters

如今咱們開始進行實驗。爲了簡單化,咱們將實驗分爲兩部分。

Part 1 — Non-Admin 用戶登陸,隱藏 AddNew 連接

第一步:建立標識 UserStatus 的枚舉

右擊 Models 文件夾,選擇「Add New Item」。

在對話框中選擇「Code File」選項。

7 天玩轉 ASP.NET MVC — 第 5 天

在名稱欄中輸入「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」複選框。

7 天玩轉 ASP.NET MVC — 第 5 天

第六步:在 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,而後執行應用。

  • Test 1

7 天玩轉 ASP.NET MVC — 第 5 天

  • Test 2

7 天玩轉 ASP.NET MVC — 第 5 天

Part 2 — 直接的 URL 安全性

按照上述的邏輯,一件事是能夠確保的。即如今 non-Admin 用戶不能經過超連接導航到 AddNew 行爲。

這樣就夠了嗎?

答案是否認的,這還不夠。若是一個 non-Admin 用戶直接經過 URL 試圖導航到 AddNew 行爲會發生什麼呢。

7 天玩轉 ASP.NET MVC — 第 5 天

正如你在上述例子中所看見的,一個 non-Admin 用戶依然能夠訪問 AddNew 行爲。

爲了解決這個問題,咱們須要運用 MVC 中的 Action Filters。Action Filters 讓咱們向行爲方法中添加一些預處理和後處理的邏輯。在本實驗中,咱們將着重於 Action Filters 的預處理功能,在後面的實驗中,咱們再着重於後處理功能。

第一步:設置過濾器

在項目下建立一個新的文件夾,命名爲 Filters,而後建立一個新的類,命名爲 AdminFilter。

7 天玩轉 ASP.NET MVC — 第 5 天

第二步:建立過濾器

升級簡單的 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 行爲方法。

7 天玩轉 ASP.NET MVC — 第 5 天

正如你所看見的,如今你的行爲方法處於徹底安全狀態。

Lab 23 的 Q&A

咱們能夠經過地址欄直接觸發 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 的一種過濾器類型。它容許咱們向行爲方法添加預處理和後處理邏輯。

3. Lab 24 — 任務實驗 — 處理 CSRF 攻擊

從視圖的安全性方面出發,咱們還須要在項目中處理 CSRF 攻擊。這裏我將再也不作過多指導,你須要本身手動完成。

我建議你閱讀下述文章,而後實現方法。

如何在 MVC 中防止 CSRF 攻擊

4. Lab 25 — 實現項目的一致性外觀

在 ASP.NET 領域中,一致性的佈局意味着母版頁(MasterPage)。

但 ASP.NET MVC 是區別於此的。在 Razor 中,母版頁被稱爲佈局頁(Layout Pages)。

在正式開始試驗以前,咱們先來討論一下在母版頁中咱們須要放置哪些元素。

1.帶有歡迎信息的 Header。
2.帶有頁腳數據的 Footer。

最大的問題是什麼?

頁腳和頁眉的數據做爲 ViewModel 的一部分從控制器傳輸到視圖中。

7 天玩轉 ASP.NET MVC — 第 5 天

如今最大的問題即是,當頁眉和頁腳移動到佈局頁後,數據如何從視圖傳輸到佈局頁。

解決方案 — 繼承

在這裏咱們能夠簡單地遵循面向對象繼承準則。讓咱們經過一個小實驗來理解。

第一步:建立 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 視圖

  1. 從 Index 視圖中移除 Headers 和 Footers。
  2. 複製 Body 標籤中的剩餘內容,而後將它保存在別處。
  3. 複製 Title 標籤裏的內容。
  4. 將視圖中的全部 HTML 內容都移除。確保你只是移除了 HTML,@model 和佈局聲明不須要被移除。
  5. 定義 Title 部分和 Content 部分,內容是剛纔所複製下的內容。

完整的視圖將會以下所示。

@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 行爲上。

7 天玩轉 ASP.NET MVC — 第 5 天

第九步:在 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 行爲上。

7 天玩轉 ASP.NET MVC — 第 5 天

Index 視圖是 EmployeeListViewModel 的強類型視圖,EmployeeListViewModel 又是 BaseViewModel 的子類,因此 Index 視圖能夠運轉。可是 CreateEmployee 視圖是 CreateEmployeeViewModel 的強類型視圖,而 CreateEmployeeViewModel 不是 BaseViewModel 的子類,因此 CreateEmployee 出現了這樣的錯誤。

第十二步:準備 CreateEmployeeViewModel

讓 CreateEmployeeViewModel 繼承 BaseViewModel,代碼以下。

public class CreateEmployeeViewModel:BaseViewModel
{
...

第十三步:執行並測試

再一次測試。

7 天玩轉 ASP.NET MVC — 第 5 天

此次的錯誤看起來與以前的不同。錯誤真正的緣由是,咱們在 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,而後執行應用。

7 天玩轉 ASP.NET MVC — 第 5 天

Lab 25 的 Q&A

RenderBody 是用於作什麼的?

當咱們第一次建立 Layout 頁面時,咱們有一個 Razor 聲明以下。

@Html.RenderBody()

如今讓咱們來理解下它是作什麼的。在內容頁面上,咱們正常地定義區域,這些區域在佈局頁聲明。

可是奇怪的是,Razor 容許咱們在區域外定義一些內容。在內容頁面上,全部非區域內的內容將會被 RenderBody 函數呈現。

下圖將會更好地進行解釋。

7 天玩轉 ASP.NET MVC — 第 5 天

咱們有嵌套的佈局嗎?

答案是確定的。咱們能建立一個嵌套了其它佈局頁的佈局頁。語法是同樣的。

在每個視圖中都指定佈局頁是必須的嗎?

你可以在 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

5. Lab 26 — 運用 Action 過濾器讓 Header 和 Footer 數據更高效

在 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,執行應用。

7 天玩轉 ASP.NET MVC — 第 5 天

6. 總結

這裏咱們已經完成了第五天的學習。接下來的第六天學習是最困難的,也是最有意思的。

繼續保持學習的熱情吧!

原文地址:Learn MVC Project in 7 days

本文系 OneAPM 工程師編譯整理。想閱讀更多技術文章,請訪問 OneAPM 官方博客

相關文章
相關標籤/搜索