ASP.NET 常见参考项目的 UI、BLL 、Model 、 DAL 分析

应用/项目名称 UI层实现 Business Model & Logic Layer 实现 Data Access Layer 实现
Personal Web Site Starter Kit 在ASP.NET页面上直接利用 ObjectDataSource 来绑定 PhotoManager 中的方法来获取数据、更新数据 两个数据实体类(Album、Photo),一个管理类(PhotoManager)
自行解决数据库连接、使用 SqlCommand 来调用存储过程来完成
Club Web Site Starter Kit 在ASP.NET页面上直接利用 SqlDataSource 来获取数据、更新数据 只有一些简单的 Helper/Utility类,业务逻辑大多在页面上实现 有一个DataSet,提取 Member表的数据,在自己的数据库中扩充了 SqlMembershipProvider的字段
Classifieds Site Starter Kit 在ASP.NET页面上,增/删/改主要是利用FormView调用BLL中的ModelDB来实现,数据列表主要利用ModelCache的List和ModelDB返回的ModelDataTable来绑定 1) BLL中实现了 ModelDB的类,调用DAL中的DataSet来进行数据更新,如果是查询数据(GetModelList),则得到 ModelDataComponent.ModelDataTable,这是数据集自动生成代码中的一个类

2) 在 App_Code 的Web目录中,主要实现了部分实体在 HTTP Context中的Cache功能,建立了 CachedModel(数据实体类)及其管理对象 ModelCache,后者主要是将BLL层的ModelDB的Retrive结果DataTable转成 List

全是ASP.NET 2.0 中的DataSet,实现了所有表数据的获取与更新,它是调用存储过程来实现的
Commerce Starter Kit 在ASP.NET页面上,有一些是直接调用 ModelManager对象来完成用户交互,有一些则是利用 ObjectDataSource 绑定 ModelManager 来达到同样功能

对于某些操作,如果没有对应的 ModelManager 则直接使用 SqlDataSource

1) 在Objects目录下,定义了数据实体类,包含所有属性的Get/Set方法的定义,没有实例化方法,而是使用 void Load(IDataReader)来初始化,其中有一个对象(ShoppingCartItems),则继承至DataTable,利用BuildDataTable()来进行初始化

2) 利用数个 ModelProvider 将与数据库的主要交互功能封装起来,提供了实体层次的CRUD

3) 在 BLL 目录下,有数个 ModelManager,提供从业务层面对 Model 的操作,其中主要是调用 ModelProvider来完成具体的操作

在 ModelProvider项目中中,先定义ModelProvider抽象类,再由 SqlModelProvider 来继承,后者中利用 SqlHelper 来完成数据访问,主要是调用存储过程
Duwamish 7.1
(.NET 1.1)
调用BusinessFacade中的 OrderSystem 和 ProductSystem 中的方法完成用户交互,这主要是调用DAL层的相关对象来完成的 1) ModelData,继承自System.Data.DataSet,在构造函数里调用BuildDataTables()来初始化一个DataTable用来存储Model数据

2) 在BusinessFacade和BusinessRule中,实现了与业务逻辑有关的内容,调用数据层的 Models 来完成数据访问

实现了数个 Models对象,提供了对于 ModelData的CRUD方法,它也是调用 SqlHelper 来完成与数据库的交互
Jobs Site Starter Kit 利用 ObjectDataSource 绑定 Model 类,Command 主要是调用 Model 的 CRUD方法 在 Model 对象中定义了所有属性和CRUD方法,实现时调用了 DAL 的 DBAccess 对象,也使用了诸如 SqlParameter 等对象 只有一个类 DBAccess ,属于工具类,类似于 SqlHelper,它是利用 System.Data.SqlClient 来实现的,如果向其他数据库移植,代码量不大
Timer Tracker Starter Kit 利用 ObjectDataSource 绑定 Model 类,Command 主要是调用 Model 的 CRUD方法 在 Model 对象中定义了所有属性和CRUD方法 DataAccess:抽象类,定义了DAL层需要实现所有 Model 的 CRUD 对应的数据访问方法

