ASP.NET MVC

覆寫預設 Scaffold 樣板

Jonathan Waldman

下載代碼示例

編寫常式的常見任務創建、 檢索、 更新和刪除操作針對資料存儲區恰如其分地傳達的 CRUD 經常使用首字母縮寫。 Microsoft 提供了一個有用腳手架的引擎,T4 範本由供電自動化ASP.NETMVC 應用程式,使用Entity Framework中創建基本的 CRUD 控制器和模型的視圖。 (還有 WebAPI 和 MVCEntity Framework棚架工人沒有當前可用。)

支架生成通航和可用的頁。 他們普遍減輕你所涉及的建造 CRUD 頁單調。 然而,基架的結果提供這種有限的功能,你很快就發現自己調整的生成的控制器邏輯和意見,以滿足您的需要。

在這樣做的危險是腳手架是一個單向過程。 您不能重新腳手架您的控制器和視圖以反映模型中的更改而不會覆蓋您的調整。 因此,你必須保持警惕,跟蹤哪些模組已經自訂了,所以你可以知道哪些型號你可以安全地重新腳手架和哪些是你不能。

在團隊環境中,此保持警惕是很難實施。 最糟的編輯控制器大多數模型屬性上顯示編輯檢視中,從而有可能公開敏感資訊。 它盲目模型綁定,並堅持認為提交的所有屬性,這就增加了大眾轉讓攻擊的風險。

在這篇文章,我就會顯示你如何創建專案特定的 T4 範本的自訂這種力量ASP.NETMVCEntity FrameworkCRUD 腳手架子系統。 一路走來,看你如何擴展控制器的創建和編輯回發處理常式使您可以插入您自己的代碼之間的回發模型綁定和資料存儲持久性。

解決大規模分配問題,我將創建自訂屬性,使您的模型屬性,應堅持和哪些不應該完全控制。 然後我將添加允許您顯示一個屬性作為唯讀的標籤,在編輯檢視上的另一個自訂屬性。

在此之後,你就會有空前控制您的 CRUD 頁以及如何顯示和降低您的應用程式暴露于攻擊的同時保持您的模型。 最重要的是,你將能夠充分利用這些技術為您ASP.NETMVC 專案中的所有模型並安全地重新組建控制器和意見作為您的模型更改。

專案設置

我開發這一解決方案使用Visual Studio2013年終極ASP.NETMVC 5Entity Framework6、、 C# (討論的技術也是與Visual Studio2013年專業、 保費和快遞的 Web 和Visual Basic的.NET 相容的)。 我創建了兩個下載解決方案:第一是該基線解決方案,您可以使用同一個工作專案啟動和手動實現這些技術。 第二個是完整的解決方案,其中包括所有的此處討論的改進。

每個解決方案包含三個專案:一個用於ASP.NETMVC Web 網站中,一個用於實體模型和 T4 支架功能,和一個用於資料上下文。 解決方案的資料上下文指向SQL ServerExpress 資料庫。 除了已經提到的依賴項,添加引導到主題使用 NuGet 的基架的意見。

檢查 Microsoft Web 開發工具安裝程式選項時,腳手架子系統被安裝過程中安裝。 隨後Visual Studio服務包將自動更新的腳手架檔。 你可以對發佈最新微軟 Web 平臺安裝程式中,您可以從下載的Visual Studio服務包之間的腳手架子系統的任何更新 bit.ly/1g42AhP

如果您有使用本文附帶的下載代碼的任何問題,請確保您擁有其最新版本並仔細閱讀 ReadMe.txt 檔。 根據需要就會更新。

定義的商務規則

為了說明完整的工作流程參與生成 CRUD 的意見,以及以減少分心,我要用一種非常簡單的實體模型,稱為產品的工作。

public class Product
{
  public int ProductId { get; set; }
  public string Description { get; set; }
  public DateTime?
CreatedDate { get; set; }
  public DateTime?
ModifiedDate { get; set; }
}

