1.建立一个自己的异常类。有一点是我比较困惑的,如果我通过SqlCommand来执行一个查询或者更新,由于种种原因操作没有成功,抛出一个SqlException,那么在SqlException里面应当有一个属性来打印查询或更新的sql命令文本。就我个人而言,我觉得这是对开发者最有帮助的信息。虽说异常里提供了调用栈,可以帮我定位到出错的数据层、逻辑层或显示层方法,但查看这些方法的源代码、找出里面执行数据库操作的相关语句效率还是太低了。可我找了半天也没找到,如果哪位同志清楚的话能不能跟我说一下?如果确实没有这个属性,请问又是为什么呢?我自己的异常类非常简单,除了一个SqlException类型的对象,就是一个表示sql命令的文本,代码如下:
1
public class SqlTextException : Exception
2
{
3
private SqlException baseException = null;
4
private string sqlText = null;
5
6
public SqlTextException(SqlException e, string sql)
7
{
8
baseException = e;
9
sqlText = sql;
10
}
11
12
public SqlException BaseException
13
{
14
get
15
{
16
return baseException;
17
}
18
}
19
20
public String SqlText
21
{
22
get
23
{
24
return sqlText;
25
}
26
}
27
}

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

2.接下来,在数据层的相关位置截获sql异常,并封装成SqlTextException类型继续抛出,以数据层的一个方法举例如下:
1
public Object ExecuteScalar(string cmdText, SqlParameter[] sqlParams)
2
{
3
if (cmdText == null)
4
return null;
5
6
Object result = null;
7
SqlCommand command = this.PrepareCommand(cmdText, sqlParams);
8
9
try {
10
connection.Open();
11
result = command.ExecuteScalar();
12
}
13
catch (SqlException e) {
14
SqlTextException myE = new SqlTextException(e, cmdText);
15
throw myE;
16
}
17
finally {
18
connection.Close();
19
}
20
return result;
21
}

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

3.异常被创建了,也从数据层被抛出了,接下来就是对异常的处理了。正如随笔开头所说的那样,数据层会在两种运行环境中被用到,一种我们姑且称之为同步Web环境,这种环境的特点有3:(1)程序的运行是由客户端对服务器端页面的请求直接引发的;(2)当前线程位于w3wp工作进程管理的线程池中;(3)用户正在客户端等待页面刷新。而另一种运行环境,要么代码是在服务器端的后台运行(windows服务),要么代码是另起一个工作线程在后台处理(任务队列),我们姑且统称为非Web环境。下面就对这两种环境分别叙述。
同步Web环境在整个系统中占主要地位,如果在所有可能抛出异常的方法里都进行异常的捕获和处理,工作量将十分巨大。还好,ASP.NET已经为我们定义了一个很好的异常处理结构(具体可参见msdn),我们可以在某个时刻(具体来说,就是Page_Error事件和Application_Error事件中)对页面或者整个应用程序的未处理异常(异常抛出时,CLR会向上遍历整个调用栈来查看与被抛出异常对象类型相匹配的catch块;若未找到这样的catch块,就会出现一个unhandled exception)统一进行处理。最后我的实现是使用了Application_Error事件,即在Global.ascx中加入如下代码段:
1
void Application_Error(object sender, EventArgs e)
2
{
3
Exception objErr = Server.GetLastError().GetBaseException();
4
GEA52.Rule.SqlBase.SqlTextException myExp = objErr as GEA52.Rule.SqlBase.SqlTextException;
5
if (myExp != null)
6
{
7
string err = "引发错误的sql语句为:\n" + myExp.SqlText +"\n; 系统返回的出错信息:"+myExp.BaseException.Message;
8
Server.ClearError();
9
GEA52.Rule.CommonRule.ShowError(err);
10
}
11
else
12
{
13
string err = "在Application_Error事件中捕获异常:\n" +
14
"Error in:" + Request.Url.ToString() +
15
"\nError Message:" + objErr.Message.ToString() +
16
"\nStack Trace1:" + objErr.StackTrace.ToString();
17
18
Server.ClearError();
19
GEA52.Rule.CommonRule.ShowError(err);
20
}
21
}

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

非Web环境可就没那么幸运了,我还没能找到一个统一的未处理异常处理位置(哪位兄弟知道,望不吝赐教^_^)。好在这部分代码不多,我在一些主要的方法调用处进行了异常捕获,并把捕获后的异常存储数据库(在数据库里建了ErrorLog表,表包含Message,Source,TargetSite,StackTrace等列来记录异常的一些主要属性),这一部分就不赘述了。