开发框架
1. ORM, LLBL Gen,NHibernate
2. 接口与实现分离,界面与逻辑分离,分五个项目,
BusinessLogic, Interface,Manager,Validation,EntryForm3. SQL与ORM
4. 通讯集成 Remoting/WCF
5. Control/Component: NumberiEditor,TextEditor,Grid,ComboBox,ListBox,ListView,Tree
6. 异常
7. 元数据
ORM
使用ORM可以减少大量的数据读写和绑定代码,做大型的项目,必须用ORM
再配合CodeSmith代码生成器,可以完成数据读写90%的代码。
界面与逻辑分离
做一个MIS的库存项目,有四个项目
BusinessLogic 业务逻辑,业务实体
Interface 接口
Manager 实现接口
System Administration/Inventory, 界面
这样达到的效果,
1. 数据表新增加字段,界面部分不需要任何改动;
2. 可以灵活的切换界面到WPF/ASP.NET/Sliverlight
3. 插件式Addon,PlugIn式的开发,新增加功能,不需要改动原有的项目文件
SQL与ORM
ORM是跨平台的,要兼容所有的主流数据库,必需创建一种语法,以达到读写各种类型的数据库。
熟悉这个映射表,可以很快的入门,写出读写数据代码。虽然这个步骤不是必须的(因为CodeSmith代码生成器会成90%的代码)。 再配合SQL解析工具,输入SQL语句,实用程序(SQLTranslate.exe)可以自动翻译SQL为ORM的写法。
如果担忧ORM性能不好,可以直接使用ADO.NET
这个写法需要工具的配合,才能快速开发.
这个代码生成器也是组合的方式,例如表名是backupset
Entity 实体 | BackupSet |
ADO.NET(Get,Save,Insert,Update,GetList) | BackupSetDAL |
Interface 接口 | IBackupSet |
Service 逻辑调用 | BackupSetService |
ASP.NET应用代码生成器界面如下,配和ADO.NET或是Enterprise Library,具有很强的威力。
最新版本的ASP.NET应用代码生成器,直接写成CodeSmith的模板。这样,在改动生成的代码时,不需要任何编译动作。
CodeSmith现有版本只支持.NET 2.0,不支持.NET 3.5和.NET 4.0, 虽然CodeSmith 6.0 Alpha已经释出,但是非常的不stable.
也没有Studio可以使用。
SQL Profiler 跟踪查询
直接运行SQL Profile
运行自己开发的SQL Profiler
启动程序中增加配置节
<system.diagnostics>
<!-- LLBLGen Trace
Trace Level: 0 - Disabled
3 - Info
4 - Verbose
-->
<switches>
<add name="SqlServerDQE" value="4" />
<add name="ORMGeneral" value="0" />
<add name="ORMStateManagement" value="0" />
<add name="ORMPersistenceExecution" value="0" />
</switches>
<trace autoflush="true">
<listeners>
<add name="socketWriterTraceListener"
type="Avatar.ORMTraceListener,ORMTraceListener" />
</listeners>
</trace>
</system.diagnostics>
开启监听程序
源代码如下
或者运行如下的跟踪程序
改进的智能提示支持
当鼠标悬停在实体名上时,可以显示实体对应的表名
当鼠标悬停在字段上时,可以显示字段对应的表名
在SQL查询管理器中,当鼠标悬停在表名上时,可以显示表的注释
创建表的描述
创建字段的描述
导入表中现有的字段描述,以达到最小的劳动量
智能提示的设计演化过程
1. 把提示内容放到Access数据库中,这样,拷贝到项目开发目录中即可。遇到Provider=Microsoft.Jet.OLEDB.4.0 没有64bit的版本,编译时必须设置x86的平台格式,而不是AnyCPU.
增加Provider=Microsoft.ACE.OLEDB.12.0,但是,在每台开发人员机器上安装这个组件,不太实现。
2. 使用SQLExpress, 这种方式的问题,还是需要配置SQL,可尝试用dbo4之类的对象数据库,一个文件拷贝到指定目录就可以(可行, doable)
3. SQL Server内置实现方式,如下图
打开SQL Profiler, 秘密就在存储过程sp_addextendedproperty
最后,干脆做一个工具,专门用于更新字段的描述,这样会方便很多。
Remoting/WCF通讯技术
功能目标
1. 应用程序服务器 Remoting/WCF Server
2. Report Server
3. Workflow Server
4. 并发用户控制,跟踪日志输出(Trace output),组件授权验证
License 许可控制
用RSA签名xml文件,生成不可修改的xml文件,以保护软件授权许可
与硬件(CPU,Harddisk)信息绑定,在生成license文件时,先要求用户运行一段实用程序,生成一个hardware的sinature的文件,license generator依据这个文件生成许可文件。
与软件绑定,比如演示版不允许数据库超过2G的容量大小(SQL Express规定数据库大小不能超过4G);只能在规定的时间内运行,通常是一个月,过期后软件无法启动;不允许在虚拟机(Virtual Machine)中运行,因为虚拟机的原因,整个系统可以无限制的被Ghost还原;
Report Extension
经典的SQL查询语句的写法是这样,可以制作出客户报表
现在我们换成这样的查询数据库的写法2种方式,SQL Procedure和.NET Assembly,可维护性肯定后者强于前者,性能的损失也有.
后者也只有程序员可以维护报表,客户不可能懂.NET.
但是,面对日益复杂的业务逻辑,多数据库需求的客户(有的客户指定要用Oracle),用.NET Assembly应该是一种趋势。
数据库管理
一个框架数据库,驱动多个业务数据库。
一个业务数据库可以看成一套帐,可以独立进行版本管理,功能控制;也可以针对不同的客户需要,定制(customization)。
如下的注册公司的界面,Driver Assembly和Driver Type即是注册客户定制的程序集,以达到同一个产品,维护多个客户,不同行业的客户的使用。
性能(Reflection)的损失是不可避免的,同时也带来相当可观的灵活性。
Microsoft的产品也经常Reflection,为什么我们不可以,为一点斤斤计较的Performance?
认证authentication,授权authorization 模式(AD/Forms/Windows)
因为我们已经设计出了Application Server,所以,这个地方可以为所欲为,尽情的发挥。
看K3的登陆方式
Activity Directory的方式,是推荐的企业局域网构建方法,AD带来的PC间相互信任的关系,好处简直让人不可忘却。
Forms方式,可以对用户名和密码进行加密,可以记住用户名和密码,定期要求用户修改密码
Reporting Services的默认登陆方式是Windows,我们需要把它重写成Forms
很遗憾,即使是Microsoft SQL Server 2008 R2,仍然需要手动修改配置文件,以改成Forms认证。计划中,要制造一个小工具,来修改Reporting Services的认证方式,手动的配置有些复杂,容易出错。
再来看集成到ERP中的Report Manager的登陆方式
再来看一下授权,三种权限:功能权限,字段权限,数据权限
功能权限, 基于角色的认证授权 对各子系统的功能模块的执行权限
先设定用户组别权限
再到用户注册时,设定用户所属的组别
可实现ERP系统中60%的权限需求。
字段权限也实现,如上图,Demo用户不可以访问所有的报表,但是可以读取所有的客户和供应商信息。
字段权限对某些特殊的字段进行控制,如仓库人员不可以看到采购员输入的物料单价,A销售员,不可以看到B销售员的客户的联系方式,
数据权限,是对具体数据的操作权限。
比如,当采购金额达到10万时,财务经理Finance Manager不可以直接修改;
于是做出一个数据权限编辑器
如图中显示的条件,采购单总金额大于1000000,费用大于5000,而且供应商为Maskey.
这个条件是可以动态增加和删除,在运行时,由表达式引擎负责解析表达式,传回表达式执行的结果。
异常处理
在业务系统中,异常可实现N层撤消回滚的能力。
为了不暴露具体的产品实现细节,异常的显示方式,设计如下的异常对话框。
实现方式是注册当前应用程序域的UnhandledException事件,将异常显示在自定义对话框中。
AppDomain.CurrentDomain.UnhandledException+= new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);观察一下Microsoft的产品对异常出错的提示,Microsoft Report Builder
Microsoft SQL Server
SQL Server出错窗体的左下方,有三个按钮,Help,Copy message text, Show technical details
Show technical details会打开一个stack trace的窗体,用于诊断出错的细节信息。
异常的传送实现,有二个思路
1. 运用Enterprise Library的Log Application Block,将异常重定向的各种输出设置中(Console,File,Database)
2. 使用TCP Socket技术,将异常发往指定的服务器,并记录用户的操作步骤。因为已经制作出了Application Server,所以,这个地方实现起来也很简单。至于发送出错时,当前的操作用户名称,stack信息,甚至可以copy screen,把当前出错的屏幕图片也一同发送到服务器指定目录中。
应用框架代码,将会大量使用.NET Trace机制,将框架的运行状态输出
Public class SQLServerTraceListener : TraceListener {
public override void Write(string message)
{
using (SqlConnection conn =
new SqlConnection("server=(local);database=TraceDatabase;Integrated security=true;")) {
using (SqlCommand cmd = conn.CreateCommand()) {
cmd.CommandText = "INSERT INTO Logs(Message) VALUES(@message)";
cmd.Parameters.Add(new SqlParameter("@message", message));
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
}
}
public override void WriteLine(string message)
{
Write(message);
}
}
这样读写SQL会导致Performance下降,推荐的方式是TCP Socket技术,把异常发送到服务器(Application Server),大量的异常,是不需要处理的,比如,用户登录时输错密码,没有必要大量的写到服务器的数据库中。
框架代码可以识别哪些是关键代码出错,这些异常则很有必要记录到持久化介质中以供开发人员诊断。
元数据管理
Schema Viewer ERP维护人员最关心的数据表字段,到底存放了一些什么内容,数据间的关系
数据间关系
.NET 属性代码
从图中看到,已经将Table Name放到了Xml注释的summary中,这样,充分利用.NET智能感知。
框架数据库,还有大量的元数据管理:Report, Lookup,Query, Workflow,Form Layout,User/User Group