学习笔记 --- BLL层事物、asp.net异常处理
1. BLL层事务:
简单的BLL层的事物, 使用TransactionScope就可以, 在TransactionScope的代码块中, 无错误就调用TransactionScope对象上的Complete()方法提交数据, 若有错就自动回滚.
值得注意的是, 对于使用DataSet、DataTable等无连接存取数据时, 如果要实现BLL层事物, 则需要给出一个状态为Open的Connection. 详见文章中的System.Transactions and ADO.NET 2.0 (英文的).
//示例代码:
//DAL/Utility.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
namespace DAL
{
public class Utility
{
public static void ExeNoQuery(string sqlStr, string constr, CommandType type, params SqlParameter[] param)
{
SqlConnection con = new SqlConnection(constr);
SqlCommand com = new SqlCommand();
com.Connection = con;
com.CommandType = type;
com.CommandText = sqlStr;
if (type == CommandType.StoredProcedure)
{
for (int i = 0; i < param.Length; i++)
{
if (param[i].Value as string == string.Empty)
{
param[i].Value = DBNull.Value;
}
com.Parameters.Add(param[i]);
}
}
try
{
con.Open();
com.ExecuteNonQuery();
}
catch (Exception ex)
{
throw;
}
finally
{
if (con.State == ConnectionState.Open)
con.Close();
}
}
public static DataSet ExeDataSet(string sqlStr, string constr, CommandType type, params SqlParameter[] param)
{
SqlConnection con = new SqlConnection(constr);
SqlCommand com = new SqlCommand();
com.Connection = con;
com.CommandType = type;
com.CommandText = sqlStr;
if (type == CommandType.StoredProcedure)
{
for (int i = 0; i < param.Length; i++)
com.Parameters.Add(param[i]);
}
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = com;
try
{
da.Fill(ds);
}
catch (Exception ex)
{
}
return ds;
}
public static SqlDataReader ExeQuery(string sqlStr, string constr, CommandType type, params SqlParameter[] param)
{
SqlDataReader dr = null;
SqlConnection con = new SqlConnection(constr);
SqlCommand com = new SqlCommand();
com.Connection = con;
com.CommandType = type;
com.CommandText = sqlStr;
if (type == CommandType.StoredProcedure)
{
for (int i = 0; i < param.Length; i++)
com.Parameters.Add(param[i]);
}
try
{
con.Open();
dr = com.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (Exception ex)
{
}
return dr;
}
}
}
//DAL/EmployeeDAL.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DAL
{
public class EmployeeDAL
{
private static readonly string constr = System.Configuration.ConfigurationManager.ConnectionStrings["MsSql"].ConnectionString;
public void InsertEmployee(string employeename, int departmentid)
{
System.Data.SqlClient.SqlParameter p_name = new System.Data.SqlClient.SqlParameter("@ename", System.Data.SqlDbType.NVarChar, 30);
p_name.Value = employeename;
System.Data.SqlClient.SqlParameter p_depid = new System.Data.SqlClient.SqlParameter("@depid", System.Data.SqlDbType.Int);
p_depid.Value = departmentid;
Utility.ExeNoQuery("SP_AddEmployee", constr, System.Data.CommandType.StoredProcedure, p_name, p_depid);
}
}
}
//DAL/DepartmentDAL.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DAL
{
public class DepartmentDAL
{
private static readonly string constr = System.Configuration.ConfigurationManager.ConnectionStrings["MsSql"].ConnectionString;
public int InsertDepartment(string departmentname)
{
int depid = -1;
System.Data.SqlClient.SqlParameter p_name = new System.Data.SqlClient.SqlParameter("@depname", System.Data.SqlDbType.NVarChar, 30);
p_name.Value = departmentname;
System.Data.SqlClient.SqlParameter p_id = new System.Data.SqlClient.SqlParameter("@return_value", System.Data.SqlDbType.Int);
p_id.Direction = System.Data.ParameterDirection.ReturnValue;
Utility.ExeNoQuery("SP_AddDepartment", constr, System.Data.CommandType.StoredProcedure, p_name, p_id);
depid = (int)p_id.Value;
return depid;
}
}
}
//BLL/DepartmentBLL.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BLL
{
public class DepartmentBLL
{
#region 全局变量
DAL.DepartmentDAL dd = new DAL.DepartmentDAL();
DAL.EmployeeDAL ed = new DAL.EmployeeDAL();
#endregion
public void AddDepartmentWithSomeEmployees(string departmentname, params string[] employeenames)
{
//添加System.Transactions.dll.
//开启分布式事务支持:把 C:\WINDOWS\system32\dtclog 这个目录重命名(如果有),然后重新建立该目录。然后在命令行下: msdtc -resetlog
//在“开始”->“设置”->“控制面板”->“管理工具”->“组件服务”中,“控制台根目录”->“组件服务”->“计算机”->“我的电脑”->“COM+应用程序”中,有一个“IIS Out-Of-Process Pooled”鼠标右键“属性”--“标识”--把“此用户”调整为“交互式用户--目前已登录的用户”。然后“确定”,再鼠标右键“属性”--“启动.
using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope())
{
int departmentid = dd.InsertDepartment(departmentname);
for (int i = 0; i < employeenames.Length; i++)
{
ed.InsertEmployee(employeenames[i], departmentid);
}
ts.Complete();
}
}
}
}
//UI/Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<span>部门: </span><asp:TextBox ID="txt_dep" runat="server"></asp:TextBox>
<hr />
<span>员工1: </span><asp:TextBox ID="txt_emp1" runat="server"></asp:TextBox>
<span>员工2: </span><asp:TextBox ID="txt_emp2" runat="server"></asp:TextBox>
<span>员工3: </span><asp:TextBox ID="txt_emp3" runat="server"></asp:TextBox>
<asp:LinkButton ID="lbtn_submit" runat="server" onclick="lbtn_submit_Click">添加</asp:LinkButton>
</div>
</form>
</body>
</html>
//UI/default.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _Default : System.Web.UI.Page
{
#region 全局变量
BLL.DepartmentBLL db = new BLL.DepartmentBLL();
#endregion
protected void Page_Load(object sender, EventArgs e)
{
}
protected void lbtn_submit_Click(object sender, EventArgs e)
{
db.AddDepartmentWithSomeEmployees(this.txt_dep.Text, this.txt_emp1.Text, this.txt_emp2.Text, this.txt_emp3.Text);
}
}
//创建表的Sql命令
create database BLLTransactionDemo
go
use BLLTransactionDemo
go
if exists(select [name] from sysobjects where [name]='T_Employee' and [type]='U')
drop table T_Employee
go
create table T_Employee
(
eid int identity primary key not null,
ename nvarchar(30) not null,
depid int
)
go
if exists(select [name] from sysobjects where [name]='T_Department' and [type]='U')
drop table T_Department
go
create table T_Department
(
depid int identity primary key not null,
depname nvarchar(30) not null
)
go
if exists(select [name] from sysobjects where [name]='SP_AddDepartment' and [type]='P')
drop procedure SP_AddDepartment
go
create procedure SP_AddDepartment
(
@depname nvarchar(30)
)
as
begin
insert into T_Department(depname) values(@depname);
return @@identity;
end
go
exec SP_AddDepartment '32'
if exists(select [name] from sysobjects where [name]='SP_AddEmployee' and [type]='P')
drop procedure SP_AddEmployee
go
create procedure SP_AddEmployee
(
@ename nvarchar(30),
@depid int
)
as
begin
insert into T_Employee(ename,depid) values(@ename,@depid)
end
go
exec SP_AddEmployee '王',10
select * from T_employee
select * from T_department
2. asp.net的错误处理机制(简述):
asp.net的错误处理机制共分3个层次, 代码级的错误处理, 页面级的错误处理, 网站级的错误处理.
首先, 代码级的错误处理: 很简单,就是try...catch的使用
其次, 页面级的错误处理: 在页面事件处理方法中抛出的异常可以被IHttpHandler中约定的ProcessRequest方法所捕获, 可以通过页面处理对象的Error事件来处理异常.但是Error事件的委托类型是EventHandler, 换句话说就是它无法获得异常信息. 这时, 可以通过HttpContext获得Server对象, 该对象提供了public Exception GetLastError()和pulic void ClearError()两个方法来处理异常. 若,页面级处理了异常, 异常将不再会被抛出到应用程序中.
最后, 网站级的错误处理: 可以在HttpApplication对象的Error事件中处理, 可以再IHttpModule中处理, 但为简单起见, 更常见的是在Global.asax中处理. 值得注意的是, 此时的异常已被包装, 需要通过Server.GetLastException().InnerException来获取异常.
网站级别的异常处理的配置: 当网站出现未处理的异常时, 可以通过web.config文件中的customErrors元素进行配置(mode有3种可选值,off关闭错误处理, 直接显示异常给客户;On想所有用户返回自定义错误信息页面;RemoteOnly向远程用户返回自定义错误信息页面, 向本级客户返回错误详细内容.), 且defaultRedirect属性用来指出自定义的错误信息页面的URL地址(地址可以是相对的, 也可以使绝对的, 相对地址是针对网站根目录的).