2018 年 3 月

第 33 卷,第 3 期

本文章是由機器翻譯。

ASP.NET - 使用 Razor 在單頁應用程式中產生 HTML 範本

Nick Harrison

單一頁面應用程式 (SPA) 應用程式是非常普遍,原因。使用者期望有快速,Web 應用程式參與,並從智慧型手機寬螢幕桌面的每個裝置上運作。此外,它們必須是安全的視覺效果多樣的進行有用的動作。是從 Web 應用程式要求,但是這實際上是開始的點。

當使用者啟動需要更多 Web 應用程式,時發生爆炸用戶端架構,「 說明 」 所提供的模型-檢視-ViewModel (MVVM) 模式的用戶端實作。它可以似乎沒有新的架構每週。某些經證實非常實用,其他人不太多。但所有這些實作的設計模式以不同的方式,加入新功能,或解決週期性的問題,以自己的方式。每個架構會取用不同的方式向設計模式中,以唯一的語法,範本和簡介自訂處理站、 模組和可預見值等概念。結果是 vogue 的可以 frustrate 嘗試為新的架構移入和登出保持最新的開發人員清晰學習曲線。我們可以簡化學習曲線進行的任何項目是個好方法。

具有用戶端架構實作 MVVM 模式和 ASP.NET MVC 模式在伺服器上的導致一些混淆的實作。您要如何混合搭配 MVVM 用戶端的伺服器端 MVC?許多,答案是簡單:它們不混合在一起。常見的作法是建立靜態 HTML 頁面或片段及具有最少的伺服器端處理將它們傳遞給用戶端。在此案例中,Web API 控制器通常可能會取代將已處理之 MVC 控制器在過去的處理。

做為圖 1沒有最基本的 Web API 的 Web 伺服器和完整功能的伺服器需求,而且這兩個伺服器必須要能在防火牆之外顯示。

一般應用程式版面配置
圖 1 一般應用程式版面配置

這種安排可提供良好的分隔的考量,已寫入許多應用程式遵循此模式中,但身為開發人員,您讓許多資料表上。ASP.NET 具有更多提供,其實作的 MVC 提供許多功能仍然相關,即使其中一個用戶端架構執行大部分繁重的工作。在本文中,我將焦點放在其中的功能,Razor 檢視引擎。

Razor 中 SPA

Razor 檢視引擎是 marvel 時簡化產生的 HTML 標記。只要幾做調整,以符合範本對用戶端會使用任何架構輕易自訂產生的標記。我將會反白顯示一些範例 Angular 與 Knockout,但這些技術會不論您採用的架構。若要回到伺服器的呼叫提供您的應用程式的範本,您現在可以使用 Razor 要產生 HTML 困難。

有很多這裡偏好。EditorTemplates 和 DisplayTemplates 仍是您的朋友 scaffolding 範本時。您仍然可以將插入部分檢視和 Razor 語法的流暢流程是使用對您來說仍然存在。超出您也可以使用 MVC 控制器的檢視,其中可以若要加速進行的處理能力加總,或新增一層額外的安全性。如果這不需要控制站可能是簡單傳遞至檢視。

若要示範如何使用此程式的效益,我會逐步執行階段追蹤應用程式中,某些資料輸入螢幕的建立顯示 Razor 如何協助加速適合 Angular 或 Knockout 使用 HTML 建立。

做為圖 2所示,從一般的版面配置不太多變更。我已包含顯示在 MVC 應用程式可與資料庫互動的選項。在這個階段,這並非必要,但如果它可簡化您的處理,並使用。一般情況下,流程看起來像:

  • 從 MVC 應用程式,包括所有的樣式表和 JavaScript 的參考和最少的內容擷取完整的頁面。
  • 一旦頁面已完全載入瀏覽器和初始化的 framework 中,架構就可以呼叫 MVC 伺服器要求做為部分檢視的範本。
  • 此範本會產生含有 Razor,通常沒有任何相關聯的資料。
  • 同時,架構會讓應用程式開發介面呼叫,以取得的資料,會收到來自 MVC 網站範本繫結。
  • 一旦使用者進行任何必要的編輯,架構會呼叫 Web API 伺服器更新後端資料庫。

