ASP.NET三层架构步骤讲解

 

 

 

前言:

与ASP相比ASP.NET在Web应用开发上无疑更容易,更有效率。Web开发大部分还是围绕着数据操作,建立数据库存储数据,编写代码访问和修改数据,设计界面采集和呈现数据。走过Asp.net学习入门阶段后,真正开始着手开发一个Web项目时,才发现错综复杂的数据与关联根本就不是SqlDataSource和AccessDataSource数据源控件能简单解决的,而恰恰是被忽视了的一个ObjectDataSource数据源控件才是真正踏入开发门槛的关键,由此也对三层架构模式有了初步体验。

一.ASP.NET三层架构介绍

设计模式中的分层架构(可以参考一下J2EE中MVC模式)实现了各司其职,互不干涉,所以如果一旦哪一层的需求发生了变化,就只需要更改相应的层中的代码而不会影响到其它层中的代码。这样就能更好的实现开发中的分工,有利于组件的重用。所以这些年关于模式的研究有很多成果,应用也很广泛。一个好的模式在程序开发和后期维护中作用重大。

ASP.NET三层架构自底向上分为:数据访问层(DAL),业务逻辑层(BLL)和表示层(PL)。




数据访问层(DAL):使用了一个强类型的DataSet作为数据访问层,只是单纯的对数据进行增,删,改,查询和判断存在等等较通用的数据访问方法(由SQL语句来提供),不应该有“事务”存在。

业务逻辑层(BLL):业务逻辑层是在数据访问层和表示层之间进行数据交换的桥梁,按业务需求调用数据访问层中的方法组合,集合了各种业务规则到一个BLL中,例如通过条件进行判断的数据操作或“事务”处理。BLL都是以类库(Class Library)的形式来实现的。

表示层(PL):表示层是为客户提供用于交互的应用服务图形界面,帮助用户理解和高效地定位应用服务,呈现业务逻辑层中传递的数据,用ASP.NET页面来实现。

 

 二.三层架构应用实现

随着ASP.NET 的不断升级,可以很方便的使用ASP.NET 来构建B/S 三层架构的应用程序,下面以“教师业务信息管理系统”项目中的部分例子来演示如何使用ASP.NET 2.0 和SQL Server 2005数据库来构建一个三层架构的应用程序。

1.创建数据库

打开SQL Server 2005,新建一个数据库“TeacherDb”,建立如下所示结构的两个表“PersonInfo”和“JobInfo”。两表以PersonIDNumber作为关联字段,存储18位身份证号码。

 

 

 2.创建数据访问层

在开始创建数据访问层(DAL)之前,首先需要创建一个网站,配置好数据库链接。

第一步:创建一个Web项目,配置数据库连接

打开Visual Studio 2005(以下简称VS2005)集成开发环境, 首先创建一个C#语言的ASP.NET网站,并将其命名为WebSite,设置位置(Location)列表的选项为文件系统( File System),然后选这一个放置这个网站的文件夹,然后选择编程语言为C#。Visual Studio会为你生成一个新的网站,同时生成一个名为Default.aspx的网页,和一个App_Data文件夹。

 

 

 第二步:创建数据访问层,配置数据库连接

接下来创建数据访问层,添加一个强类型的DataSet。在解决方案管理器里的项目节点上按右鼠标,选择“添加新项”,在模板列单里选择“数据集”,将其命名为DataSet1.xsd。接下来会出现“TableAdpater”配置向导的窗口,选择数据库服务器,设置好各项参数,并按照提示逐步完成。需要注意:

1.指定连接的数据库字符串,并选择将连接字符串保存到web.config文件中去。

2.命令类型选择“使用SQL语句”,通过“高级选项”选择“生成Insert、Update和Delete语句”,通过“查询生成器”生成要装载数据的“Select语句”。并为方法命名。

 

 

 


SELECT ID, UserID, TrueName, PersonIDNumber, Sex, BirthDate, Nation, NativePlace,

Polity, JoinPolityTime, PersonImageUrl, Telephone, MobiePhone, Email

FROM EM_P_PersonInfo

针对项目需求对数据库中各表查询操作分别建立各种方法,完成后的可能如下图。

 

 

跟底层数据源相关的所有编码,比如建立到数据库的连接,发出SELECT,INSERT ,UPDATE和DELETE命令等的编码,都应该放置在DAL中。表现层不应该包含对这些数据访问编码的任何引用,而应该调用DAL中的编码处理所有的数据访问请求。数据访问层包含访问底层数据库数据的方法。至此,清晰构建出数据访问层,之后可在“业务逻辑层”和“表示层”通过调用自动生成的TableAdpater及相关类来操作数据。由于“数据集”是强类型,对于数据库中的NULL数据需要使用方法来判断,这些内容在后续内容中再详细描述。

 