DataAccessHelper:工厂类,利用配置创建相应的 DataAccess 对象

SqlDataAccess:DataAccess 的 SQL Server 实现,其中也包含一些类似于SqlHelper 的通用方法以简化代码

.Text 0.95
(.NET 1.1)
大多数是调用 Model有直接调用 SqlDataProvider 来获取数据、更新数据 在Dottext.Framework 的 Component 中定义了业务实体 Model 和 ModelCollection,在在Dottext.Framework定义了 Models 类,主要用提供 Model 的 CRUD 方法,其中的 R 返回 ModelCollection 在Dottext.Framework 的 Data 中定义了 IDbProvider和 IDTOProvider 接口,然后提供了 DataDTOProvider 和 SqlDbProvider 的实现,其中调用了 SqlHelper 类
Community Server 2.1 SDK
(.NET 1.1 & 2.0)
直接调用 Models 的方法来获取数据、更新数据等 在 CommunityServerComponents 项目的 Components 中定义 Model 类,其中仅包含属性定义及构造函数,另外定义了 Models 类,其中实现了 Model 的 CRUD 方法,它是调用 Provider 下的 CommonDataProvider 来完成数据访问的 在 CommunityServerComponents 项目的 Proivder 中,利用抽象类CommonDataProvider 定义了所有 BLL & Model 层需要的数据访问方法,然后在 SqlDataProvider 中项目中使用 SqlDataProvider 继承此类,完成与 SQL Server 数据库的交互
.Pet Shop 4.0 在 ASP.NET 的页面上,大多是利用代码来调用 BLL 层的 Model 对象来获取数据、更新数据 Model 项目 中定义了所有的业务实体 ModelInfo
BLL 项目中定义业务实体 Model ,其中包含业务视角的 CRUD 方法,它们是调用 IDAL 中的 IModel 的 CRUD 方法来实现的
IDAL 项目中有多个接口定义 IModel,其中定义了需要实现的 Model 的 CRUD 方法
SqlServerDAL 和 OracleDAL 分别在两种数据库上实现了 IDAL
DALFactory 为工厂类,负责根据配置返回相应的 IDAL 的 IModel 实现类
DBUtility 是 SQL Server 和 Oracle 数据库操作的工具类,主要是 SQLHelper 和 OracleHelper

简单个人评价:

  1. Personal Web Site Starter Kit:简单,供初学者参考之用
  2. Club Web Site Starter Kit:对标准 MemberShip 的扩充值得一看
  3. Classifieds Site Starter Kit:结构较为清晰,利用 DataSet 简化了大量 SQL 代码的编写
  4. Commerce Starter Kit: 利用了 Provider 模型,有些小瑕疵,如界UI层有 SqlDataSource,Model 中有 DataTable
  5. Duwamish 7.1:架构比较清晰,但Model 继承自 DataSet ,因此其 BuildDataTables 和 Models 中的CURD 方法较为麻烦,代码量较大
  6. Jobs Site Starter Kit:简单实用,有些缺点,如 Model 的 CRUD 方法的 SqlParameter 造成 BLL 和 DAL 无法完全隔离
  7. Timer Tracker Starter Kit:一种架构清晰、较好的实现模式,只是代码量稍大
  8. .Text 0.95:基于 .NET 1.1 ,因此 BLL 层稍显复杂,DAL 层代码量也较大
  9. Community Server 2.1:它同时兼容 .NET 1.1 和 .NET 2.0 ,因此没有利用 .NET 2.0 的许多特性,但其 Provider 的模式较为清晰
  10. .Pet Shop 4.0:架构清晰

注:上述分析以数据访问为主,本 Post 是使用 Windows Live Write 来编写完成

数据访问层实现的一些个人想法

个人感觉数据访问层应该实现以下几个主要目的:

1) 分离业务层与数据层

2)屏蔽具体数据库的差异(如SQLServer、Oracle、OLEDB、ODBC等)

3)简化数据访问层的代码,经常写一些 Parameter 的设定是很无聊的事情)