由公約 》,MVC 瞭解產品 id 是主鍵,但卻不知道我有特殊要求的 CreatedDate 和 ModifiedDate 的屬性有關。 他們的名字,意味著我希望 CreatedDate 轉達時被插入到資料庫中的產品問題 (由產品 id 表示)。 我也想要 ModifiedDate 傳達它的上次修改時間 (會使用 UTC 日期時間值)。

我想作為唯讀文本編輯檢視上顯示的 ModifiedDate 值 (如果不修改了該記錄,ModifiedDate 將等於 CreatedDate)。 我不想在任何視圖上顯示 CreatedDate。 我也不希望使用者能夠供應或修改這些日期值,所以我不想要呈現收集為他們在創建或編輯檢視上的輸入的任何表單控制項。

為了使這些值攻擊證明,我希望確保回發時,保持其值,是不是即使聰明的駭客是能夠提供他們作為表單欄位或查詢字串值。 因為我認為這些業務邏輯層規則,我不想要有任何負責維護這些列中的值的資料庫 (例如,我不想創建任何觸發器或嵌入任何表格列定義邏輯)。

探索的 CRUD 腳手架工作流

讓我們先檢查預設腳手架功能。 我將添加一個控制器,右擊 Web 專案的控制器資料夾,然後選擇添加控制器。 這將啟動添加腳手架對話方塊 (請參閱圖 1)。

The MVC 5 Add Scaffold Dialog
圖 1 5 MVC 添加腳手架對話方塊

該條目的"MVC 5 控制器與視圖,使用Entity Framework"是我就會使用,因為它支架的 CRUD 控制器和模型的視圖。 請選擇該條目,按一下添加。 下一個對話方塊中為您提供大量的選項,最終作為它隨後變換的 T4 範本的參數 (請參見圖 2)。

The Add Controller Dialog
圖 2 添加控制器對話方塊

輸入 ProductController 作為該控制器的名稱。 保留"使用非同步控制器操作"核取方塊未選中為便於討論 (非同步作業是超出了本文的範圍)。 下一步,選擇的產品模型的類。 因為您使用的Entity Framework,你需要一個資料上下文類。 如果您的解決方案使用多個資料庫上下文,從 System.Data.Entity.DbCoNtext 繼承類將出現在下拉清單中,所以選擇正確的一個。 有關視圖選項,請檢查"生成視圖"和"使用佈局頁面"。將佈局頁面文字方塊保留為空。

當您按一下添加時,幾個 T4 範本進行轉換以提供基架的結果。 這一過程為一個控制器 (ProductController.cs) 寫入 Web 專案的資料夾中控制器和五個視圖 (Create.cshtml、 Delete.cshtml、 Details.cshtml、 Edit.cshtml 和 Index.cshtml) 都寫入到 Web 專案的視圖資料夾中生成代碼。 此時,你有工作的控制器和所有你需要管理的資料在產品實體中的 CRUD 意見。 您可以開始使用這些 Web 頁馬上開始帶有索引視圖。

您可能會希望你 CRUD 頁的外觀和行為同樣為您的專案中的所有模型。 使用 T4 範本,腳手架的 CRUD 頁有助於強制執行這種一致性。 這意味著你應該抵制誘惑直接修改控制器和視圖。 相反,您應該修改的 T4 範本,生成它們。 按照這一做法,確保您的基架的檔準備就緒可使用作任何進一步的修改。

檢查控制器的缺點

雖然腳手架子系統起床你和運行相當迅速,控制器就會生成有幾個缺點。 我會教你怎麼做一些改進。 看看處理創建的基架的控制器操作方法並在編輯圖 3

圖 3 的基架的控制器操作方法進行創建和編輯