3.创建业务逻辑层

数据访问层(DAL)将数据访问的细节从表示层中分离出来了,可它却不能处理任何的业务规则。比如判断数据的有效性。这些工作将由业务逻辑层(简称BLL)来承担,在以下应用程序中,将BLL实现为App_Code文件夹中的一系列的类。每一个BLL类都对应DAL中的一个TableAdapter,它们都从各自的TableAdapter中得到读取、插入、修改以及删除等方法以应用合适的业务规则。

第一步:创建BLL类
在App_Code文件夹中创建2个类文件。在解决方案浏览器(Solution Explorer)中右键点击App_Code文件夹,并选择新建项目(New Item),然后在弹出的对话框中选择“类”模板(Class template)就可以创建新的类文件了。将这2个文件分别命名为UserBLL以及JobBLL。

 


第二步:通过BLL类访问类型化数据集

为UserBLL和JobBLL类分别添加如下方法:

(1) UserBLL.css

l updateUser(string UserName, String PersonIDNumber, int SchoolID, string Password, string Sex, string TrueName, bool InPosition)

l updateUser(String PersonIDNumber, string TrueName, string BirthDate, string Nation, string NativePlace, string Polity, string JoinPolityTime, string Telephone, string MobiePhone, string Email)

l getPersons(int SchoolID,string TrueName)

l getPersonByPID(string PersonIDNumber)

l deleteUser(string UserName, String PersonIDNumber, int? SchoolID)

l addUser(string UserName, String PersonIDNumber, int SchoolID, string Password, string Sex, string TrueName, bool InPosition)

(2)JobBLL.css

l getPersonJob(string PersonIDNumber)

l updateUser(String PersonIDNumber, string Post1, string Post2, string JoinTime, int? CountryWorkedTime, string MasteSubject, string SecondSubject, string SchoolPhase, int? MotherClassTime)

以下为JobBLL.css的代码(UserBLL.css的代码太长,不列出)

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using TeacherTableAdapters;

///


/// JobBLL 的摘要说明
///


[System.ComponentModel.DataObject]
public class JobBLL
{
private JobInfoTableAdapter _JobAdapter = null;

public JobBLL()
{
//
// TODO: 在此处添加构造函数逻辑
//
}

protected JobInfoTableAdapter Adapter
{
get
{
if (_JobAdapter == null)
_JobAdapter = new JobInfoTableAdapter();

return _JobAdapter;
}
}

 


//select
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]
public Teacher.JobInfoDataTable getPersonJob(string PersonIDNumber)
{
return Adapter.GetPersonJobByPID(PersonIDNumber);
}

//update
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, false)]
public bool updateUser(String PersonIDNumber, string Post1, string Post2, string JoinTime, int? CountryWorkedTime, string MasteSubject, string SecondSubject, string SchoolPhase, int? MotherClassTime)
{
if (string.IsNullOrEmpty(PersonIDNumber))
{
return false;
}

try
{

Teacher.JobInfoDataTable PersonJob = Adapter.GetPersonJobByPID(PersonIDNumber);
Teacher.JobInfoRow PersonJobPID;

if (PersonJob.Count == 1)
{
PersonJobPID = PersonJob[0];
}
else
{
return false;
}

if (!string.IsNullOrEmpty(Post1))
{
PersonJobPID.Post1 = Post1;
}
else
{
PersonJobPID.SetPost1Null();
}
if (!string.IsNullOrEmpty(Post2))
{
PersonJobPID.Post2 = Post2;
}
else
{
PersonJobPID.SetPost2Null();
}
if (!string.IsNullOrEmpty(MasteSubject))
{
PersonJobPID.MasteSubject = MasteSubject;
}
else
{
PersonJobPID.SetMasteSubjectNull();
}
if (!string.IsNullOrEmpty(SecondSubject))
{
PersonJobPID.SecondSubject = SecondSubject;
}
else
{
PersonJobPID.SetSecondSubjectNull();
}
if (!string.IsNullOrEmpty(SchoolPhase))
{
PersonJobPID.SchoolPhase = SchoolPhase;
}
else
{
PersonJobPID.SetSchoolPhaseNull();
}

if (!(CountryWorkedTime == null))
{
PersonJobPID.CountryWorkedTime = CountryWorkedTime.Value;
}
else
{
PersonJobPID.SetCountryWorkedTimeNull();
}
if (!(MotherClassTime == null))
{
PersonJobPID.MotherClassTime = MotherClassTime.Value;
}
else
{
PersonJobPID.SetMotherClassTimeNull();
}
if (!string.IsNullOrEmpty(JoinTime))
{
PersonJobPID.JoinTime = DateTime.Parse(JoinTime);
}
else
{
PersonJobPID.SetJoinTimeNull();
}

int rowAffect1 = Adapter.Update(PersonJobPID);
return (rowAffect1 == 1);
}
catch (System.Configuration.Provider.ProviderException e)
{
return false;
}
}
}