先下载并研究了一下Enterprise Library 2.0 ,发现其中的Data Access Application Block有点复杂了,有近 40 个类文件,还需要引用 Configuration、Common、ObjectBuilder 等项目,本身就是一个很大的项目了… 个人觉得还不如上一个版本中的 SQLHelper 对象那么简单方便(Pet Shop 4.0 中的 DabaAccess 项目里就是用 OracleHelper和SQLHelper来实现的)

再来研究Pet Shop 4.0 ,其中主要对象层次一般是(假设Model是业务对象):

ModelInfo <- Model -> IDAL <- SQLServerDAL(或OracleDAL)

其中:

  • ModelInfo 是瘦的业务实体数据对象
  • Model 实现 ModelInfo 的管理(增、删、改、查询)等,调用 IDAL 来实现
  • IDAL 是数据访问层的接口定义
  • SQLServerDAL 是 IDAL 在 SQLServer 上的实现,如果是 Oracle,可以利用 OracleDAL 来实现

貌视还不错的结构,只是 DAL 层的里面的代码还是比较多,好多SQL、好多Parameter的操作

再看看 Visual Studio 2005 中带的”个人网站的初学者工具包”的数据访问代码,它只是简单在App_Code中有 Model(瘦的业务实体数据对象)、ModelManager(管理对象,数据层的访问也在其中实现)的两个对象,数据库也只是SQL Server,较为简单,但也不易扩展。

我的一点想法:

1)Enterprise Library 2.0 有些庞大和重量级,学习曲线太长,谨慎使用

2)Visual Studio 2005 中的数据集对象(DataSet)是个好东西,可以简化很多SQL语句的编写和参数的设定

3)Pet Shop 4.0 的总体架构还是不错的(Model <- ModelInfo -> IDAL <- SQLServerDAL),值得参考,但是在SQLServerDAL 和 OracleDAL 不用手动去编写代码,而是调用利用 DataSet 自动生成的代码来实现(SQLServer、Oracle、OLEDB或ODBC等),简单的业务对象管理动作应該是能直接利用DataSet提供的方法直接实现,如果是复杂的数据层操作,可以自己编写代码来实现(如多个表之间的数据操作)

4)musiclandJGTM 2006 也提供了一种不错的实现方式,具体参考这篇Post

这样的话,开始提到的三个目的都能达到了。

.NET 中对日志操作时的一个问题

近几天用 C# 在对日志进行操作的时候,发现经常无法正常写入正确的日志条目,经过测试,发现这可能是 .NET 的一个 Bug ,重现/测试程序如下:

