使用 Evolutility 进行即时代码生成





5.00/5 (25投票s)
用于 CRUD 应用程序的通用 Web 用户界面,可在运行时基于外部元数据生成所有屏幕。它附带了通讯录、备忘录、待办事项列表、餐馆列表、酒窖以及数据库结构文档的示例应用程序,并且易于自定义。
目录
引言
本文介绍了一个用于 CRUD(创建、读取、更新、删除)应用程序的通用 Web 用户界面,它被实现为一个适用于 ASP.net 和 SQL Server 的 Web 控件。该工具完全由元数据驱动,可以适应不同的数据库结构。
通过它,用户界面(字段标题、位置、视觉分组、CSS 类)及其数据库映射(表、列、存储过程)不是在代码中定义的,而是在外部元数据中定义的。它可以表现得像一个待办事项列表、一个通讯录、一个酒窖,或者任何你想构建的 CRUD 应用程序。它非常适合快速构建数据库 Web 应用程序或网站管理页面的功能组件(只需要简单的验证规则)。
此 Web 控件可以嵌套在任何 ASP.net 页面中。它将在运行时自动生成所有必需的 Web 表单,管理用户交互和数据库 CRUD 操作。
由于此工具依赖元数据来更改 Web 表单、结构和大小,因此我将其命名为“Evolutility”,在生物学中,它指的是“所有具有自我滋养能力的物质通过形式、体积或结构的改变来表现出滋养行为的能力”。
示例应用程序
为了说明简单的 CRUD 应用程序如何用于管理页面之外的更多用途,本文提供了一个包含多个示例应用程序的演示项目。
- 待办事项列表
- 通讯录
- 备忘录
- 餐馆列表
- 数据库结构文档
- 为盲人提供的资源
- 酒窖
一方面,从开发者的角度来看,这些应用程序是相似的,因为它们使用相同的模式和(如果手动编码)非常相似的代码;另一方面,从用户的角度来看,它们非常不同,因为它们服务于不同的目的(例如跟踪任务或联系人列表、发布喜欢的餐馆列表或管理葡萄酒瓶库存),并且使用截然不同的字段集。
“待办事项列表”是我上一篇关于 CRUD 应用程序的极简元模型 的文章中使用的示例,以便读者能够亲身体验元数据驱动的应用程序。
“通讯录”、“备忘录”、“餐馆列表”和“为盲人提供的资源”是其他简单的 CRUD 应用程序,通过重复使模式更加明显。
“数据库结构文档”应用程序更有趣,因为它像处理常规数据一样查询 SQL Server 元数据(系统表 sysobjects 和 syscolumns),从而自动记录数据库。它可能非常有用,因为它始终触手可及(发布在 Web 上),并且由于它是运行时生成的,因此始终是最新的。
可用于文档化表
以及视图、触发器和存储过程
最后一个示例应用程序是“酒窖”,它具有更复杂的 UI,使用了更多分组到面板和选项卡中的字段。
以及用于葡萄酒品鉴的主从详细信息。
所有这些示例应用程序都不是运行不同的编译代码,而是运行同一个 Web 控件的不同实例。现场演示可在 Evolutility.com 上找到。
在我下一篇关于 向导和 CRUD 应用程序用于构建其他 CRUD 应用程序 的文章中,将讨论另一种类型的 CRUD 应用程序。
安全与用户访问管理
Evolutility Web 控件内置了用户标识、行级安全、协作和用户评论功能。您可以使用它们,或者通过嵌套控件的页面中的自定义代码绕过它们,例如根据用户选择不同的 XML 文件。
在组件级别(在 ASPX 页面中)
控件的 SecurityModel
属性提供了让用户查看和更新记录的不同方式。
- Single_User:所有用户都可以查看或编辑所有内容。
- Single_User_Password:需要登录名和密码才能查看或编辑数据。
- Multiple_Users_RLS:每个用户只能看到和编辑自己的数据(行级安全)。
- Multiple_Users_Sharing:每个用户都能看到所有数据,但只能编辑自己创建的记录。
为了使用 Multiple_Users_RLS 和 Multiple_Users_Sharing,驱动表必须有一个名为“UserID”(整数类型)的列。Multiple_Users_Sharing 还需要一个名为“Publish”(位或整数类型)的列。
DBReadOnly
属性可以阻止用户编辑记录,使表单只读。
DBAllowDelete
、DBAllowInsert
和 DBAllowUpdate
属性可用于允许或禁用数据库功能,如删除、插入和更新。
在字段级别(在元数据中)
可以使用每个 field
元素的 readonly
属性使单个字段可编辑或只读。
字段可以是必需的或可选的(属性 required
和 optional
)。
此外,您可以为不同用户选择完全不同的 XML 文档。
Evolutility 处理用户登录
当 SecurityModel
设置为 Single_User_Password、Multiple_Users_RLS 或 Multiple_Users_Sharing 时,Evolutility 会在页面首次显示时提示用户登录。
可以使用 XML 中 data
元素的 splogin
属性指定用于用户/密码验证的存储过程。
随示例提供了一个名为“EvoDemoSP_Login”的用户标识示例存储过程。可以根据您的具体需求进行修改。
在不同页面之间共享登录信息:Evolutility 表单会与其应用程序中具有相同 DBApplicationID
属性的其他 Evolutility 表单共享其登录信息。这样,用户只需登录一次即可使用所有(或部分)Evolutility 表单。
自定义安全
用户标识:您可以使用自己的登录屏幕,并在页面中包含自定义代码,如果用户未被您的应用程序识别,则将其重定向到登录页面。
限制特定用户访问特定字段:举个例子:两个用户都可以查看产品信息,其中一个用户可以看到产品价格,而另一个用户看不到。您可以创建 2 个组件定义(映射到同一组数据库表),一个包含产品价格,另一个不包含。然后,在页面中使用自定义代码来识别用户,并将 Evolutility Web 控件绑定到其中一个定义。
用户管理
用户管理与其他实体一样简单;您只需要使用 Evolutility 来映射用户表。
您可以创建不同的页面,如下所示:
- 管理员用于管理用户的页面
- 一个页面(使用 SecurityModel=Multiple_Users_RLS)让每个用户编辑自己的个人资料
- 一个页面(使用 SecurityModel=Multiple_Users_Sharing)让用户浏览其他用户的个人资料。
协作与用户评论
任何组件都可以设置为允许用户对记录发表评论。这是通过 Web 控件属性 UserComments
完成的。默认情况下,评论保存在数据库表“Evol_Comment”中,但可以使用 XML 中的 dbtablecomments
属性指定另一个表。
启用用户评论后,每条记录的评论数会显示在列表中。
记录的评论(如果有)显示在页面底部,并带有一个用于输入新评论的文本框。
Evolutility Web 控件属性
该工具的大部分灵活性都来自于其元数据(在我上一篇关于元模型的文章中已详细介绍),但与所有 .NET Web 控件一样,它也有属性。除了继承自 .NET 类的标准 WebControls
属性外,Evolutility 还提供以下属性:
AllowSorting
:允许按列对搜索结果进行排序。将其设置为 false 将在列表标题中删除用于排序记录的上下箭头。BackColorRowMouseOver
:确定鼠标光标移到行上时用于突出显示行的颜色。CollapsiblePanels
:确定用户是否可以显示和隐藏面板。DBAllowDelete
:用于允许或禁用特定数据库查询的属性。DBReadOnly 需要设置为 False 才能使这些属性生效。DBAllowExport
:启用导出功能(用于列表和单条记录)。DBAllowHelp
:在编辑模式下显示每条字段的 help 属性内容。DBAllowInsert
:用于允许或禁用在驱动表上插入数据库记录的属性。DBReadOnly 需要设置为 False 才能使这些属性生效。DBAllowInsertDetails
:用于允许或禁用在详细信息表中插入数据库记录的属性。DBAllowPrint
:指定工具栏上是否应显示“打印”按钮。DBAllowSearch
:指定工具栏上是否应显示“搜索”和“高级搜索”按钮。DBAllowSelections
:在工具栏上显示“选择”按钮,以提供自定义查询列表。需要在 XML 中定义查询和查询。DBAllowUpdate
:用于允许或禁用修改驱动表上记录的属性。DBReadOnly 需要设置为 False 才能使这些属性生效。DBAllowUpdateDetails
:用于允许或禁用详细信息表的就地编辑的属性。DBReadOnly
:使页面只读。禁用所有记录的添加、编辑和删除(当 DBReadOnly 设置为 true 时,工具栏按钮消失)。DesignDisplayMode
:允许您在设计时获得 Web 表单任何模式的所见即所得显示。DesignTabIndex
:允许您在设计时获得 Web 表单编辑或查看模式的任何选项卡的所见即所得显示。DesignWebPath
:在设计时设置 XML 目录的路径。此路径将与 XML 文件名连接。DisplayMode (Read Only)
:指示当前显示模式(查看、编辑、列表、搜索、高级搜索或选择)。DisplayModeStart
:Evolutility 首次调用页面时显示的模式。ItemID (Read Only)
:当前记录的 ID。Language
:控件中显示的所有文本和日期格式的本地化。目前提供英语和法语。可能的值:- EN - 英语
- FR - 法语
NavigationLinks
:在编辑或查看记录时,在页面底部显示导航链接(首页、上一页、下一页、末页)。RowsPerPage
:一次在搜索结果中显示的行数。此属性仅在应用程序定义 XML 中指定了分页存储过程时可用。SecurityKey
:允许组件之间共享凭据的密钥。SecurityModel
:使用以下内置安全模型之一,以 4 种不同的方式管理用户:- Single_user - 无密码保护
- Single_user_password - 需要凭据
- multiple_users_RLS - 每个用户只能看到和编辑自己的数据(行级安全)
- multiple_users_sharing - 每个用户都能看到所有数据,但只能编辑自己创建的记录
ShowTitle
:确定标题头的显示。SQLConnection
:数据库连接字符串。为避免在应用程序的每个 Web 控件中输入此属性,可以将其设置为应用程序的 Web.config 文件中。Text
:仅在表单首次调用时显示的介绍性文本。Title
:应用程序标题。ToolbarPosition
:工具栏的位置/显示。可能的值:- 顶部
- 顶部和底部
- 无
UseCache
:启用或禁用值列表的缓存。将其设置为 true 将提高性能。UserComments
:允许用户对特定记录发表评论。可能的值:- 无
- 只读
- 登录用户
- 匿名
UserID (Read Only)
:当前用户的 ID(如果用户未登录或 Evolutility 在单用户模式下使用,则为 0)。VirtualPathDesigner
:设置应用程序设计器的虚拟路径。VirtualPathPictures
:设置字段中使用图片的虚拟路径。VirtualPathToolbar
:设置工具栏图片的虚拟路径。XMLFile
:包含元数据的 XML 文件名,可以指定为绝对路径,例如“c:/EVOLUTILITY/XML/AddressBook.XML”;或者作为相对路径(推荐),例如“XML/AddressBook.XML”;或者使用通配符指定程序集路径,例如“ AddressBook.XML”,这允许 XML 文件与 Evolutility.DLL 一起位于 BIN 目录中。
服务器事件
目前 Evolutility 提供一个事件,DBChange
,在记录插入、更新或删除时触发。
事件参数 DBChange
指定 Action
(Insert
、Update
或 Delete
)和 ID
,其中 Action 是一个字符串,指定数据库查询,ID 是已执行操作的记录的主键。
通过 Web 控件对数据库执行操作,可以触发嵌套控件的页面中的自定义代码。以下是一个显示最后一次数据库操作到标签中的代码示例。
C#
private void Evolutility1_DBChange(object sender,
Evolutility.Evolutility.DatabaseEventArgs e) {
switch(e.Action) {
case "INSERT":
Label1.Text = String.Format("Record {0} added.", e.ID.ToString());
break;
case "UPDATE":
Label1.Text = String.Format("Record {0} updated.", e.ID.ToString());
break;
case "DELETE":
Label1.Text = String.Format("Record {0} deleted.", e.ID.ToString());
break;
}
}
VB.net
Private Sub evo1_DBChange(ByVal sender As System.Object, ByVal e As
Evolutility.Evolutility.DatabaseEventArgs) Handles evo1.DBChange
Select Case e.Action
Case "INSERT"
Label1.Text = "Record " & e.ID & " added to database"
Case "UPDATE"
Label1.Text = "Record " & e.ID & " updated"
Case "DELETE"
Label1.Text = "Record " & e.ID & " deleted"
End Select
End Sub
这种“单一事件实现”虽然可用,但功能非常有限。添加更好的服务器事件是 Evolutility 目前的重中之重。现在 UI 和数据库代码已就绪,下一步是使该工具更加开放和可扩展。
导航链接
当链接到嵌入了 Evolutility Web 控件的页面时,可以使用链接中的请求变量来改变控件的正常行为。可能的示例包括:
选择特定记录
- 查看 ID=5 的记录:
MyPage.aspx?ID=5
选择特定模式
要以特定模式打开页面,可以这样做:
- 创建新记录:
MyPage.aspx?MODE=new
- 编辑第一条记录:
MyPage.aspx?MODE=edit
- 编辑 ID=5 的记录:
MyPage.aspx?MODE=edit&ID=5
- 搜索页面:
MyPage.aspx?MODE=search
- 高级搜索页面:
MyPage.aspx?MODE=searchadv
- 选择列表:
MyPage.aspx?MODE=selections
- 所有记录列表:
MyPage.aspx?MODE=list
- 查询“amex”的结果列表:
MyPage.aspx?QUERY=amex
它是如何工作的?
每个组件的构建和行为方式都相同。一个物理 Web 页面嵌入了 Evolutility Web 控件。控件的属性指示要获取的元数据、特权(读取、插入、编辑、删除...)以及一些其他选项。
当用户首次调用页面时:
- 页面加载控件(可能在页面内的自定义代码中设置控件的属性)。
- 控件检查其属性。
- 控件检索要管理的组件的元数据。
- 控件检查 URL 的参数(例如,“page.aspx?ID=4”表示必须显示主键为 4 的记录)。
- 根据属性和页面参数,控件确定要显示的模式(登录、查看、编辑、列表、搜索、高级搜索或导出)。
- 控件查询数据库以获取一条记录的所有定义字段(如果处于查看或编辑模式),或查询多条记录的字段子集(如果处于列表模式),或者根本不查询数据库(如果处于登录或选择模式)。对于搜索和高级搜索模式,根据要显示的值列表的数量(以及它们是否已缓存),它可能会运行多个查询或不运行。
- 控件为模式和要显示的数据生成用户界面。
- Web 服务器发送包含控件生成的代码的页面。
用户将在页面上执行一个操作,例如通过单击控件工具栏按钮之一。
- 页面再次调用自身(而不是像大多数应用程序那样调用另一个页面)。
- 步骤 1、2、3 和 4 的执行与第一次调用页面时相同。
- 控件确定是否必须执行数据库查询来处理上一个页面实例触发的操作(如果用户单击删除,则必须删除之前编辑过的记录……)。
- 控件根据需要执行数据库查询。
- 如果查询返回错误,控件将在生成的用户界面中添加一个标题消息以通知用户。
- 步骤 5、6、7 和 8 的执行与第一次相同。
要运行演示项目和示例应用程序,请按照以下步骤操作:
- 将包含网站的“EvolutilityDemo”目录复制到您的 Web 服务器。
- 创建一个新的 SQL Server 数据库。
- 更改 Web.config 文件(或每个 ASPX 页面)的“appSettings”部分中的数据库连接字符串。
- 在您的数据库上运行名为 Evolutility-Common.sql 的 SQL 脚本。
- 如果您想为多个用户使用登录名和密码,请运行名为 EVOL-MultiUser.sql 的 SQL 脚本。
- 运行其他 SQL 脚本以用于您想要的演示。
使用 Evolutility 构建应用程序最简单的方法是先从现有应用程序开始,然后对其进行修改以成为您想要的应用程序。只需将任何一个示例应用程序作为起点,玩转 XML,修改 UI 属性或重新排序字段。然后,从相应的数据库表中添加或删除列,并相应地自定义 XML。
代码中包含一个 XML Schema Definition(XSD 文件),以帮助您构建和修改应用程序的元数据。XML 语法详情在我上一篇关于 CRUD 应用程序的极简元模型 的文章中讨论过,或者在 Evolutility.com 上有更详细的介绍。
在我下一篇关于 向导和 CRUD 应用程序用于构建其他 CRUD 应用程序 的文章中,将讨论使用 Evolutility 构建应用程序的替代方法。
项目代码是开源的,遵循 Affero GPL v3 许可,并提供双重许可,托管和更新于 SourceForge。尽情享用……也许可以改进它并贡献您的代码。
关注点
这类工具可以节省构建应用程序的时间,同时还可以大大简化维护和定制。它甚至可能使非技术用户也能进行应用程序开发。
此外,对于商业软件而言,由于(有限的)定制不需要重新编译,因此它非常适合客户、合作伙伴和 OEM,因为他们无需访问源代码即可进行定制或添加屏幕。
此外,采用元数据驱动的方法进行应用程序开发将使您的代码库大大减少,通常代码越少,错误就越少。