1. 程式人生 > >ASP.NET MVC 替換默認的基架模板

ASP.NET MVC 替換默認的基架模板

不想 esp black 函數返回 als work 相同 bae detail

在學習Asp.net Mvc中,今天第一次聽了基架,哈哈!

常用的首字母縮略詞 CRUD 恰當地傳達了根據數據存儲編寫例程創建、檢索、更新和刪除操作的普通任務。Microsoft 提供由 T4 模板強力驅動的實用基架引擎,可為使用實體框架的 ASP.NET MVC 應用程序中的模型自動創建基本的 CRUD 控制器和視圖(目前也可使用不帶實體框架基架的 WebAPI 和 MVC)。

基架生成可導航和使用的頁面。總而言之,它們減少了您在構建 CRUD 頁面時需要執行的單調工作。不過,基架生成的結果提供的功能具有限制性,會讓您立即根據自己的需求稍稍調整所生成的控制器邏輯和視圖。

這樣做的風險在於構建基架是一個單向過程。您無法重新使用基架生成可以反映模型變化的控制器和視圖,而又不覆蓋調整。因此,您必須註意跟蹤您已自定義的模塊,這樣才能知道哪些模型可以安全地重新使用基架生成,哪些模型不可以。

在團隊環境中,很難保持這樣的警惕性。最重要的是,編輯控制器在“編輯”視圖中顯示大部分的模型屬性,因此可能會揭示敏感信息。它會盲目地對視圖提交的所有屬性進行模型綁定和暫留,這增加了大規模賦值攻擊的風險。

在本文中,我將介紹如何創建項目專用的自定義 T4 模板,從而強力驅動 ASP.NET MVC 實體框架 CRUD 基架子系統。與此同時,我還將介紹如何擴展控制器的創建和編輯回發處理程序,這樣您便可以在回發模型綁定和數據存儲暫留之間插入您自己的代碼。

為了解決對大規模賦值的擔憂,我將創建一個自定義屬性,讓您能夠完全控制應該以及不應該暫留的模型屬性。然後,我將另外添加一個自定義屬性,以便您可以將屬性顯示為“編輯”視圖上的只讀標簽。

此後,您將對以下內容擁有前所未有的控制力:您的 CRUD 頁面以及如何顯示和暫留模型,同時將降低應用程序受到攻擊的風險。最棒的一點是,您將可以對 ASP.NET MVC 項目中的所有模型利用這些技術,並能在模型改變時安全地重新生成控制器和視圖。

項目設置

我已使用 Visual Studio 2013 Ultimate、ASP.NET MVC 5、Entity Framework 6 和 C#(此處所討論的技術也與 Visual Studio 2013 Professional、Premium 和 Express for Web 以及 Visual Basic .NET 兼容)開發出此解決方案。我創建了兩個解決方案以供下載:第一個是基線解決方案,您可以使用該解決方案從正在處理的項目入手,然後手動實施這些技術。第二個是完整解決方案,其中包括本文提及的所有改進。

每個解決方案都包含三個項目:一個適用於 ASP.NET MVC 網站、一個適用於實體模型和 T4 基架函數,另一個適用於數據上下文。解決方案的數據上下文指向 SQL Server Express 數據庫。除了已提及的依賴關系,我使用 NuGet 添加了啟動,以設置基架生成的視圖的主題。

如果您選中 Microsoft Web Developer Tools 設置選項,那麽基架子系統便會在設置期間安裝。後續的 Visual Studio Servive Pack 將自動更新基架文件。在最新的 Microsoft Web 平臺安裝程序中,您可以獲取在 Visual Studio Servive Pack 之間發布的基架子系統的所有更新。您可以從 bit.ly/1g42AhP 下載 Microsoft Web 平臺安裝程序。

如果您在使用本文隨附的下載代碼時遇到任何問題,請確保您使用的是最新版本,並且已仔細閱讀 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 知道 ProductId 是主鍵,但它卻不知道我對 CreatedDate 和 ModifiedDate 屬性有特殊要求。顧名思義,我希望 CreatedDate 傳遞相關產品(由 ProductId 表示)插入數據庫的時間。我還希望 ModifiedDate 傳遞產品的最後一次修改時間(我將使用 UTC 日期時間值)。

我想將 ModifiedDate 值作為只讀文本顯示在“編輯”視圖上(如果記錄從未經過修改,則 ModifiedDate 等於 CreatedDate)。我不希望在任何視圖上顯示 CreatedDate。我也不希望用戶能夠提供或修改這些日期值,因此我不想呈現任何表單控件來收集用戶在“創建”或“編輯”視圖上的輸入值。