在 Razor 中加入簡單的流程
圖 2 Razor 中加入簡單的流程

視需要要求新的範本時,會重複執行此工作流程。如果此架構可讓您指定的 URL 範本,範本可以提供 MVC。當我將示範 Angular 和 Knockout 中產生適用於繫結的檢視表的範例時,請注意,這些都是難以僅有的選項。

設定方案

安裝程式的觀點而言,您需要至少三個專案。其中一個 Web api,另一個用於 MVC 應用程式,最後,一般常見這些兩個專案之間的裝載程式碼專案。基於本文章的詳細資訊,通用專案將會裝載 ViewModels,讓他們可以使用在 Web 主控台和 Web API。結構會初始專案中所示圖 3

初期的專案結構
圖 3 初始專案結構

在真實世界中,您將只支援一個用戶端架構。這個發行項,簡化具有兩個 MVC 專案,一個用於每個架構,來示範如何影響結果。如果您需要支援的 Web 應用程式、 自訂的行動應用程式、 SharePoint 應用程式、 桌面應用程式或無法輕易的方式轉譯,常見的 UI 專案的任何其他案例,您可能遇到類似的項目。不論如何,只將內嵌在 UI 專案中的邏輯必須支援多個前端重複。

匯入資料

在實務上,您的資料會儲存在資料庫中,有可能使用例如 Entity Framework 物件關聯式對應 (ORM) 中。在這裡,我將偏方將焦點放在後端的資料持續性的問題。我將會依賴 Web API 控制器中取得動作傳回硬式編碼值,將會執行這些範例在理想的世界裡,其中每個 API 呼叫會傳回成功。新增適當的錯誤處理會做為練習保留讓您輕易打敗讀取器。

此範例中會使用單一的檢視模型裝飾 System.ComponentModel.DataAnnotations 命名空間的屬性中所示圖 4

圖 4 簡單 TimeEntryViewModel

namespace TimeTracking.Common.ViewModels
{
  public class TimeEntryViewModel
  {
    [Key]
    public int Id { get; set; }
    [Required (ErrorMessage ="All time entries must always be entered")]
    [DateRangeValidator (ErrorMessage ="Date is outside of expected range",
      MinimalDateOffset =-5, MaximumDateOffset =0)]
    public DateTime StartTime { get; set; }
    [DateRangeValidator(ErrorMessage = "Date is outside of expected range",
      MinimalDateOffset = -5, MaximumDateOffset = 0)]
    public DateTime EndTime { get; set; }
    [StringLength (128, ErrorMessage =
      "Task name should be less than 128 characters")]
    [Required (ErrorMessage ="All time entries should be associated with a task")]
    public string Task { get; set; }
    public string Comment { get; set; }
  }
}

DateRangeValidator 屬性並不是來自 DataAnnotations 命名空間。這不是標準的驗證屬性,但圖 5示範可以如何輕鬆地建立新的驗證程式。一旦套用,它的行為就像標準的驗證程式。

圖 5 自訂驗證程式

public class DateRangeValidator : ValidationAttribute
{
  public int MinimalDateOffset { get; set; }
  public int MaximumDateOffset { get; set; }
  protected override ValidationResult IsValid(object value,
    ValidationContext validationContext)
  {
    if (!(value is DateTime))
      return new ValidationResult("Inputted value is not a date");
    var date = (DateTime)value;
    if ((date >= DateTime.Today.AddDays(MinimalDateOffset)) &&
      date <=  DateTime.Today.AddDays(MaximumDateOffset))
      return ValidationResult.Success;
    return new ValidationResult(ErrorMessage);
  }
}