static void Main(string[] args) ...{ string sSource = "DotNetMySource"; string sLog = "DotNetMyLog"; //新建日志文件及源并写入一条日志 if(!EventLog.SourceExists(sSource)) ...{ EventLog.CreateEventSource(sSource,sLog); Console.WriteLine("Source Created"); } EventLog log = new EventLog(); log.Source = sSource; log.WriteEntry("Hello China"); Console.WriteLine("Log Entry Writed"); Console.ReadLine(); //删除刚才的建立日志文件及源 if(EventLog.SourceExists(sSource)) ...{ EventLog.DeleteEventSource(sSource); Console.WriteLine("Source Deleted"); } else ...{ Console.WriteLine("Source Not Found"); } if(EventLog.Exists(sLog)) ...{ EventLog.Delete(sLog); Console.WriteLine("Log Deleted"); } else ...{ Console.WriteLine("Log Not Found"); } Console.ReadLine(); //重新建立同样的日志文件及源 if(!EventLog.SourceExists(sSource)) ...{ EventLog.CreateEventSource(sSource,sLog); Console.WriteLine("Source Created"); } log = new EventLog(); log.Source = sSource; log.WriteEntry("Hello China Again"); Console.WriteLine("Log Entry Writed"); Console.ReadLine(); }

在程序运行的三个步骤中,你需要打开/关闭“日志查看器”以确定每次程序执行的结果(日志查看器中的刷新功能,不能刷新新建立的日志文件)。

在最后程序执行结束后,你会发现新写入的日志条目的“源”属性为空,而不是预计的 “DotNetMySource”。

甚至有时候会出现把日志写入到 Application 日志文件中的情况,且在日志查看器中会看到如下的消息(英文 OS):

The description for Event ID ( 0 ) in Source ( DotNetMySource ) cannot be
found. The local computer may not have the necessary registry information or
message DLL files to display messages from a remote computer. You may be
able to use the /AUXSOURCE= flag to retrieve this description; see Help and
Support for details. The following information is part of the event: Hello China Again

目前似乎没有别的解决办法,在 VS.NET 中直接删除日志文件,也会出现同样的问题,只有换用不同的 Source Name 和 Log Name 了,如果不删除,在写入新的 Log Entry 时好象没有这样的问题。

希望大家有时间测试一下,也希望 MS 的同志们确认是否是一个 Bug。

 

ASP.NET开发经验(5) — 制作功能完善的安装程序

每年到这个时候,周围做技术开发的人都会懈怠下来,听电台上说,这叫“岁未综合症”,但对于部分做与财务或运营相关来人说,年底可能是最忙的一段时间了,象我们这里,每年的12月31日午夜要进行年终决算,计算大家帐户里的利息,所有做运营维护的人员在饱餐了一次丰盛的美食后,就开始了通宵忙碌,当然也有运气不好的开发人员会被拉去做技术支持。

既然偷点空闲了,就写点 ASP.NET 应用安装程序的东西吧。

象 ASP、ASP.NET 等诸多基于 Web 的应用程序的安装与部署一直是个麻烦事情,一般都是手工复制、手工修改相关配置文件(主要是数据库配置),和 Windows 上 Installer 或 Linux 上的 RPM 相比,这种方式显然一点技术含量都没有

对于胖客户端应用,从很早开始就一直都有较为完善的安装程序制作工具了,如 InstallShield、InstallAnywhere、Wise Installer、SWIFT Installer 等等,其中一部分已经实现了跨平台,可以运行在 Windows、Linxu、Java 等平台上。

从 Visual Studio 6.0 开始,Microsoft 提供了单独的 Setup Tools ,可以用来制作简易的安装程序,后来,这个工具被集成到 VS.NET 2002/2003 中,并且功能做了一些增强,可以制作自定义的对话框等。其优点是能很好的和 VS.NET 的项目进行集成,这样在整个解决方案(Solution)在 Build 的时候,就可以生成安装包,这样便于实现每日构建(Daily Build),同时其缺点仍然存在,不能对安装过程进行更多地控制,提供的对话框功能和类型有限,很少看到有人利用这些对话框实现对系统的一些较为复杂的配置,如绝大多数应用程序中都会涉及的数据库创建、初始数据的生成等工作。

有很多不错的安装工具中,在安装的过程中就可以对实现对系统进行一些配置,但安装结束后,如果配置发生改变,例如数据库迁移等,又变成一件令人头疼的事情,如果对系统了解较多,知道配置数据的存放位置,就可以手动修改,如果不了解怎么办?难道要先卸载,再重新安装来完成新配置?

在很多不错的胖客户应用中,配置界面是和安装界面独立的,这样便于在安装系统后,灵活地调整其配置,那么就把它拿到 ASP.NET 的安装程序中吧。

1) 建立解决方案 Solution

2) 建立 Web 应用 

3) 新增一个 WinForms 应用 AppConfig,增加一个 WinForm ,完成初始化系统环境,修改系统配置的功能(如生成数据库、生成初始数据、修改 Web.Config 中的数据库连接参数,Machine.Config 或自定义配置文件)等功能,生成 AppConfig.exe 

4) 新增一安装项目 Setup,除了将 Web 应用的的“主输出”和“内容输出”加入到项目中,还要将 AppConfig 的“主输出”加入到此项目中

5) 在 Setup 项目中的“自定义操作中”的“安装”节,增加一自定义操作,使其运行来自于 AppConfig 的“主输出” AppConfig.exe

这样 ASP.NET 的安装程序在运行的最后阶段,会运行 AppConfig 的 WinForm 程序,来完成相关的配置,如数据库等。如果以后配置发生改变,可以直接运行 AppConfig.exe 来更改配置。

