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

目錄

0. 前言

歡迎來到第四天的 MVC 系列學習中。如果你直接開始學習今天的課程,我強烈建議你先完成之前的學習內容再來到這里。

1. Lab 15 — 認證錯誤的保留值

在 Lab 13 中,我們介紹了服務器端的認證,并且在 Lab 14 中,我們通過添加自定義認證的方式將其提示到一個新的層級。

我強烈建議你再回顧一下 Lab 14。再次執行應用,并且能夠很好地理解代碼以及輸出。

在 Lab 15 中,我們將學習如何在認證失敗時填充值。

第一步:創建 CreateEmployeeViewModel

在 ViewModel 文件夾下創建一個新的類。

public class CreateEmployeeViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Salary { get; set; }
}

第二步:改變 SaveEmployee 行為方法

我們將重新使用 Model Binder 創建的 Employee 對象來重新生成。改變 SaveEmployee 行為方法如下。

public ActionResult SaveEmployee(Employee e, string BtnSubmit)
{
    switch (BtnSubmit)
    {
        case "Save Employee":
            if (ModelState.IsValid)
            {
                EmployeeBusinessLayer empBal = new EmployeeBusinessLayer();
                empBal.SaveEmployee(e);
                return RedirectToAction("Index");
            }
            else
            {
                CreateEmployeeViewModel vm = new CreateEmployeeViewModel();
                vm.FirstName = e.FirstName;
                vm.LastName = e.LastName;
                if (e.Salary.HasValue)
                {
                    vm.Salary = e.Salary.ToString();                        
                }
                else
                {
                    vm.Salary = ModelState["Salary"].Value.AttemptedValue;                       
                }
                return View("CreateEmployee", vm); // Day 4 Change - Passing e here
            }
        case "Cancel":
            return RedirectToAction("Index");
    }
    return new EmptyResult();
}

第三步:在視圖中重新填值

  • 將 View 成為一個強類型視圖

在 CreateEmployee 視圖的頂部,放置如下代碼。

@using WebApplication1.ViewModels
@model CreateEmployeeViewModel
  • 在相應控件中呈現從 Model 中獲取的值

    ...
    ...
    <input type="text" id="TxtFName" name="FirstName" value="@Model.FirstName" />
    ...
    ...
    <input type="text" id="TxtLName" name="LastName" value="@Model.LastName" />
    ...
    ...
    <input type="text" id="TxtSalary" name="Salary" value="@Model.Salary" />
    ...
    ...

第四步:執行并測試

按下 F5 執行應用。通過點擊“Add New”鏈接導航到 AddNew 屏幕上。

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

上述的錯誤將會在實驗結束后探討。現在讓我們來實現解決方案。

第五步:改變 AddNew 行為方法