每當驗證模型,將會執行所有驗證程式,包括任何自訂驗證程式。建立 razor 檢視可以輕易地將這些驗證用戶端,以及這些驗證程式會自動在伺服器上評估模型繫結器。驗證使用者輸入為索引鍵有更安全的系統。

API 控制器

現在,我已經檢視模型,我已準備好產生控制器。我將使用內建的 scaffolding 出控制器虛設常式。這會建立方法 (Get、 Post、 Put、 Delete) 的標準動詞命令為基礎的動作。這篇文章的目的而言,我不擔心這些動作的詳細資料。我只想要確認已將呼叫從用戶端架構的端點。

建立檢視 (View)

接下來,開啟我注意到內建的 scaffolding 會從檢視模型產生檢視。

在 TimeTracking.Web 專案中,我要加入新的控制器和命名 TimeEntryController 並將其建立為空白的控制器。此控制站,在建立編輯動作加入此程式碼:

public ActionResult Edit()
{
  return PartialView(new TimeEntryViewModel());
}

從這個方法,我要以滑鼠右鍵按一下並選取 [新增]] 檢視。 在快顯視窗中,我會指定,我想要編輯的範本,選取 TimeEntryViewModel 範本。

除了指定的模型,確定指定的部分檢視的建立。我想要產生的檢視,以加入只在產生的檢視中定義的標記。這個 HTML 片段會插入至用戶端上現有的頁面。由 scaffolding 所產生的標記範例所示圖 6

編輯檢視的圖 6 Razor 標記

@model TimeTracking.Common.ViewModels.TimeEntryViewModel
@using (Html.BeginForm())
{
  @Html.AntiForgeryToken()
  <div class="form-horizontal">
    <h4>TimeEntryViewModel</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    @Html.HiddenFor(model => model.Id)
    <div class="form-group">
      @Html.LabelFor(model => model.StartTime, htmlAttributes:
        new { @class = "control-label col-md-2" })
      <div class="col-md-10">
        @Html.EditorFor(model => model.StartTime,
          new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.StartTime, "",
          new { @class = "text-danger" })
      </div>
    </div>
    ...
  </div>
}
<div>
  @Html.ActionLink("Back to List", "Index")
</div>

有幾個重要注意事項與此產生的檢視,會立即產生能有效回應,啟動程序為基礎的 UI。這些工作包括:

  • 表單群組會重複檢視模型中每一個屬性。
  • Id 屬性為隱藏,因為它已經標記來將它識別為不是要修改的索引鍵的索引鍵屬性。
  • 每個輸入的欄位都有相關聯的驗證訊息的預留位置,如果已啟用不顯眼的驗證可以使用。
  • 所有標籤會都加入使用 LabelFor 協助專家,解譯的屬性來判斷適當的標籤上的中繼資料。DisplayAttribute 可以用於提供較佳的名稱,以及處理當地語系化。
  • 每個輸入的控制項加入使用 EditorFor 協助專家,解譯屬性來判斷適當的編輯器上的中繼資料。

中繼資料是在執行階段評估。這表示您可以將屬性加入至模型產生檢視之後,而且這些屬性會用來判斷驗證程式、 標籤和適當的編輯器。

樣板是一次性的程式碼產生,因為它是 [確定] 以編輯產生的標記,因為通常預期也一樣。

繫結至 Knockout

若要讓使用 Knockout 產生的標記,我需要將幾個屬性加入至產生的標記。我將不會深入深 Knockout 除了至。 請注意繫結會使用資料繫結屬性的內部工作。繫結宣告指定的繫結,然後屬性要使用的類型。我要加入的輸入控制項中的資料繫結屬性。您回查看產生的標記,請參閱如何加入類別屬性。遵循相同的程序,可以修改 EditorFor 函式中的程式碼所示:

@Html.EditorFor(model => model.StartTime,
  new { htmlAttributes = new { @class = "form-control",
         data_bind = "text: StartTime" } })

這是加入 Knockout 繫結所需的唯一變更是使用產生從 scaffolding 現成的標記。

繫結至角度