值得一提的是,由于 AppConfig 是 WinForms 应用,相对于 Installer 的对话框而言,有很大的发挥余地,例如我经常在项目中加入 SQL Server 管理对象 Interop.SQLDMO.dll 的引用,这样可以在输入/选择 SQL Server 的列表框中实现自动列出可用的 SQL Server 名称列表,看起来很专业的样子,用户很喜欢,后果很不错。

ASP.NET开发经验(4) — 一种简便地同时使用匿名与集成 Windows 验证的方法

相对来说,集成 Windows 验证是 ASP.NET 提供的一种安全性较高的验证方式,不用考虑被 Sniffer、不用去创建登录页面、不用去考虑登录失败次数限制、更重要的是,不用在应用程序中提供用户管理的功能,以及如何保护数据库中的用户名和密码。

经常会碰到这种应用场景:用户对一些普通功能可以匿名访问,对另外一些高级/管理功能,则需要登录后才能使用,很多人的做法就是将普通功能的页面放置在一个目录中,而高级/管理功能的页面则放在另外一个目录中,使用不同的 Web.Config 设置(<authorization> 的 <allow/> 或 <deny/>节)来控制,这样可能带来的一个问题就是:实现同样功能的页面可能要被复制两份,分别部署在这些目录中。

如果全部页面只在一个目录中,有什么办法可以同时实现匿名和授权用户的访问呢?即如何在需要验证用户的时候,弹出那个集成验证的对话框。

如果是基于 Forms 验证,则只需要手动调用(链接)一个 Login.aspx 就可以解决这个问题,但对于 Windows 集成验证来说,仔细查看了一下 WindowsAuthenticationModule 类,似乎没有找到可以编程控制来弹出 Windows 集成验证的那个对话框的方法。

还是采取了一个土办法。

  • 原有页面目录中的 Web.Config 设置如下:

   <authorization>
        <allow users=”*” />
   </authorization>

  • 新建一个子目录,Web.Config 设置如下:

   <authorization>
        <deny users=”?” />
   </authorization>
  

  • 在子目录中创建一个简单的 Auth.aspx ,使其 Response.Redirect 到上级目录中的页面
  • 在原有页面中的适当位置,建立一个“Login”的链接,指向 Auth.aspx

这样就可以在原有页面中通过 User.Identity.Name 是否为空来检测用户是否登录,当然也可以在 Auth.aspx 中通过检查用户的 User.Identity.Name ,来进行一些其它的处理,如取出用户的权限、记录日志等。

估计还有更好的方法,探寻中 … …

PHP 移植的几点经验

最近帮别人忙将一个在 Linux 上的 PHP + MySQL 的小系统移植到 Windows 上,PHP 不变,数据库改用 SQL Server ,整个移植过程挺简单。

1、环境

  • 在 Windows 上安装 PHP ,注意要将 PHP\sessiondata 的目录设置为 IUSR_Machine 用户可写
  • 在 IIS 中建立 PHP 的虚拟站点,如果是 IIS 6.0,新增加一个 PHP 的 CGI 扩展并启用之
  • 修改 PHP.ini ,使 PHP 可以连接 SQL Server,extension=php_mssql.dll,并更改 session.save_path (Linux 上一般是 /tmp,Windows 上是 C:\PHP\sessiondata)
  • 在 Windows 上安装 MySQL、MySQL Control Center(可选)、MySQL ODBC Connector。

2、数据库

  • 将 MySQL 的数据备份文件恢复
  • 在 SQL Server 中新建 DB,并使用 DTS 将 MySQL 的 DB 导入
  • 可以还要做少许设置,将一些未能导入的设置还原,如 Key、Index、Auto Increment 列等
  • 在新数据库建立专门的 PHP 访问登录用户

3、应用

  • 将 MySQL 的数据库连接参数改成 MS SQL Server ,参数都差不多,无非 Server、DB Name、UserName 和 Password 等;
  • 将所有 PHP 页面中的 mysql_XXX 函数替换成 mssql_XXX   函数,唯一不同的是没有 mssql_error 这个函数;
  • MySQL 的 SQL 中可以用 “’” 来加在表名的两端,这在 SQL Server 中是非法的,将其替换成空(替换成 [ ] 也可以,但太麻烦);
  • MySQL 的 SQL 中使用 LIMIT m,n (从 m 条开始取 n 条记录)来实现分页,SQL Server 中没有这样的功能,只能使用 TOP 和子查询来实现了