為了防止這些值受到攻擊,我希望確保不在回發中暫留這些值,這樣縱使聰明的黑客可以將它們作為表單域或查詢字符串值提供,也無法發起攻擊。由於我考慮到這些業務邏輯層規則,因此我不希望數據庫負責維護這些列值(例如,我不想創建任何觸發器或嵌入任何表格列定義邏輯)。

探索 CRUD 基架工作流程

首先,讓我們檢查一下默認基架的功能。我將右鍵單擊 Web 項目的“控制器”文件夾並選擇“添加控制器”,從而添加一個控制器。此時,“添加基架”對話框啟動(請參見圖 1)。

技術分享
圖 1:MVC 5“添加基架”對話框

我將使用“具有視圖的 MVC 5 控制器,使用實體框架”條目,因為它可以使用基架為模型生成 CRUD 控制器和視圖。選擇該條目,然後單擊“添加”。接下來出現的對話框為您提供了幾個選項,這些選項最終會成為隨後轉換的 T4 模板的參數(請參見圖 2)。

技術分享
圖 2:“添加控制器”對話框

輸入“ProductController”作為控制器名稱。為了方便本文進行論述,請取消選中“使用異步控制器操作”復選框(異步操作不在本文的討論範圍之內)。接下來,選擇產品模型類。由於您使用的是實體框架,因此需要數據上下文類。下拉列表中顯示繼承自 System.Data.Entity.DbContext 的類,因此如果您的解決方案使用多個數據庫上下文,請選擇一個正確類。對於視圖選項,請選中“生成視圖”和“使用布局頁面”。將布局頁面文本框留空。

在您單擊“添加”後,多個 T4 模板會進行轉換,從而提供基架生成的結果。此過程生成控制器 (ProductController.cs) 和五個視圖(Create.cshtml、Delete.cshtml、Details.cshtml、Edit.cshtml 和 Index.cshtml)的代碼。前者寫入 Web 項目的“控制器”文件夾,後者寫入 Web 項目的“視圖”文件夾。此時,您擁有一個可正常運行的控制器,以及管理產品實體中的數據所需的全部 CRUD 視圖。您可以立即開始使用這些網頁(從索引視圖入手)。

您可能希望 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 控制器在回發後對所有模型屬性進行模型綁定,這就是所謂的大規模賦值。這也稱為過發布,屬於嚴重的安全漏洞。黑客可以利用這一漏洞,因為在數據庫上下文中後續會調用 SaveChanges。這樣就可以確保模型在數據存儲中暫留。默認情況下,MVC 5 中的 CRUD 基架系統使用的控制器模板為創建和編輯操作回發方法生成大規模賦值代碼。