public ActionResult Create(
  [Bind(Include="ProductId,Description,CreatedDate,ModifiedDate")] 
  Product product)
{
  if (ModelState.IsValid)
  {
    db.Products.Add(product);
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(product);
}
public ActionResult Edit(
  [Bind(Include="ProductId,Description,CreatedDate,ModifiedDate")] 
  Product product)
{
  if (ModelState.IsValid)
  {
    db.Entry(product).State = EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(product);
}

每個方法的綁定屬性顯式包括每個屬性上的產品型號。 當一個 MVC 控制器模型在回發後綁定模型的所有屬性時,它被稱為大規模分配。 這也稱為 overposting,它是一個嚴重的安全性漏洞。 駭客可以利用此漏洞,因為那裡是隨後 SaveChanges 調用上的資料庫上下文。 這可確保模型獲取保存到資料存儲區。 MVC 5 中的 CRUD 腳手架系統使用的控制器範本生成大規模分配代碼,預設情況下創建和編輯操作回發方法。

如果您選擇裝飾上,模型的某些屬性,所以它們不呈現給創建或編輯檢視,就會發生大規模分配的另一個後果。 這些屬性將被設置為 null 後模型綁定。 (見"使用屬性對抑制屬性上 CRUD 的意見,"包含您可以使用指定是否你應該呈現基架的屬性到生成的視圖的屬性)。為了說明問題,我會首先將兩個屬性添加到產品模型:

public class Product
{
  public int ProductId { get; set; }
  public string Description { get; set; }
  [ScaffoldColumn(false)]
  public DateTime?
CreatedDate { get; set; }
  [Editable(false)]
  public DateTime?
ModifiedDate { get; set; }
}

重新運行時使用添加控制器的腳手架過程如前文所述,[Scaffold(false)] 屬性可確保 CreatedDate 不會出現任何的意見。 [Editable(false)] 屬性確保 ModifiedDate 將會出現在刪除、 詳情和索引視圖,但不是創建或編輯的意見。 當屬性不被呈現到創建或編輯檢視,它們不會出現在回發的 HTTP 要求流。

這是有問題,因為你將值分配給這些 MVC 供電的 CRUD 頁中的模型屬性的最後機會是在回發期間。 所以如果屬性的回發值為 null,該空值要將模型綁定。 然後該模型要 SaveChanges 執行資料上下文物件上時將保存到資料存儲區。 如果這是編輯的回發操作方法中,該屬性將被替換為 null 值。 這有效地刪除資料存儲區中的當前值。

在我的示例中,舉行了由 CreatedDate 資料存儲區中的值將會丟失。 事實上,不會呈現到編輯檢視的任何屬性將導致資料存儲的值被覆蓋為 null。 如果模型屬性或資料存儲區不允許空值的分配,你會在回發時出現錯誤。 為了克服這些缺點,我會修改的 T4 範本,負責組建控制器。

重寫的腳手架範本

若要修改如何的控制器和視圖都啟用了基架,你必須修改的 T4 範本,生成它們。 您可以修改的原始範本,將全球範圍內影響腳手架跨所有Visual Studio專案。 您還可以修改具體專案的 T4 範本中,這只會影響拷貝都放入其中的專案的副本。 我會做,後者。

原始的 T4 腳手架範本都位於 %programfiles%\MicrosoftVisual Studio12.0\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates 資料夾。 (這些範本取決於幾個.NET 程式集,位於 %programfiles%\­MicrosoftVisual Studio12.0\Common7\IDE\Extensions\Microsoft\Web Tools\Scaffolding 資料夾.)我將重點在腳手架的Entity FrameworkCRUD 控制器和視圖的特定範本上。 這些在總結圖 4

圖 4 的 T4 範本,腳手架Entity FrameworkCRUD 控制器和視圖

腳手架範本的子資料夾名稱

範本檔的名稱

(.cs 的 C# 中 ; Visual Basic.NET.vb)

生成此檔

(.cs 的 C# 中 ; Visual Basic.NET.vb)

MvcControllerWithCoNtext

Controller.cs.t4

Controller.vb.t4

Controller.cs

Controller.vb

MvcView

Create.cs.t4

Create.vb.t4

Create.cshtml

Create.vbhtml

MvcView

Delete.cs.t4

Delete.vb.t4

Delete.cshtml

Delete.vbhtml

MvcView

Details.cs.t4

Details.vb.t4

Details.cshtml

Details.vbhtml

MvcView

Edit.cs.t4

Edit.vb.t4

Edit.cshtml

Edit.vbhtml

MvcView

Index.cshtml

Index.vbhtml

Index.cshtml

Index.vbhtml

若要創建特定于專案的範本,複製你想要從原來的 T4 支架資料夾覆蓋到一個資料夾中稱為的 CodeTemplates (它必須有此確切名稱)ASP.NETMVC Web 專案的檔。 公約 》,由腳手架子系統首先查找在 CodeTemplates 資料夾中的 MVC 專案範本匹配。

為此,必須精確地複製的特定子資料夾名稱和您看到的原始範本資料夾中的檔案名稱。 我已經複製我計畫重寫從Entity Framework腳手架子系統 CRUD 的 T4 檔。 看看我的 Web 專案中的 CodeTemplates 圖 5

The Web Project’s CodeTemplates
圖 5 Web 專案的 CodeTemplates

我也複製 Imports.include.t4 和 ModelMetadataFunctions.cs.include.t4。 該專案以腳手架意見需要這些檔。 五行只有 C# (.cs) 檔的版本 (如果您使用Visual Basic.NET,你會想要將包括.vb 檔的檔案名中的檔案複製)。 腳手架子系統將變換這些具體專案檔案,而不是它們的全球版本。

擴展創建和編輯操作方法

現在,我有具體專案 T4 範本,我可以根據需要對其進行修改。 第一,我就會延長控制器的創建和編輯操作方法,所以我可以檢查和修改模型之前它已經堅持了。 若要保留該範本生成的代碼盡可能通用,我不想向範本中添加任何模型特定的邏輯。 相反,我想調用外部函數綁定到模型。 這種方式,該控制器的創建和編輯被擴展雖然他們類比模型上的多態性。 為此目的,我會創建一個介面,並稱之為 IControllerHooks:

namespace JW_ScaffoldEnhancement.Models
{
  public interface IControllerHooks
  {
    void OnCreate();
    void OnEdit();
  }
}

接下來,我會修改的 Controller.cs.t4 範本 (在 CodeTemplates\­MVCControllerWithCoNtext 資料夾) 所以其創建和編輯的回發操作方法調用的模型裡面方法和 OnEdit 方法,分別,如果模型實施了 IControllerHooks。 該控制器的創建操作回發方法所示圖 6 和其創建行動回發方法所示圖 7

圖 6 控制器的擴展的版本的創建的回發操作方法

public ActionResult Create(
  [Bind(Include="ProductId,Description,CreatedDate,ModifiedDate")] 
  Product product)
{
  if (ModelState.IsValid)
  {
    if (product is IControllerHooks) { 
      ((IControllerHooks)product).OnCreate(); 
    }
    db.Products.Add(product);
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(product);
}

圖 7 擴展版本的控制器的編輯操作回發方法

public ActionResult Edit(
  [Bind(Include="ProductId,Description,CreatedDate,ModifiedDate")] 
  Product product)
{
  if (ModelState.IsValid)
  {
    if (product is IControllerHooks) { 
      ((IControllerHooks)product).OnEdit(); 
    }
    db.Entry(product).State = EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(product);
}

現在,我會修改產品類,所以它實現了 IController­掛鉤。 然後我將添加我想要當控制器調用裡面和 OnEdit 時執行的代碼。 新產品模型的類顯示在圖 8

圖 8 產品模型,實現 IControllerHooks 延長控制器

public class Product : IControllerHooks
{
  public int ProductId { get; set; }
  public string Description { get; set; }
  public DateTime?
CreatedDate { get; set; }
  public DateTime?
ModifiedDate { get; set; }
  public void OnCreate()
  {
    this.CreatedDate = DateTime.UtcNow;
    this.ModifiedDate = this.CreatedDate;
  }
  public void OnEdit()
  {
    this.ModifiedDate = DateTime.UtcNow;
  }
}

誠然,有很多方法實現此"擴展"的邏輯,但通過使用控制器範本的創建和編輯的方法對這一線改造,我現在可以修改的產品模型實例模型綁定之後但在持久性之前。 我甚至可以設置創建和編輯的意見也不會發佈的模型屬性的值。

你會遵守該模型的 OnEdit 函數並不將值設置為 CreatedDate。 如果 CreatedDate 不呈現到編輯檢視,它要後控制器的編輯操作方法仍然存在模型在它調用 SaveChanges 時被覆蓋一個 null 值。 為了防止這種情況的發生,我需要做一些進一步修改到控制器的範本。

加強編輯操作方法

我已經提到過一些與大規模分配有關的問題。 修改模型綁定行為的一種方法是修改綁定屬性,所以它排除了不是要綁定的屬性。 在實踐中,但是,這種方法可以仍然導致 null 值寫入資料存儲區。 更好的戰略涉及額外的程式設計,但是回報是值得努力。

我要使用Entity Framework連接方法來將模型附加到的資料庫上下文。 我然後可以跟蹤實體條目,並根據需要設置 IsModified 屬性。 駕駛這種邏輯,我將創建一個新的類別模組在 JW_Scaffold 中調用 CustomAttributes.cs­Enhancement.Models 專案 (請參閱圖 9)。

圖 9 新的類別模組 CustomAttributes.cs

using System;
namespace JW_ScaffoldEnhancement.Models
{ 
  public class PersistPropertyOnEdit : Attribute
  {
    public readonly bool PersistPostbackDataFlag;
    public PersistPropertyOnEdit(bool persistPostbackDataFlag)
    {
      this.PersistPostbackDataFlag = persistPostbackDataFlag;
    }
  }
}

我將使用此屬性以指示我不想將保存到資料存儲區從編輯檢視 (未修飾的屬性將會有一個隱式的 [PersistPropertyOnEdit(true)] 屬性) 的屬性。 我很感興趣從正在保持不變,防止 CreatedDate 屬性,所以我已經向僅自己的產品模型的 CreatedDate 屬性添加新的屬性。 新裝修的模型類如下所示:

public class Product : IControllerHooks
{
  public int ProductId { get; set; }
  public string Description { get; set; }
  [PersistPropertyOnEdit(false)]
  public DateTime?
CreatedDate { get; set; }
  public DateTime?
ModifiedDate { get; set; }
}

現在我需要修改 Controller.cs.t4 範本,所以它榮譽的新特性。 時提高 T4 範本,你可以選擇是否要對範本進行內的範本或外部的變化。 除非您使用協力廠商範本編輯器的工具之一,我主張盡可能在外部代碼模組中放置盡可能多的代碼。 這樣做的提供了一個純 C# 畫布 (而不是一個穿插 T4 標記) 在其中您可以專注于代碼的範圍內。 它還愛滋病測試,並讓您將您的功能整合到您更廣泛的測試控管工作方法。 最後,由於在如何從一個 T4 支架引用程式集的一些不足之處,您會遇到較少的技術問題,得到了有線的一切。

我的模型專案包含一個稱為 GetPropertyIsModifiedList,返回的字串 < > 清單的公共函數 我可以逐一查看生成的程式集和類型傳遞的 IsModified 設置。 圖 10 Controller.cs.t4 範本中顯示此代碼。

T4 Template Code Used To Generate an Improved Controller Edit Postback Handler
圖 10 T4 範本代碼,用於生成改進的控制器編輯回發處理常式

在 GetPropertyIsModifiedList,在顯示圖 11,反射用於獲取對所提供的模型屬性的訪問。 然後我迴圈跨他們來確定哪些使用 PersistPropertyOnEdit 屬性進行修飾。 你最有可能就會想要堅持的多數屬性對您的模型,所以我構建的範本代碼,預設情況下將 IsModified 屬性的值設置為 true。 這種方式,你需要做的就是向你不想保留的屬性添加 [PersistPropertyOnEdit(false)]。

圖 11 模型專案 ScaffoldFunctions.GetPropertyIsModifiedList 靜態函數

static public List<string> GetPropertyIsModifiedList(string ModelNamespace, 
  string ModelTypeName, 
  string ModelVariable)
{
  List<string> OutputList = new List<string>();
  // Get the properties of the model object
  string aqn = Assembly.CreateQualifiedName(ModelNamespace + 
    ", Version=1.0.0.0,
    Culture=neutral, PublicKeyToken=null", ModelNamespace + "." + 
    ModelTypeName);
  // Get a Type object based on the Assembly Qualified Name
  Type typeModel = Type.GetType(aqn);
  // Get the properties of the type
  PropertyInfo[] typeModelProperties = typeModel.GetProperties();
  PersistPropertyOnEdit persistPropertyOnEdit;
  foreach (PropertyInfo propertyInfo in typeModelProperties)
  {
    persistPropertyOnEdit = 
      (PersistPropertyOnEdit)Attribute.GetCustomAttribute(
      typeModel.GetProperty(propertyInfo.Name), typeof(PersistPropertyOnEdit));
    if (persistPropertyOnEdit == null)
    {
    OutputList.Add(ModelVariable + "Entry.Property(e => e." +
      propertyInfo.Name + ").IsModified = true;");
    }
    else
    {
    OutputList.Add(ModelVariable + "Entry.Property(e => e." +
      propertyInfo.Name + ").IsModified = " +
      ((PersistPropertyOnEdit)persistPropertyOnEdit).
PersistPostbackDataFlag.ToString().ToLower() + ";");
    }
  }
  return OutputList;
}

訂正的控制器範本生成一個新構想的看法的編輯回發操作方法,所示圖 12。 我的 GetPropertyIsModifiedList 函數生成此原始程式碼的某些部分。

圖 12 新基架控制器編輯處理常式

if (ModelState.IsValid)
{
  if (product is IControllerHooks) 
  {
   ((IControllerHooks)product).OnEdit(); 
  }
  db.Products.Attach(product);
  var productEntry = db.Entry(product);
  productEntry.Property(e => e.ProductId).IsModified = true;
  productEntry.Property(e => e.Description).IsModified = true;
  productEntry.Property(e => e.CreatedDate).IsModified = false;
  productEntry.Property(e => e.ModifiedDate).IsModified = true;
  db.SaveChanges();
  return RedirectToAction("Index");
}

使用屬性來禁止 CRUD 視圖的屬性

ASP.NETMVC 提供只有三個特性,它們提供一些控制模型屬性是否呈現的基架的意見 (見圖 A)。 (雖然它們駐留在不同的命名空間中) 的第一次兩個屬性做同樣的事情:[Editable(false)] 和 [ReadOnly(true)]。 這些將導致修飾的屬性,不會呈現的創建和編輯的意見。 第三,[ScaffoldColumn(false)],導致修飾的屬性不能出現在任何呈現的視圖。

圖 A 防止從呈現的屬性的三個屬性

模型的中繼資料屬性 Namespace 屬性 受影響的意見 會發生什麼
  沒有額外的屬性會導致只有正常結果。

[] Editable(false)

[] ReadOnly(true)

可編輯:

System.ComponentModel.DataAnnotations

唯讀:

System.ComponentModel

建立

編輯

裝飾模型屬性不會呈現。
[] ScaffoldColumn(false) System.ComponentModel.DataAnnotations

建立

刪除

詳細資料

編輯

索引

裝飾模型屬性不會呈現。

自訂視圖

有時你會想要在您不希望使用者編輯編輯檢視顯示的值。 ASP.NETMVC 提供屬性不支援這個。 我想看到 ModifiedDate 在編輯檢視中,但我不想讓使用者覺得它是一個可編輯的欄位。 要實現這一點,我會創建在此處所示的 CustomAttributes.cs 類別模組中調用 DisplayOnEditView 的另一個自訂屬性:

public class DisplayOnEditView : Attribute
{
  public readonly bool DisplayFlag;               
  public DisplayOnEditView(bool displayFlag)
  {
    this.DisplayFlag = displayFlag;
  }
}

這讓我裝飾模型屬性,所以它將呈現為編輯檢視上的標籤。 然後我就能夠在編輯檢視而不必擔心有人可以篡改其值在回發過程中顯示 ModifiedDate。

現在我可以使用該屬性來進一步裝飾的產品模型。 我會在 ModifiedDate 屬性上放置新的屬性。 我會使用 [Editable(false)] 以確保它不會顯示在創建視圖和 [DisplayOnEditView(true)] 以確保它顯示為編輯檢視上的標籤:

public class Product : IControllerHooks
{
  public int ProductId { get; set; }
  public string Description { get; set; }
  [PersistPropertyOnEdit(false)]
  [ScaffoldColumn(false)]
  public DateTime?
CreatedDate { get; set; }
  [Editable(false)]
  [DisplayOnEditView(true)]
  public DateTime?
ModifiedDate { get; set; }
}

最後,我會修改的 T4 範本的生成編輯檢視,因此,它給予榮譽的 DisplayOnEditView 屬性:

HtmlForDisplayOnEditViewAttribute =
  JW_ScaffoldEnhancement.Models.ScaffoldFunctions.
GetHtmlForDisplayOnEditViewAttribute(
  ViewDataTypeName, property.PropertyName,
  property.IsReadOnly);

我會將 GetHtmlForDisplayOnEditViewAttribute 函數添加到 ScaffoldFunctions 類,如中所示圖 13

GetHtmlForDisplayOnEditViewAttribute 函數返回的屬性為 false 時的 Html.EditorFor 和 Html.Display­TextFor 當該屬性為 true。 編輯檢視會顯示 ModifiedDate 作為一個標籤和所有其他非鍵欄位作為可編輯文字方塊,所示圖 14

圖 13 ScaffoldFunctions.GetHtmlForDisplayOnEditViewAttribute 靜態函數來支援自訂 DisplayOnEditViewFlag 屬性

static public string GetHtmlForDisplayOnEditViewAttribute(
  string ViewDataTypeName, string PropertyName, bool IsReadOnly)
{
  string returnValue = String.Empty;
  Attribute displayOnEditView = null;
  Type typeModel = Type.GetType(ViewDataTypeName);
  if (typeModel != null)
  {
    displayOnEditView =
    (DisplayOnEditView)Attribute.GetCustomAttribute(typeModel.GetProperty(
    PropertyName), typeof(DisplayOnEditView));
    if (displayOnEditView == null)
    {
      if (IsReadOnly)
      { returnValue = String.Empty; }
      else
      { returnValue = "@Html.EditorFor(model => model." + 
          PropertyName + ")"; }
    }
    else
    {                         
      if (((DisplayOnEditView)displayOnEditView).DisplayFlag == true)
      { returnValue = "@Html.DisplayTextFor(model => model." + 
          PropertyName + ")"; }
      else
      { returnValue = "@Html.EditorFor(model => model." + 
        PropertyName + ")"; }
    }
  }
  return returnValue;
}

圖 14 編輯檢視顯示一個唯讀的 ModifiedDate 欄位

總結

我只被抓了抓你可以完成與腳手架子系統的表面。 我專注的Entity Framework,提供一個 CRUD 控制項和視圖的支架,但有其他支架可用來為其他類型的 Web 頁和 Web API 操作生成的代碼。

如果您從來沒有過的 T4 範本,自訂現有範本是開始的好方法。 雖然我在這裡討論的範本從Visual StudioIDE 功能表啟動,你可以創建自訂的 T4 範本,並將它們必要時轉換。 Microsoft 提供了一個良好的起點,在 bit.ly/1coB616。 如果你要找一些更先進的我建議Dustin大衛斯課程 bit.ly/1bNiVXU

在這一次,Visual Studio2013年不包括一個魯棒的 T4 編輯器。 事實上,它不會提供語法突出顯示或IntelliSense。 幸運的是,有一些做的額外產品。查閱 Devart T4 編輯器 (bit.ly/1cabzOE) 和有形工程 T4 編輯器 (bit.ly/1fswFbo)。

Jonathan Waldman  是一個經驗豐富的軟體發展人員和技術建築師。他自成立以來一直都與 Microsoft 技術堆疊。他工作了幾個高知名度企業專案,參加了在軟體發展生命週期的各個方面。他是 Pluralsight 技術團隊的成員,並繼續開發軟體解決方案和教育材料。聯繫到他在 jonathan.waldman@live.com

感謝以下 Microsoft 技術專家對本文的審閱: Joost de Nijs
Joost de Nijs 是 Azure 開發人員體驗團隊在 Microsoft,對 Web 開發人員工裝工作程式經理。目前他被側重于 Web 腳手架和 NuGet 包管理功能領域,與以往關於 Windows AzureJAVA用戶端庫和 Windows Azure 開發人員中心的工作。