EntityUI 自動 UI 生成器
介紹
EntityUI是一個能夠通過在ASP.NET中的快速代碼生成方式,創建用戶界面和數據庫存儲,即可立即生成你所需要的應用。作為一個開發,去創建應用的時候,你只需要寫域和視圖模式來調整這些類即可,無需再寫太多的代碼了。
背景
我好幾年前就開始使用ASP.net的EntityUI,也寫了許多簡單的代碼來反射繪制UI圖。這是我原來寫的文章。但是,從我開始使用EntityUI到現在,它也發生了很多改變。MVC和Knockout已經流行了一段時間,而且他們都是生成MVVM模式很好的工具。
所以,現在EntityUI現在是一個使用MVC和Knockout自動從模型生成UI的工程。它主要的目標是成為一個應用程序的快速開發工具,不僅僅是生成通用的增刪改查的頁面,而是嘗試去處理更高級別的方案。
先決條件
這是一個Microsoft MVC的工程。你首先要熟悉MVVM模式、域模型、視圖模型,以及掌握knockout并能夠使用它的一些高級功能。你也需要了解Repository模式,以及深入了解Microsoft Entity Framework Code First是怎么工作的。我們在nuget下載EntityUI包,并使用bootstrap 設計漂亮的布局。
使用代碼
首先,我會用一個全新的項目來做展示。開始一個空的MVC工程,然后添加兩個類庫工程到解決(Solution)中,一個是給域模型(Domain Model),一個是給倉庫(Repository)。然后從nuget中添加EntityUI到所有工程去。
安裝EntityUI,執行以下命令:包的管理控制臺包的管理控制臺
PM> Install-Package EntityUi
EntityUI包含了一下幾個核心的概念:
-
DomainModelBase - 基礎類,域模型對象都需要繼承它。
</li> -
ViewModelBase - 基礎類,視圖模型對象都需要繼承它。
</li> -
ControllerBase - 控制器的基礎類,它提供了增刪改查的方法。
</li> -
RepositoryBase - 倉庫的基礎類,它提供了基于Entity框架的增刪改查方法。
</li> </ul>接下來,我們需要寫域模型(Domain Model)和倉庫(Repository)方法。
在這個例子中,我們會用“Department”這個類作為例子。 這是從 MSDN Entity Framework Code First Fluent API example 中獲取的例子。
public class Department : DomainModelBase { public Department() { Courses = new HashSet<Course>(); } public string Name { get; set; } public decimal Budget { get; set; } public DateTime StartDate { get; set; } public int? Administrator { get; set; } // Navigation property public ICollection<Course> Courses { get; set; } }
正如你所看到的,這個類是繼承了DomainModelBase類。
然后,開始實現倉庫。添加你的內容(Context)類,并繼承實例框架(Entity Framework)的DbContext類,然后給Department添加一個簡單的倉庫(Repository)類"DepartmentRepository":
public class DataContext : DbContext { public DbSet<Department> Departments { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { Database.SetInitializer(new CreateDatabaseIfNotExists<DataContext>()); } }
public class DepartmentRepository : RepositoryBase<Department, DataContext> { protected override DataContext GetContext() { return new DataContext(); } }</pre>
現在,DataContext類是一個非常簡單的,只有一個屬性的Context類。
倉庫(Repository)很好實現。這個類繼承了DomainModelBase,除了GetContext就沒有別的方法了。正如你所見,當繼承了RepositoryBase,你就得給Base提供實體名和DataContext,讓它知道是什么在工作。
接下來我們把視野轉移到視圖(View),現在仍是一個空白的MVC項目。我們準備用Bootstrap來實現視圖。我使用的是Eric Hexter在Nuget上提供的包,并做了些改變。我添加并修改一些文件,使之能夠運行成功,它現在已經完全是EntityUI的核心部分之一。我最終會把包添加到Nuget上,但現在,你們可以在文章中下載該壓縮包。
在web工程中建立好一些文件之后,開始添加模型(Model)、視圖(View)和控制器(Controller)的類。我一直提倡要有一個獨立的域(Domain)和視圖模型(View Model)類,盡管在一般情況下他們是幾乎相同的。我們要用AutoMapper簡單的在域和視圖模型中進行轉換。
以下是Controller類:
public class DepartmentController : ControllerBase<Department, DepartmentView, DataContext> { public DepartmentController() { Repository=new DepartmentRepository(); } }
這個控制器和其他類很像,都是要繼承ControllerBase。它需要了解域模型(Domain Model)、視圖模型(View Model)和DataContext。
最后一步是在global.aspx中使用AutoMapper將獨立的域(Domain)和視圖模型(View Model)進行映射:
Mapper.CreateMap<Department, DepartmentView>(); Mapper.CreateMap<DepartmentView, Department>() .ForMember(d => d.Id, o => o.Condition(s => s.Id > 0)) .ForMember(d => d.Courses, o => o.Ignore());;
以上是使用AutoMapper對域視圖和模型視圖的簡單配置.它的基本做法是通過反射機制將一個對象的屬性值賦給另外一個.本質上這個工具是開告訴 EntityUI如何將 域(Domain ) 轉換成 模型視圖(Model View )對象的.
現在可以創建和運行你的程序了,當你瀏覽Department時,它將把Department的內容展示出來,包括完整的CRUD功能,包括渲染頁面,并將它保存到數據庫.
這就是最簡單最基礎的使用EntityUi,現在可以做一些更有樂趣的事情.
使用下拉列表
接下來介紹如何只需要修改你的視圖模型便能使用下拉列表。首先先添加Course,如下:
這個是域模型(Domain Model):
public class Course : DomainModelBase { public Course() { Instructors = new HashSet<Instructor>(); }
public string Title { get; set; } public int Credits { get; set; }
// Foreign key public int DepartmentID { get; set; }
// Navigation properties public Department Department { get; set; } public ICollection<Instructor> Instructors { get; set; }
}</pre>
正如你所見,部門(Department)作為一個Navigation Property在UI中展示,我們希望看到所有部門的下拉列表,并且用戶能夠選擇部門。
下面是倉庫(Repository)和控制器(Controller):
public class CourseRepository : RepositoryBase<Course, DataContext> { protected override DataContext GetContext() { return new DataContext(); } }
他們都只是簡單地從EntityUi的RepositoryBase和ControllerBase繼承過來的。
現在是模型視圖(Model View):
public class CourseView : ViewModelBase { public string Title { get; set; } public int Credits { get; set; }
public DropDown Departments { get; set; }
public CourseView() { Departments = new DropDown { Items = (new DepartmentRepository()) .List() .ToList() .ConvertAll(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) }; } }</pre>
這里有點不太一樣。我們定義了Departments Property作為EntityUi中“DropDown”的助手類型,來給Department提供下拉列表。此外,我們從數據庫中加載了部門的清單,放在構造函數里。我希望代碼是一目了然的,不需要過多的解釋。我們只需要調用在DepartmentRepository 中的“List()”方法(EntityUi提供的)去獲取所有部門,然后用“ConvertAll()”方法(Linq提供的)來轉換為SelectListItem。
另一個有趣的部分是映射模型視圖(Model View)和域模型(Domain View)。下面的代碼是需要添加到Global.asax:
Mapper.CreateMap<DepartmentView, Department>() .ForMember(d => d.Id, o => o.Condition(s => s.Id > 0)) .ForMember(d => d.Courses, o => o.Ignore());
Mapper.CreateMap<Department, DepartmentView>();</pre>
這實際上是Auto Mapper的一個比較新鮮的用法,你可以看看AutoMapper的有關文檔。
在第一個映射表中,分別把CourseView(視圖模型)映射到Course(域模型)。有趣的部分是,把域(Domain)的部門ID映射到視圖(View)的部門下拉列表中的SelectedId的屬性。在第二次映射的時候,我們是從域到視圖模型,而它也是完全相反的。
這些基本上是所需要的代碼。如果你想現在運行,并導航到“Courses”,你就需要有添加、編輯、刪除部門的下拉選項。
增加用戶接口交互
到目前為止,我們已經看到了一些基本的 CRUD 功能。通過處理模型視圖,不僅僅能實現 CRUD 功能。因此比如說,我們有這樣的業務需要,只要預算(budget)被分配部門就應該申請預算,否則,預算輸入框不應該顯示出來。
關于它最好的實現將是視圖中的 Javascript。處理這些場景最容易的方法是通過 knockout。EntityUi 允許你增加 knockout 綁定到使用 DataBind 數據標注的任意屬性上。
所以,我們通過如下方式簡單的修改 Department 視圖,來滿足這個需求:
public class DepartmentView : ViewModelBase { public string Name { get; set; } public bool HasBuget { get; set; } [DataBind("visible:HasBuget()")] public decimal Budget { get; set; } public DateTime StartDate { get; set; } }
這樣,我這里所作的是首先增加了一個 boolean 屬性的 HasBudget。這將渲染成一個檢查框。
之后,我增加了 DataBind 屬性,提供了我通常會給視圖增加的 knockout 綁定。EntityUi 會自動渲染它。你需要熟悉 knockout 綁定來充分利用這個特性。如果沒有,請查看 www.knockoutjs.com 的文檔。所有這里所做的是設置 HasBudget 屬性的可見性。在幕后,EntityUi 使用 knockoutmvc 將每個模式視圖設置為 knockout 視圖模型,使得每個屬性都可以被觀察。
這處代碼變化所做的事情是,當你在編輯模式查看頁面時,如果勾選了 "HasBudget" 檢查框,它會顯示 Budget 輸入字段和標簽,如果沒有勾選則會隱藏它們。
總結
因此希望通過上文提到的細節,你可以了解 EnitityUi 是如何通過利用工具處理代碼編寫的各個方面,從數據處理直到用戶界面,來用于快速應用程序開發的。
作為開發者,主要的任務是書寫 Domain Model 和 View Model。之后其它的大多數事情是增加屬性,和 Fluent 的 API 配置,以及遵守約定,這樣我們就會有個全功能的應用程序。
EntityUi 也非常靈活,為開發者提供了完全的控制。開發者可以對任何類進行重載或者增加方法,不管是 Repository,Controller 還是 View。你可以在同樣的應用程序中,不使用 EntityUi 而是憑自己非常容易的書寫出完整的頁面或者類,或者利用 EntityUi 的框架將其增加到視圖或者控制器中。
參考
我使用了許多不同的開源庫實現了 EntityUi。下面是其中的一些主要開發庫:
-
MVC Bootrap 包 推ter.bootstrap.mvc4,作者 Eric Hexter
</li>
(https://www.nuget.org/packages/推ter.bootstrap.mvc4/) -
AutoMapper,作者 Jimmy Bogard
</li>
(https://www.nuget.org/packages/AutoMapper/3.0.0) -
knockoutmvc (http://knockoutmvc.com/)
</li> </ul>
-