public ActionResult AddNew()
{
    return View("CreateEmployee”, new CreateEmployeeViewModel());
}

第六步:執行并測試

按下 F5,并執行應用。

  • Test

步驟如下。

  1. 通過點擊「Add New」鏈接導航到 AddNew 屏幕。

  2. 保持 First Name 為空。

  3. 將 Salary 設置為 56。

  4. 點擊「Save Employee」按鈕。

這樣會使得兩個認證是失敗的。

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

正如你所看見的那樣,值56 仍然保留在 Salary 文本框內。

  • Test 2
7 天玩轉 ASP.NET MVC — 第 4 天
7 天玩轉 ASP.NET MVC — 第 4 天

正如你所看見的,FirstName 和 LastName 文本框內的值仍然有所保留。
但是奇怪的是,Salary 并沒有保留值。我們將會在實驗的最后探討原因并給出解決方案。

Lab 15 的 Q&A

我們真的將值保留了嗎?

答案是否定的。實際上,我們重填的值是從 Posted 數據中獲取的。

為什么在初始的請求中,在「AddNew」行為方法中需要傳輸「new CreateEmployeeViewModel()」?

在視圖中,我們嘗試將模型中的值重新填充到文本框內。例如:

<input id="TxtSalary" name="Salary" type="text" value="@Model.Salary" />

正如你所看見的,在代碼區域,我們訪問當前模型的 FirstName 屬性。如果 Model 為 Null,那么將會拋出「Object reference not set to an instance of the class」的異常。

當點擊「Add New」超鏈接時,請求將會被「Add New」行為方法處理。在該方法中,我們可以在返回視圖時不傳輸任何數據。這意味著視圖中 Model 的屬性為 Null,并且會拋出「Object reference not set to an instance of the class」的異常。為了解決這個問題,在初始請求中,需要傳輸「new CreateEmployeeViewModel()」。

我們可以通過自動的方式來達到上述同樣的功能效果嗎?

答案是肯定的。我們可以運用 HTML Helper 類來解決。我們將會在接下來的實驗中探討這個問題。

2. Lab 16 — 添加客戶端認證

首先我們列舉所需要的所有認證。

  1. FirstName 不應為空。

  2. LastName 的長度不能超出5。

  3. Salary 不應為空。

  4. Salary 應該為一個正確的數字。

  5. FirstName 應該不能包含「@」符號。

讓我們來實現它吧。

第一步:創建一個 JavaScript 認證文件

創建一個 JavaScript 文件,命名為「Validations.js」,并且把它放到 Scripts 文件夾內。

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

第二步:創建認證函數

在「Validations.js」文件內,創建一個認證函數。

function IsFirstNameEmpty() {
    if (document.getElementById('TxtFName').value == "") {
        return 'First Name should not be empty';
    }
    else { return ""; }
}

function IsFirstNameInValid() {    
    if (document.getElementById('TxtFName').value.indexOf("@") != -1) {
        return 'First Name should not contain @';
    }
    else { return ""; }
}
function IsLastNameInValid() {
    if (document.getElementById('TxtLName').value.length>=5) {
        return 'Last Name should not contain more than 5 character';
    }
    else { return ""; }
}
function IsSalaryEmpty() {
    if (document.getElementById('TxtSalary').value=="") {
        return 'Salary should not be empty';
    }
    else { return ""; }
}
function IsSalaryInValid() {
    if (isNaN(document.getElementById('TxtSalary').value)) {
        return 'Enter valid salary';
    }
    else { return ""; }
}
function IsValid() {

    var FirstNameEmptyMessage = IsFirstNameEmpty();
    var FirstNameInValidMessage = IsFirstNameInValid();
    var LastNameInValidMessage = IsLastNameInValid();
    var SalaryEmptyMessage = IsSalaryEmpty();
    var SalaryInvalidMessage = IsSalaryInValid();

    var FinalErrorMessage = "Errors:";
    if (FirstNameEmptyMessage != "")
        FinalErrorMessage += "\n" + FirstNameEmptyMessage;
    if (FirstNameInValidMessage != "")
        FinalErrorMessage += "\n" + FirstNameInValidMessage;
    if (LastNameInValidMessage != "")
        FinalErrorMessage += "\n" + LastNameInValidMessage;
    if (SalaryEmptyMessage != "")
        FinalErrorMessage += "\n" + SalaryEmptyMessage;
    if (SalaryInvalidMessage != "")
        FinalErrorMessage += "\n" + SalaryInvalidMessage;

    if (FinalErrorMessage != "Errors:") {
        alert(FinalErrorMessage);
        return false;
    }
    else {
        return true;
    }
}

第三步:在 View 中包含認證文件

在「CreateEmployee」視圖的頂部,將「Validations.js」文件引入。

<script src="~/Scripts/Validations.js"></script>

第四步:附加認證

在 SaveEmployee 按鈕點擊時觸發 IsValid 函數。

<input type="submit" name="BtnSubmit" value="Save Employee" onclick="return IsValid();" />

第五步:執行并測試

按下 F5,執行應用。

通過點擊「Add New」鏈接導航到 AddNew 屏幕。

  • Test 1
7 天玩轉 ASP.NET MVC — 第 4 天
7 天玩轉 ASP.NET MVC — 第 4 天
  • Test 2
7 天玩轉 ASP.NET MVC — 第 4 天
7 天玩轉 ASP.NET MVC — 第 4 天

Lab 16 的 Q&A

為什么點擊 SaveEmployee 按鈕時,關鍵字需要被返回?

正如我們在 Lab 9 中所探討的,提交按鈕被點擊時,它將會向服務器發送請求。當認證失敗時,向服務器發送請求是沒有意義的。通過在提交按鈕中寫下「return false」,我們可以阻止默認的服務器請求。

在我們的這個例子中,當認證失敗時,IsValid 函數將會返回 false,因此我們達到了預期的功能。

除了彈出的警告以外,我們可以在頁面本身上顯示錯誤信息嗎?

答案是肯定的。只需要為每個錯誤創建一個 Span 標簽。運用 CSS 使它在開始時不可見,當提交按鈕點擊后,如果認證失敗了,運用 JavaScript 使其可見。

是否存在客戶端自動認證的方法?

答案是肯定的。當我們運用 HTML Helper 就可以基于服務端認證實現自動客戶端認證。我們將會在后面的實驗中探討這個問題。

服務器端的認證還被需要嗎?

答案是肯定的。在一些場景下,JavaScript 無法使用,服務器端認證可以替代它使用。

3. Lab 17 — 添加授權認證

在這個實驗中,我們將會使得 GetView 方法更加安全。我們將會確保只有合法用戶才能訪問行為方法。

在第一天的系列學習中,我們了解了 ASP.NET 和 MVC 的真實含義。我們理解到 ASP.NET MVC 是 ASP.NET 的一部分。許多 ASP.NET 的功能都被 ASP.NET MVC 所繼承。其中一個功能便是表單的認證。

在我們開始實驗之前,我們先了解下在 ASP.NET 中如何進行表單認證工作。

  1. 終端用戶通過瀏覽器發送一個表單認證的請求。

  2. 瀏覽器將發送所有請求相關的Cookies,存儲在客戶機器上。

  3. 當請求被服務器端接收到,服務器會檢查請求并檢查特殊的 Cookie,即「Authentication Cookie」。

  4. 如果發現了合法的認證 Cookie,服務器就會證實用戶的身份,或者簡單來說,認為用戶是一個合法的用戶,并允許他進行下一步。

  5. 如果沒有發現合法的認證 Cookie,服務器就會認為用戶是匿名(未認證)的用戶。在這種情況下,如果被請求的資源被標記為 Protected/Secured,那么用戶將會被重新導向到登錄頁面。

第一步:創建一個 AuthenticationController 和一個登錄行為方法

右擊 Controller 文件夾,選擇「Add New Controller」,然后創建一個控制器,命名為「Authentication」。在這種情況下,全名應該為「AuthenticationController」。

在控制器內創建一個行為方法,命名為 Login。

public class AuthenticationController : Controller
{
    // GET: Authentication
    public ActionResult Login()
    {
        return View();
    }
}

第二步:創建 Model

在 Model 文件夾下創建一個 Model 類,命名為 UserDetails。

namespace WebApplication1.Models
{
    public class UserDetails
    {
        public string UserName { get; set; }
        public string Password { get; set; }
    }
}

第三步:創建 Login 視圖

在「~/Views/Authentication」文件夾下創建一個新的視圖,命名為 Login。使它成為一個 UserDetails 的強類型視圖。

在視圖內放置如下 HTML 代碼。

@model WebApplication1.Models.UserDetails

@{

    Layout = null;

}

<!DOCTYPE html>

<html>

<head>

    <meta name="viewport" content="width=device-width" />

    <title>Login</title>

</head>

<body>

    <div>

        @using (Html.BeginForm("DoLogin", "Authentication", FormMethod.Post))

        {

            @Html.LabelFor(c=>c.UserName)

            @Html.TextBoxFor(x=>x.UserName)

       

            <br />

            @Html.LabelFor(c => c.Password)

            @Html.PasswordFor(x => x.Password)

            <br />

            <input type="submit" name="BtnSubmit" value="Login" />

        }

    </div>

</body>

</html>

正如你所看見的,這次我們生成的視圖運用了 HtmlHelper 類,而不是純 HTML。

  • 在視圖中我們已經創建了一個 HtmlHelper 類的對象,即「Html」。

  • HtmlHelper 類的功能簡單返回 HTML 字符串。

Example 1

@Html.TextBoxFor(x=>x.UserName)

上述的代碼將產生如下的 HTML。

<input id="UserName" name="UserName" type="text" value="" />

Example 2

@using (Html.BeginForm("DoLogin", "Authentication", FormMethod.Post))
{
}

上述的代碼將產生如下的 HTML。

<form action="/Authentication/DoLogin" method="post">
</form>

第四步:執行并測試

按下 F5,執行應用。在地址欄輸入 Login 方法的 URL。在這個例子中,將會是「http://localhost:8870/Authentication/Login」。

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

第五步:授權表單認證

打開 Web.config 文件。導航到 System.Web 區域。找到子區域 Authentication。如果這里不存在就創建一個。設置 Authentication 的模式是 Forms,Login URL 指向第一步所創建的「Login」的行為方法。

<authentication mode="Forms">
<forms loginurl="~/Authentication/Login"></forms>
</authentication>

第六步:讓行為方法更加安全

打開 EmployeeController,然后向 Index 方法附上 Authorize 屬性。

[Authorize]
public ActionResult Index()
{
    EmployeeListViewModel employeeListViewModel = new EmployeeListViewModel();
......

第七步:執行并測試

按下 F5 并執行應用。在地址欄中輸入 EmployeeController 的 Index 行為方法的 URL。在這個情景中,URL 為“http://localhost:8870/Employee/Index”。

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

正如你所看見的,Index 行為的請求將會重指向 Login 行為。

第八步:創建一個業務層功能

打開 EmployeeBusinessLayer 類,然后創建一個方法叫做 IsValidUser。

public bool IsValidUser(UserDetails u)
{
    if (u.UserName == "Admin" && u.Password == "Admin")
    {
        return true;
    }
    else
    {
        return false;
    }
}

注:在業務層,我們對比 UserName 和 Password 的硬編碼值。在真實場景中,我們能夠調用數據庫層,并對比真實的值。

第九步:創建 DoLogin 行為方法

打開 AuthenticationController 類,然后創建一個新的行為方法,叫做 DoLogin。

這個 DoLogin 方法會在 Login 按鈕點擊時被觸發。

現在我們來列舉一下 DoLogin 中需要做的幾點。

  1. 通過觸發業務層功能來檢查用戶的合法性。

  2. 如果用戶是一個合法用戶,就創建一個認證的 Cookie。它能夠使得未來的請求是認證過的請求。

  3. 如果用戶是不合法的,就向當前的 ModelState 增加一個錯誤。這個錯誤將會呈現在視圖中。

    [HttpPost]
    public ActionResult DoLogin(UserDetails u)
    {
    EmployeeBusinessLayer bal = new EmployeeBusinessLayer();
    if (bal.IsValidUser(u))
    {
    FormsAuthentication.SetAuthCookie(u.UserName, false);
    return RedirectToAction("Index", "Employee");
    }
    else
    {
    ModelState.AddModelError("CredentialError", "Invalid Username or Password");
    return View("Login");
    }
    }

讓我們理解下上述代碼區域。

  • 如果你記得「第三天 — Lab 13」中我們所談論的 ModelState,那么就能理解它包含了模型的狀態。它包含了當前模型的錯誤信息。在上述的代碼片段中,當用戶是一個非法用戶時,就增加一個新的錯誤。(錯誤由鍵值「CredentialError」和信息「Invalid UserName or Password」組成)

  • 表單認證。SetAuthCookie 將會在客戶機器上創建一個新的 Cookie。

第十步:在視圖中呈現信息

打開 Login 視圖,在 @Html.BeginForm 上增加一小段代碼。

@Html.ValidationMessage("CredentialError", new {style="color:red;" })
@using (Html.BeginForm("DoLogin", "Authentication", FormMethod.Post))

第十一步:執行并測試

按下 F5 并執行應用。直切發起一個指向 Login Action 的請求。我相信你現在已經知道如何去做。

注:如果你想發起一個指向 EmployeeController 中 Index Action 的請求,它會重新導向到 Login Action。

  • Test 1
7 天玩轉 ASP.NET MVC — 第 4 天
7 天玩轉 ASP.NET MVC — 第 4 天
  • Test 2
7 天玩轉 ASP.NET MVC — 第 4 天
7 天玩轉 ASP.NET MVC — 第 4 天

Lab 17 的 Q&A

為什么 DoLogin 會附上 HttpPost 屬性?

這個屬性可以使 DoLogin 行為方法只為 Post 請求開啟。如果想試圖得到一個 DoLogin 的請求,將不會起作用。

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

我們還有其它類似的屬性嗎?

答案是肯定的。我們有 HttpGet,HttpPut 和 HttpDelete。作為一個最佳實踐,每一個行為方法都應該被附上這樣的屬性。

注意:為了保持代碼和學習是輕松并簡單的,我們在這個系列學習中并沒有全部都遵循最佳實踐,但是我們建議你在項目中遵循。

在我們持續的學習中,我們將會繼續談論最佳實踐。

FormsAuthentication.SetAuthCookie 是必須要寫的嗎?

答案是肯定的。

讓我們來理解一個小的程序。

  • 用戶通過瀏覽器向服務器發送請求。

  • 當請求通過瀏覽器發出,所有相關聯的 Cookies 將會伴隨著請求。

  • 服務器接收到請求并且準備發出響應。

  • 現在我們已經知道請求和響應是通過 HTTP 協議,并且 HTTP 是無關國籍的。對于服務器而言,每一個請求都是一個新的請求,因此當相同的用戶發出兩次請求時,服務器并不能夠識別它。為了解決這個問題,服務器在準備響應的時候增加了 Cookie,然后返回響應。

  • 當客戶端瀏覽器接收到伴隨著 Cookie 的響應后,它將會在客戶端創建 Cookies。

  • 現在客戶又一次發出請求,服務器將會識別他,因為請求中包含了 Cookies。

FormsAuthentication.SetAuthCookie 將會向響應增加一個特殊的 Cookie,命名為「Authentication」。

如果沒有 Cookies,是不是意味著 FormsAuthentication 就不會起作用?

答案是否定的。我們有替代物。我們可以運用 URI,而不是 Cookies。

打開 Web.config,然后更改「Authentication/Forms」區域如下。

<forms cookieless="UseUri" loginurl="~/Authentication/Login"></forms>
7 天玩轉 ASP.NET MVC — 第 4 天
7 天玩轉 ASP.NET MVC — 第 4 天

正如你所看見的,現在認證 Cookie 通過 URL 它自己傳輸。

默認情況下,Cookieless 屬性會被設置為「AutoDetect」。這意味著認證工作通過 Cookie 完成,在這種情景下,Cookies 將不會支持通過 URL 傳輸。

FormsAuthentication.SetAuthCookie 的第二個參數起到什么作用?

這決定了我們是否愿意創建一個永久的 Cookie。非永久的 Cookie 將會在瀏覽器關閉時自動刪除。永久性的 Cookies 將不會被自動刪除。我們可以通過代碼或者瀏覽器設置手動刪除。

通過代碼做到登出?

我們將會在以后的 Lab 中學習。

當認證失敗時,UserName 文本框將會如何被填充?

這是 HTML Helper 類的神奇之處。它們將會在控件中填充來自 Posted 數據的值。這是運用 HTML Helper 類的其中一個優勢。

@Html.ValidationMessage 是做什么的?

我們在 Lab 13 中已經探討過了。它根據鍵值呈現 ModelState 的錯誤。

Authorize 屬性是做什么的?

在 ASP.NET MVC 中,存在一個概念叫做 Filters。運用它可以過濾請求和響應。這里存在四種過濾器。我們將會在第七天的學習中探討它們。Authorize 屬性通過 Authorization 過濾器得出。這樣可以確保只有認證過的請求允許指向動作方法。

我們可以在一個行為方法中同時附上 HttpPost 和 Authorize 屬性嗎?

答案是肯定的。

在這個例子中,為什么沒有 ViewModel?

在 Lab 6 中我們所探討的,View 應該和 Model 直接相關聯。我們必須有 View 和 Model 中的 ViewModel。視圖是展示視圖或者數據入口視圖都不重要,它們都應該和 ViewModel 相關聯。在真實項目中,我強烈希望你全部都運用上 ViewModel。

對于每一個行為方法都必須附上 Authorize 屬性嗎?

答案是否定的。我們可以附上它 Controller 級別或者 Global 級別。當附上 Controller 級別,它將可以適用于一個控制器里的所有行為方法。當附上 Global 級別,它將會適用于所有控制器里的所有行為方法。

  • Controller 級別:

    [Authorize]
    public class EmployeeController : Controller
    {
    ....

  • Global 級別:

第一步:從 App_start 文件夾下打開 FilterConfig.cs 文件

第二步:在 RegisterGlobalFilters 中增加一行

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());//Old line
    filters.Add(new AuthorizeAttribute());//New Line
}

第三步:向 AuthenticationController 附上 AllowAnonymous 屬性

[AllowAnonymous]
public class AuthenticationController : Controller
{

第四步:執行并測試應用

「filters.Add(new HandleErrorAttribute())」是用來做什么的?

我們將會在日后的試驗中探討這個問題的細節。

為什么 AuthenticationController 中需要加上 AllowAnonymous 屬性?

我們已經附上了 Global 級別的 Authorize 過濾器。這意味著所有的方法都將是受保護的,包括 Login 和 DoLogin 行為方法。AllowAnonymous 為未認證的請求開啟了行為方法。

FilterConfig 類中的 RegisterGlobalFilters 方法如何被觸發的?

它通過 Global.asax 文件內的 Application_Start 事件所觸發。

4. Lab 18 — 在視圖中展示 UserName

在本實驗中,我們將在視圖中呈現當前登錄的用戶名。

第一步:在 ViewModel 中增加 UserName

打開 EmployeeListViewModel,然后增加一個新的屬性,即 UserName。

public class EmployeeListViewModel
{
    public List<EmployeeViewModel><employeeviewmodel> Employees { get; set; }
    public string UserName { get; set; }
}

第二步:向 ViewModel 的UserName 設置值

打開 EmployeeController,然后更改 Index 方法如下。

public ActionResult Index()
{
    EmployeeListViewModel employeeListViewModel = new EmployeeListViewModel();
    employeeListViewModel.UserName = User.Identity.Name; //New Line
......

第三步:在視圖中呈現 UserName

打開 Index.cshtml 視圖,呈現 UserName。

<body>
  <div style="text-align:right"> Hello, @Model.UserName </div>
  <hr />
  <a  href="/Employee/AddNew">Add New</a>
    <div>
       <table border="1"><span style="font-size: 9pt;"> 
</span>

第四步:執行并測試

按下 F5 并執行應用。完成登錄操作后,你將會看到如下輸出。

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

5. Lab 19 — 實現登出

第一步:創建登出鏈接

打開 Index.cshtml 文件然后創建登出鏈接。

<body>
    <div style="text-align:right">Hello, @Model.UserName
    <a href="/Authentication/Logout">Logout</a></div>
    <hr />
    <a  href="/Employee/AddNew">Add New</a>
    <div>
        <table border="1">

第二步:創建登出行為方法

打開 AuthenticationController,然后增加一個行為方法,命名為 Logout。

public ActionResult Logout()
{
    FormsAuthentication.SignOut();
    return RedirectToAction("Login");
}

第三步:執行并測試

按下 F5 并執行應用。

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

6. Lab 20 — 在 Login 頁實現認證

第一步:增加數據注釋

打開 UserDetails.cs,然后增加 Data Annotation。

public class UserDetails
{

[StringLength(7,MinimumLength=2, ErrorMessage = "UserName length should be between 2 and 7")]
    public string UserName { get; set; }
    public string Password { get; set; }
}

第二步:在視圖中呈現錯誤信息

改變 Login.cshtml,呈現錯誤信息。

@using (Html.BeginForm("DoLogin", "Authentication", FormMethod.Post))
{
    @Html.LabelFor(c=>c.UserName)
    @Html.TextBoxFor(x=>x.UserName)
    @Html.ValidationMessageFor(x=>x.UserName)
......

注:這次我們運用 Html.ValidationMessageFor,而不是Html.ValidationMessage。兩個做的是同一件事。Html.ValidationMessageFor 只能用于強類型視圖。

第三步:改變 DoLogin

改變 DoLogin 行為方法如下:

[HttpPost]
public ActionResult DoLogin(UserDetails u)
{
    if (ModelState.IsValid)
    {
        EmployeeBusinessLayer bal = new EmployeeBusinessLayer();
        if (bal.IsValidUser(u))
        {
            FormsAuthentication.SetAuthCookie(u.UserName, false);
            return RedirectToAction("Index", "Employee");
        }
        else
        {
            ModelState.AddModelError("CredentialError", "Invalid Username or Password");
            return View("Login");
        }
    }
    else
    {
        return View("Login");
    }
}

第四步:執行并測試

按下 F5 并執行應用

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

7. Lab 21 — 在 Login 頁實現客戶端的認證

這次我們將以不同的方式實現客戶端的認證。

第一步:下載 JQuery Unobtrusive Validation 文件

右擊項目,選擇「Manage Nuget Packages」。

點擊 Online,然后搜索「JQuery Unobtrusive」。

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

安裝「Microsoft JQuery Unobtrusive Validation」。

第二步:在視圖中引入 JQuery Validation 文件

在 Scripts 文件夾下增加三個 JavaScripts 文件。

  • JQuery-Someversion.js

  • JQuery.validate.js

  • JQuery.validate.unobtrusive

打開 Login.cshtml 文件,然后在頭部引入這三個 JavaScript 文件。

<script src="~/Scripts/jquery-1.8.0.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>

第三步:執行并測試

按下 F5,執行應用。

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

8. Lab 21 的 Q&A

客戶端的認證是如何實現的?

正如你所看見的,不費多少力氣就實現了客戶端的認證。在 Login 視圖中,HTML 元素通過 HTML Helper 類產生。Helper 函數能夠根據數據注釋屬性來生成帶有屬性附加的 HTML 標記。

例如:

@Html.TextBoxFor(x=>x.UserName)
@Html.ValidationMessageFor(x=>x.UserName)

上述的代碼產生如下的 HTML 代碼。

<input data-val="true" data-val-length="UserName length should be between 2 and 7" data-val-length-max="7" data-val-length-min="2" id="UserName" name="UserName" type="text" value="" />
<span class="field-validation-error" data-valmsg-for="UserName" data-valmsg-replace="true"> 
</span>

這些自定義的 HTML 屬性將會被「JQuery Unobtrusive Validation」文件使用,因此在客戶端自動實現認證。

自動的客戶端認證是 HTML Helper 類的第二個優勢。

Unobtrusive JavaScript 的意思是什么?

下面是 Wikipedia 所述。譯文為:

Unobtrusive JavaScript 是一個在 Web 頁面中常用的 JavaScript 方法。盡管它沒有被正式定義,但是它的幾個基本的準則可以被大概理解:

  • 從 Web 頁面的結構或者內容中分離的功能("Behaviour Layer"),并且展示。

  • 傳統的 JavaScript 編程中,最佳避免問題的實踐。(例如瀏覽器的不一致性和缺乏伸縮性)

  • 逐步增強支持用戶可能不先進的 JavaScript 功能。

讓我以外行來定義一下。

「以一種方式來寫你的 JavaScript,這種 JavaScript 不能與 HTML 強聯系。JavaScript 可能訪問 DOM 元素,JavaScript 可能操作 DOM 元素,但是并不和它們直接聯系。」

在上述例子中,JQuery Unobtrusive JavaScript 簡單地運用一些輸入元素屬性和實現客戶端認證。

我們可以運用這些 JavaScript 來認證,而不是采用 HTML Helper 類嗎?

答案是肯定的,對于這種方式,我們需要手動地向元素附件屬性。

哪個更推崇,是 HTML Helper 函數還是純 HTML?

我個人更傾向于純 HTML,因為 HTML Helper 函數又一次用到了「Full Control over HTML」,而這個弊端我們曾討論過。

其次我們討論下使用 JavaScript 框架或庫,而不是使用 JQuery 的項目情況。一些框架例如 Angular。在這種情況下,大多數我們都會考慮 Angular 認證,并且自定義的 HTML 認證屬性將會拋棄。

9. 總結

現在我們已經完成了第四天的學習。在第五天中,我們將會有更進一步的學習,會更有樂趣。

原文地址:Learn MVC Project in 7 days

本文系 OneAPM 工程師編譯整理。OneAPM 是應用性能管理領域的新興領軍企業,能幫助企業用戶和開發者輕松實現:緩慢的程序代碼和 SQL 語句的實時抓取。想閱讀更多技術文章,請訪問 OneAPM 官方博客

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,013評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,146評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,534評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,767評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,318評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,074評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,258評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,486評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,993評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,234評論 2 375

推薦閱讀更多精彩內容