如 SELECT * FROM Orders ORDER BY ID DESC LIMIT 10,5 ,可以变成:

SELECT TOP 5 * 
FROM ( SELECT TOP 5 * 
                  FROM ( SELECT TOP 10+5 *
                                     FROM Orders
                                     ORDER BY ID DESC ) Temp1
                  ORDER BY ID ASC ) Temp2
ORDER BY ID DESC

之所以用这么复杂的 SQL ,是为了保证只取出有限行的数据,并且排序保护不变,不过效率未知

  • 将一些 SQL 的关键字予以处理,在 MySQL 中,User、Size、Language、Top 等都可以使用,但要在 SQL Server 的 T-SQL 中使用,则必须要在两边加 [ ] 了。


基本上就改这么一些东西,如有必要,再更改一下默认首页的名称,就可以完全正常使用了。

ASP.NET开发经验(3) — 使用 GUID 值来作为数据库行标识

GUID(Global unique identifier)全局唯一标识符,它是由网卡上的标识数字(每个网卡都有唯一的标识号)以及 CPU 时钟的唯一数字生成的的一个 16 字节的二进制值。

GUID 的格式为“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字。例如:6F9619FF-8B86-D011-B42D-00C04FC964FF 即为有效的 GUID 值。

世界上的任何两台计算机都不会生成重复的 GUID 值。GUID 主要用于在拥有多个节点、多台计算机的网络或系统中,分配必须具有唯一性的标识符。在 Windows 平台上,GUID 应用非常广泛:注册表、类及接口标识、数据库、甚至自动生成的机器名、目录名等。

在这次开发 ASP.NET 应用时,我大量使用了类型为 GUID 的 ID 列作为各实体表的关键字(键)。由于其唯一、易产生的特性,给应用程序处理带来诸多好处。

1、在 SQL Server 中使用 GUID

如果在 SQL Server 的表定义中将列类型指定为 uniqueidentifier,则列的值就为 GUID 类型。

SQL Server 中的 NewID() 函数可以产生 GUID 唯一值,使用此函数的几种方式如下:

1) 作为列默认值

将 uniqueidentifier 的列的默认值设为 NewID(),这样当新行插入表中时,会自动生成此列 GUID 值。

2)使用 T-SQL

在 T-SQL 中使用 NewID()函数,如“INSERT INTO Table(ID,… ) VALUES(NewID(),…)”来生成此列的 GUID 值。

3)提前获取 GUID 值

由于特殊功能需要,需要预先获知新行的 ID 值,也可以使用如下 C# 代码提前获得 GUID 的值,再存储到数据库中:

 SqlCommand cmd = New SqlCommand();
 cmd.CommandText = “SELECT NewID()”;
 string rowID = (string) cmd.ExecuteScalar();
 cmd.CommandText = “INSERT INTO Table(ID,…) VALUES(@ID,…)
 cmd.Parameters.Add(“@ID”,SqlDbType.UniqueIdentifier).Value = new Guid(rowID);
 cmd.ExecuteNoQuery();

uniqueidentifier 值不能进行算术运算,但可以进行(意义不大的)比较操作和 NULL 检查;它不能象 IDENTITY 列一样,可以获知每行的增加时间的先后顺序,只能通过增加其它时间或时间戳列来完成此功能。

2、在 .NET 中使用 GUID

GUID 在 .NET 中使用非常广泛,而且 .NET Framework 提供了专门 Guid 基础结构。

Guid 结构的常用法包括:

1) Guid.NewGUID()

生成一个新的 GUID 唯一值

2) Guid.ToString()

将 GUID 值转换成字符串,便于处理

3)构造函数 Guid(string)

由 string 生成 Guid 结构,其中string 可以为大写,也可以为小写,可以包含两端的定界符“{}”或“()”,甚至可以省略中间的“-”,Guid 结构的构造函数有很多,其它构造用法并不常用。