说明:

(1)using TeacherTableAdapters; 引用DAL层命名空间,自动生成,必须。否则无法使用类。

(2)JobInfoTableAdapter类,对应DAL中的TableAdapter适配器JobInfo,通过这个类来调用增、删及改等数据操作。

(3)使用JobInfoDataTable PersonJob来装载查询返回的数据,是DataSet中的强类型数据表,结构和数据类型由数据库定义。使用JobInfoRow PersonJobPID来载入表中的某一行。行字段访问用如下形式:Row变量.字段名(如PersonJobPID.Post1)。

Teacher.JobInfoDataTable PersonJob = Adapter.GetPersonJobByPID(PersonIDNumber);

Teacher.JobInfoRow PersonJobPID = PersonJob[0];

(4)数据库中某些表字段在设计时可能被允许空值(null),强类型DataTable中对字段的判空与赋空值不能采用以下形式:

l !string.IsNullOrEmpty(PersonJobPID.Post1)

l PersonJobPID.Post1 == null;

l PersonJobPID.Post1 = null;

正确的做法是采用行类型变量(Teacher.JobInfoRow PersonJobPID)为每个字段生成的“空值方法”操作:

l void PersonJobPID.SetPost1Null();

l bool PersonJobPID.IsPost1Null()

(5)JobInfoDataTable或JobInfoRow中数据存储在内存中,修改后的数据要反映到数据库中采用适配器方法Update().

int rowAffect1 = Adapter.Update(PersonJobPID);

至此业务逻辑层构建完成。

 

 4.表示层-使用ObjectDataSource展现数据

在完成应用程序架构后,我们可以实现多种报表展现。ASP.NET 2.0的数据源控件提供了一种新的方式,使用这些控件可以轻松的从创建的业务逻辑层中进行数据绑定,甚至不需要手写一行的代码。

ASP.NET 2.0提供了五种内置的数据源控件:SqlDataSource、AccessDataSource,、ObjectDataSource、XmlDataSource、和SiteMapDataSource。基于已有的业务逻辑类我们将使用ObjectDataSource。

ObjectDataSource充当别的对象的代理。通过配置ObjectDataSource,我们指定这些底层的对象,还有这些对象的方法如何映射到ObjectDataSource的Select、Insert、Update和Delete方法。一旦底层的对象被指定并且其方法映射到ObjectDataSource的方法后,我们就可以把ObjectDataSource绑定到页面上的Data Web服务器控件。ASP.NET提供了许多Data Web 服务器控件,包括GridView、DetailsView、RadioButtonList和DropDownList等等。在页面的生命周期中,Data Web 服务器控件可能需要访问它所绑定的数据,这将通过调用ObjectDataSource的Select方法来实现;如果这个Data Web 服务器控件还支持插入、更新或者删除,那么将调用ObjectDataSource的Insert、Update或者Delete方法。这些调用会通过ObjectDataSource被发送到适当的底层对象的方法。


第一步:添加和配置ObjectDataSource控件

(1)新建一个“Web窗体”模板文件(UserView.aspx),语言Visual C#,选择“将代码发在单独文件中”。

(2)拖入一个“GirdView”控件,点击智能标记中的“配置数据源”,选择“新建数据源…”,进入数据源配置向导来添加一个ObjectDataSource。

(3)进入数据源配置向导。首先给ObjectDataSource指定一个业务对象。如果勾选上“只显示数据组件”,那么下拉框中就仅仅显示出那些以[DataObject]特征修饰过的对象。可以不勾选“只显示数据组件”从而看见所有对象。从下拉列表中选择业务对象UserBLL 。

 

 

 

 根据页面设计的需要为SELECT,UPDATE,INSERT及DELETE操作指定相应的业务对象的方法。这些方法已经在业务逻辑层中定义。如果用GridView及DetailsView服务器控件呈现数据,SELECT操作是必须的。

 

 

 


第二步:配置GridView

从GridView的智能标记点选“编辑列”,为“选定的字段”指定标题名,格式,删除不需要的列,添加命令字段(Command Field)等。操作比较繁琐,看参考相关资料。完成后的样子类似下图:

 

 

 根据设计需求将页面设计完成。至此,表示层的搭建过程简单演示一下。

三.总结

用了几天时间将前段时间的学习和项目开发中的框架构建简单做了个总结,这不是一个教程类的文章,许多细节性的东西不可能面面俱到。程序开发是一件比较辛苦的事,过程可能很枯燥,不过对此感兴趣的人会在不断学习中体会到其中的乐趣。

你可能感兴趣的:(.net)