資料繫結與 Angular 很類似。我可以加入 ng 模型屬性或資料 ng 模型屬性。資料 ng 模型屬性會保留標記 HTML5 相容,但仍通常用於 ng 繫結。在任一情況下,屬性的值就是要繫結的屬性名稱。若要支援角度控制器要繫結,會修改 EditorFor 函式中,使用下列程式碼:

@Html.EditorFor(model => model.StartTime,
  new { htmlAttributes = new { @class     = "form-control",
                                  data_ng-model = "StartTime" } })

有幾個更多做一些調整因素來定義應用程式和控制器。請參閱完整的範例程式碼工作範例,若要查看這些變更的內容。

您可以採用類似的技巧,可以使工作產生的標記任何 MVVM 架構與您正在使用。

變更 Scaffolding

因為 scaffolding 使用 T4 來產生輸出,我可以變更內容產生為避免必須編輯產生的每個檢視。使用的範本會儲存在 Visual Studio 的安裝。針對 Visual Studio 2017,就可以看到這裡:

C:\Program Files (x86)\Microsoft Visual Studio 14.0\
  Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates\MvcView

您可以直接編輯這些範本,但這樣會影響您處理您的電腦,從每個專案和 else 處理專案的任何人都不會受益範本所做的編輯。相反地,您應該將 T4 範本加入至專案並且本機複本覆寫標準的實作。

只複製您想要的範本到資料夾,稱為 「 程式碼範本 」,您的專案根資料夾中。針對 C# 和 Visual Basic,您可以找到範本。語言會反映在 [檔案名稱。您只會需要一種語言的範本。當您叫用 scaffolding 從 Visual Studio 時,其看似 CodeTemplates 要使用的範本資料夾中。如果範本找不到那里,scaffolding 引擎會接著尋找在 Visual Studio 安裝。

T4 是功能強大的工具,一般產生的文字,不只是程式碼。了解它是一個大型的主題,其本身,但如果您不熟悉 T4 別擔心。這些是範本稍做調整。您必須以深深入了解 T4 運作方式的優勢,內部項目不需要,但是您必須下載擴充功能新增支援編輯 Visual Studio 中的 T4 範本。具體的 T4 編輯器 (bit.ly/2Flqiqt) 和 Devart T4 編輯器 (bit.ly/2qTO4GU) 都提供絕佳的 community 版本 T4 編輯器,編輯提供語法反白顯示的 T4 範本以便更容易磁碟機的範本,從範本所建立的程式碼的程式碼分開。

當您開啟 Edit.cs.t4 檔案時,您會發現控制項範本的程式碼區塊和區塊的標記程式碼。大部分開車範本的程式碼是條件式處理特殊的情況下,例如支援部分頁面,以及處理特殊類型的屬性,例如外部索引鍵、 列舉和布林值處理。圖 7使用適當的延伸模組時,Visual Studio 中顯示範本的範例。開車範本的程式碼會隱藏在摺疊章節中,以便更容易看到的輸出會是。

在 Visual Studio 編輯 T4 範本
圖 7 Visual Studio 編輯 T4 範本

幸運的是,您不需要透過這些條件的追蹤。相反地,尋找您想要變更產生的標記。在此情況下,注意約六個不同的陳述式。它們供您參考中擷取圖 8

圖 8 原始產生程式碼編輯器

@Html.DropDownList("<#= property.PropertyName #>", null,
  htmlAttributes: new { @class = "form-control" })