如果您選擇修飾模型上的某些屬性,使得這些屬性不會呈現給“創建”或“編輯”視圖,也會導致大規模賦值發生。在進行模型綁定後,這些屬性會設置為空(請參閱“使用屬性抑制 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 頁面中為模型屬性賦值的最後一次機會就是在回發期間。因此,如果屬性回發值為空,那麽該空值將進行模型綁定。然後,當 SaveChanges 在數據上下文對象中執行時,該模型將暫留在數據存儲中。如果這是在編輯回發操作方法中完成,則該屬性將替換為空值。這實際上刪除了數據存儲中的當前值。

在我的示例中,CreatedDate 在數據存儲中暫留的值將會丟失。事實上,沒有呈現給“編輯”視圖的所有屬性都將導致數據存儲中的值被空值覆蓋。如果模型屬性或數據存儲不允許賦空值,那麽您會在回發時看到錯誤。為了克服這些缺陷,我將修改負責生成控制器的 T4 模板。

替換基架模板

若要修改使用基架生成控制器和視圖的方式,您必須修改負責生成它們的 T4 模板。您可以修改原始模板,這將對所有 Visual Studio 項目的基架產生全局影響。您還可以修改 T4 模板的項目專用副本,這將只影響包含相應副本的項目。我將執行後一修改。

原始 T4 基架模板位於 %programfiles%\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates 文件夾中(此類模板依賴位於 %programfiles%\-Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web Tools\Scaffolding 文件夾中的多個 .NET 程序集)。我將把重點放在使用基架生成實體框架 CRUD 控制器和視圖的特定模板。圖 4 對這些機制進行了總結。

圖 4:使用基架生成實體框架 CRUD 控制器和視圖的 T4 模板

基架模板的子文件夾名稱

模板文件名

(.cs 表示 C#;.vb 表示 Visual Basic .NET)

生成此文件

(.cs 表示 C#;.vb 表示 Visual Basic .NET)

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 基架文件夾復制到 ASP.NET MVC Web 項目中的 CodeTemplates 文件夾(必須與該名稱完全一致)。依據慣例,基架子系統首先會在 MVC 項目的 CodeTemplates 文件夾中查找匹配模板。

為了使用此功能,您必須精確復制原始模板文件夾中顯示的特定子文件夾名稱和文件名。我已從實體框架基架子系統的 CRUD 中復制我打算替換的 T4 文件。圖 5 展示了我的 Web 項目的 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 文件夾中)。這樣,如果模型已實施 IControllerHooks,則模板的創建和編輯回發操作方法將各自調用模型的 OnCreate 和 OnEdit 方法。圖 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-Hooks。然後,我將添加要在控制器調用 OnCreate 和 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,那麽它會在控制器的編輯操作方法暫留模型後替換為空值。為防止這種情況發生,我將需要進一步修改控制器模板。

加強編輯操作方法

我已提到過一些與大規模賦值相關的問題。修改模型綁定行為的一種方法是將綁定屬性修改為排除不要綁定的屬性。不過,這種方法實際上仍會將空值寫入數據存儲。更好的策略是進行其他編程,不過這樣做很值得。

我將使用實體框架附加方法將模型附加到數據庫上下文。然後,我可以跟蹤實體條目,並能根據需要設置 IsModified 屬性。為了驅動此邏輯,我將在 JW_Scaffold-Enhancement.Models 項目中新建名為 CustomAttributes.cs 的類模塊(請參見圖 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 的公共函數,它可返回用於循環訪問的 List<String>,從而為所傳遞的程序集和類型生成 IsModified 設置。圖 10 展示了 Controller.cs.t4 模板中的此代碼。

技術分享
圖 10:用於生成改進的控制器編輯回發處理程序的 T4 模板代碼

圖 11 展示的 GetPropertyIsModifiedList 中,我使用反射獲取對所提供的模型屬性的訪問權限。然後,我循環訪問它們,以確定哪些屬性是使用 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>(); // 獲取模型對象的屬性 string aqn = Assembly.CreateQualifiedName(ModelNamespace + ", Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", ModelNamespace + "."+ ModelTypeName); // 根據程序集限定名獲取類型對象 Type typeModel = Type.GetType(aqn); // 獲取類型的屬性 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.NET MVC 僅提供三個屬性,以便於您在某種程度上控制是否將模型的屬性呈現給基架生成的視圖(請參見圖 A)。前兩個屬性的用途相同(盡管它們駐留在不同的命名空間):[Editable(false)] 和 [ReadOnly(true)]。這些屬性會導致經過修飾的屬性不呈現給“創建”和“編輯”視圖。第三個屬性 [ScaffoldColumn(false)] 會導致經過修飾的屬性不在所呈現的任何視圖中顯示。

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

模型元數據屬性 屬性命名空間 受影響的視圖 會發生什麽
無其他屬性只帶來普通結果。

[Editable(false)]

[ReadOnly(true)]

可編輯:

System.ComponentModel.DataAnnotations

只讀:

System.ComponentModel

Create

編輯

經過修飾的模型屬性未呈現。
[ScaffoldColumn(false)] System.ComponentModel.DataAnnotations

Create

刪除

詳細信息

編輯

索引

經過修飾的模型屬性未呈現。

自定義視圖

有時,您希望在“編輯”視圖上顯示您不希望用戶修改的值。ASP.NET MVC 提供的屬性並不支持您這樣做。我想在“編輯”視圖上看到 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 所示。

當屬性為 False 時,GetHtmlForDisplayOnEditViewAttribute 函數返回 Html.EditorFor;當屬性為 True 時,該函數返回 Html.Display-TextFor。“編輯”視圖將把 ModifiedDate 顯示為標簽,並把其他所有非鍵字段顯示為可編輯的文本框(如圖 14 所示)。

圖 13:用於支持自定義 DisplayOnEditViewFlag 屬性的 ScaffoldFunctions.GetHtmlForDisplayOnEditViewAttribute 靜態函數

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 字段的“編輯”視圖

總結

我只是簡要介紹了使用基架子系統可以實現的功能。我側重的是為實體框架提供 CRUD 控件和視圖的基架,但也有其他基架可以為其他類型的網頁和 Web API 操作生成代碼。

ASP.NET MVC 替換默認的基架模板