同时,为了适用数据库中使用 GUID 的需要,.NET Framework 也提供了 SqlGUID 结构,它和 Guid 结构类似,只是两者对排序(CompareTo)的处理方式不同,SqlGuid 计算值的最后 6 个字节。而 Guid 计算全部 16 个字节,这种差异可能会给 SQL Server 中 uniqueidentifier 列的排序带来一定影响,当然这种排序意义也不大。

.NET Framework 中可以使用类 GuidConverter 提供将 Guid 结构与各种其他表示形式相互转换的类型转换器。

3、GUID 的优缺点

1) 优点

  • 同 IDENTITY 列相比,uniqueidentifier 列可以通过 NewID() 函数提前得知新增加的行 ID,为应用程序的后续处理提供了很大方便

  • 便于数据库移植,其它数据库中并不一定具有 IDENTITY 列,而 Guid 列可以作为字符型列转换到其它数据库中,同时将应用程序中产生的 GUID 值存入数据库,它不会对原有数据带来影响。

  • 便于数据库初始化,如果应用程序要加载一些初始数据, IDENTITY 列的处理方式就比较麻烦,而 uniqueidentifier 列则无需任何处理,直接用 T-SQL 加载即可。

  • 便于对某些对象或常量进行永久标识,如类的 ClassID,对象的实例标识,UDDI 中的联系人、服务接口、tModel标识定义等。

2) 缺点

  • GUID 值较长,不容易记忆和输入,而且这个值是随机、无顺序的,所以使用时要注意场合,最好不要尝试用它来作为你的电子邮件地址 J

  • GUID 的值有 16 个字节,与其它那些诸如 4 字节的整数相比要相对大一些。这意味着如果在数据库中使用 uniqueidentifier 键,可能会带来两方面的消极影响:存储空间增大;索引时间较慢。

综合来说, GUID 的优点带来的便利远超出其缺点带来的影响,随着诸如 WebService 等系统互联与整合技术的不断发展,其唯一标识的特性使得其应用越来越广,在您的应用程序中也应考虑使用它了。

ASP.NET开发经验(2) — ASP.NET中的一些图形处理

如果大家用过 SharePoint Portal Server 2001,一定会记得增加型文件夹中的一些很不错的特性,如文档检出/检入、发布、审批流程等,其中最吸引我的就是它通过在文档的图标上加一个特别的标记,来表示文档的状态,如下图所示:

自己在做文档管理系统时,也借鉴了这种做法,其实和给图片加水印的作法类似,主要代码如下:

function codedisplay()
{
if(document.all(“code”).style.display == “none”)
{
document.all(“code”).style.display = “”;
document.all(“codeop”).innerText = “Hide Code>>”;
}
else
{
document.all(“code”).style.display = “none”;
document.all(“codeop”).innerText = “Show Code>>”;
}

}

Show Code>>

//取源图像
Image imgPhoto = Image.FromFile(sSourceFile);
Bitmap bmPhoto = new Bitmap(imgPhoto.Width, imgPhoto.Height, PixelFormat.Format24bppRgb);
bmPhoto.MakeTransparent();
//设置绘图面属性,呈现质量等   
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.SmoothingMode = SmoothingMode.AntiAlias;
grPhoto.DrawImage( imgPhoto, new Rectangle(0, 0, imgPhoto.Width, imgPhoto.Height), 0, 0, imgPhoto.Width, mgPhoto.Height, GraphicsUnit.Pixel);

//打开要附加的水印图片
Image imgWatermark = new Bitmap(sWatermarkFile);
Bitmap bmWatermark = new Bitmap(bmPhoto);
bmWatermark.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
Graphics grWatermark = Graphics.FromImage(bmWatermark);

int xPosOfWm = imgPhoto.Width – imgWatermark.Width;
int yPosOfWm = imgPhoto.Height – imgWatermark.Height;