@Html.DropDownList("<#= property.PropertyName #>", String.Empty)
@Html.EditorFor(model => model.<#= property.PropertyName #>)
@Html.EnumDropDownListFor(model => model.<#= property.PropertyName #>,
  htmlAttributes: new { @class = "form-control" })
@Html.EditorFor(model => model.<#= property.PropertyName #>,
  new { htmlAttributes = new { @class = "form-control" } })
@Html.EditorFor(model => model.<#= property.PropertyName #>)

一旦您進行更新以支援您特定的用戶端架構,與範本產生的所有新檢視將會自動支援您的架構。

用戶端驗證

當我檢查所產生的檢視時,我會跳過會針對每一個屬性的 ValidationMessageFor 函式呼叫。這些呼叫會產生顯示任何驗證訊息,建立要在評估用戶端驗證時的預留位置。這些驗證根據加入至模型的驗證屬性。若要啟用這些用戶端驗證所需的所有已新增 jquery 驗證指令碼的參考:

@Scripts.Render("~/bundles/jqueryval")

Jqueryval 組合定義 BundleConfig 類別從 App_Start 資料夾中。

如果您嘗試送出表單時,不需要輸入任何資料時,必要的欄位驗證將會觸發以避免送出。

如果您偏好之不同的驗證策略用戶端,例如啟動程序的表單驗證 (bit.ly/2CZmRqR),您可以輕鬆地修改要輸出 ValidationMessageFor 呼叫的 T4 範本。如果您不使用原生的驗證方法,就不需要參考 jqueryval 組合,因為它將不再需要。

編輯器範本

因為我呼叫 EditorFor html helper 來指定的輸入的控制項,所以我未明確指定的輸入的控制項應該什麼。MVC framework 屬性来使用的最適當的輸入的控制項指定,我離開的相反地,根據資料類型或 UIHint 等屬性。我可以明確建立 EditorTemplate,也會直接影響編輯器選取項目。這可讓我控制會在全域層級如何處理特定類型的輸入。

日期時間屬性的預設編輯器是文字方塊。不最理想的編輯器,但是可以變更。

我要加入至資料夾 \Views\Shared\EditorTemplates 呼叫 DateTime.cshtml 部分檢視。標記加入至這個檔案會作為 DateTime 類型的任何屬性的編輯器。加入所示的標記圖 9為 partial 檢視,並將下列程式碼加入至 Layout.cshtml 下方:

<script>
  $(document).ready(function () {
    $(".date").datetimepicker();
  });
</script>
Figure 9 Markup for a DateTime Editor
@model DateTime?
<div class="container">
  <div class="row">
    <div class='col-md-10'>
      <div class="form-group ">
        <div class='input-group date'>
         <span class="input-group-addon">
           <span class="glyphicon glyphicon-calendar"></span>
         </span>
         @Html.TextBox("", (Model.HasValue ?
           Model.Value.ToShortDateString() :
           string.Empty), new
           {
             @class = "form-control"
           })
        </div>
      </div>
    </div>
  </div>
</div>

一旦加入這些程式碼項目之後,我得到不錯的日期和時間編輯器來編輯日期時間屬性。圖 10顯示作用中的這個新的編輯器。

啟動的日期選擇器
圖 10 啟動的日期選擇器

總結

如您所見,Razor 可以進行以簡化和加速您想要使用的檢視中的任何用戶端 MVVM 架構建立許多。您可以自由支援應用程式樣式和慣例,以及 scaffolding 和 EditorTemplates 等功能協助確保您的應用程式之間的一致性。它們也會啟用內建支援根據屬性加入至您的檢視模型,讓您的應用程式更安全的驗證。

第二個看看 ASP.NET MVC,您會發現許多仍是相關且很有用,即使隨著 Web 應用程式的橫向持續變更的區域。


Nick Harrison與愛心妻子 Tracy 哥倫比亞,S.C.,在生動的 」 和 「 女兒是軟體顧問。他一直在開發使用.NET 2002年自建立商務解決方案的完整堆疊。在 Twitter 上連絡他: @Neh123us、 其中他也宣佈他的部落格文章,已發行的運作方式以及讀出合作。

非常感謝下列技術專家檢閱這篇文章:Lide Winburn (Softdocks Inc.)
Lide Winburn 是 Softdocs,Inc.,他可協助學校移不見得在雲端架構設計人員。他也是 beer league hockey player 和勤影片 goer 與他的系列。


MSDN Magazine 論壇中的這篇文章的討論