//画
grWatermark.DrawImage(imgWatermark,
   new Rectangle(xPosOfWm,yPosOfWm,imgWatermark.Width,imgWatermark.Height),
   0,                 
   0,                  
   imgWatermark.Width,           
   imgWatermark.Height,     
   GraphicsUnit.Pixel);

//保存最终图片
imgPhoto = bmWatermark;
imgPhoto.Save(sIconFileName,ImageFormat.Png);

如果文档有审阅流程,那文档的流转图就非常受欢迎了,这样用户可以方便地查看文档正处于那个阶段。
其实与工作流有关软件可能都有这样要求,我目前没有找到更好的办法,利用 <table> ,将各个阶段
用线条和图形表示出来,办法虽有点笨,但好象显示效果还不错。

曾经试过 VML ,发现要动态地画这种图,就得很精确地控制屏幕上位置,比较麻烦,后来放弃了这种作法。

还曾经想用 Visio Automation 来试一下,发现 Visio 的对象模型和 VBA 比 Word 和 Excel 的难多了,工作量更大。

ASP.NET开发经验(1) — 解决ASP.NET与CSS中定义的中文字体名的冲突

最近做了一个 ASP.NET 的文档管理程序,有点类似于简化的 SharePoint Portal Server 2001,有兴趣的可以看看程序运行的截图 (多图)。

在开发过程中,陆续碰到和解决了一些不常见的问题,我会慢慢把这些问题和解决的办法都写出来。代码目前还有点乱,过两天再整理一下,请 Ma QiJGTM’2004kaneboy 等几位高手帮我做一下 Code Review 或 Refactory。

前两天,在修改 ASPX 页面时,发现一个奇怪的问题,链接的CSS 文件里指定的其它设置都管用,就是字体名称设置不管用,如果直接在 ASPX 页面中指定字体名称(Style=”font-family:宋体”)就是正常的。

为了测试,我用 FrontPage 新建了一个 HTML 页面并链接了CSS 文件,页面显示正常,但当我把 HTM 后缀改成 ASPX 后,又失效了。

难道是 ASPX 和 CSS 有冲突? 可这两个东西风马牛不相及呀,于是仔细对比 HTM 和 ASPX 页面的源码,没有发现任何不同的地方,真是百思不得其解。最后终于无意中发现,HTM 页面和 ASPX 页面的编码方式不一样,HTM 是 GB2312 ,ASPX 是 UTF-8(即使其中含有 <meta http-equiv=”Content-Type” content=”text/html; charset=gb2312″> 的标记)。

到此时我才明白,原来就是因为 ASPX 的输出编码为 Unicode,在处理 CSS 中的中文字体名(如“宋体”,“黑体”)时出错了错误,导致不能正确显示指定的字体。

处理办法:

1) 将 ASP.NET 的默认编码方式由 UTF-8 改为 GB2312 ;

    不过,现在都搞全环化、国际化,还是用 UTF-8 好。

2) 将 CSS 文件中的中文字体名变为英文名称;

   如 “Font-Family: 宋体” 改为 “Font-Family: SimSun” ,其它字体的英文名称如:SimYou 幼圆; SimHei 黑体; SimKai 楷体; SimFang 仿宋; SimLi 隶书等。

3) 将 CSS 文件中的中文字体名改为 Unicode 表示(\u…)

    此种方法未试验,不知是否可行。

至于为什么我一定要用中文字体呢,原因是中文字体是等宽的,在处理页面时,能很精确控制元素的宽度,这样有利于版面的设计,我对软件界面的要求是很高的 笑脸

Windows Longhorn 界面体验

PDC 2003 中的相关演示来看,Windows Longhorn 的新界面的确实非常漂亮,有好事者利用纯粹的 HTML 来仿效这种界面,仅仅利用 Internet Explorer 中的 CSS 和少量 Javascript 就完成了,按作者的话来说,它虽然比较慢并且没什么实际用处,但是确实很 Cool !

看了一下源代码,看到了大量的 CSS 和 Filter ,就是用这个来实现了透明和渐近色,他说还要尝试用 SVG 来实现同样的功能,如果实出现的好,可以和 Microsoft 的 XAML 有一拼呀 吐舌笑脸

来源:Sjoerd Visscher’s weblog