分爲如下幾層
Web
BLL
IDAL
Model
DALFactory
NHDAL
根據PetShop3.0的框架:Web層只依賴於BLL和Model,也就是說web層調用BLL層方法返回的Model層定義的數據;BLL層依賴於IDAL,Model,這一層實際是使用IDAL中的方法組合爲業務,並處理IDAL層返回的Model;IDAL定義了所有底層方法,給DAL層留下接口;Model定義了對象實體,只有屬性沒有方法,基本上可以作爲抽象類定義。DALFactory的作用是根據配置文件中的設置動態取出取出數據訪問層(Data Access Layer)對象的實例,這樣做就把實際使用的DAL跟BLL層分離,如果需要切換到其他DAL,只要修改此層就可以了。
本項目使用NH(NHibernate)作爲DAl,所以命名爲NHDAL。NHDAL依賴於Model,繼承Model中屬性的定義,並添加了NH需要用到的屬性器。同時NHDAL實現IDAL中定義的方法。
下面是對登陸驗證和儲存日誌的實例
先看看IDAL和Model中的定義吧
代碼段一 IDAL接口定義
using System;
![]()
namespace CManager.IDAL.Log
![]()
![]()
{
![]()
/**//// <summary>
/// ILoginLog 的摘要說明。
/// </summary>
public interface ISignLog
![]()
{
void LogSignIn( string userid, string sessionid, string clientip, DateTime logindate );
![]()
bool CheckPassword( string userid, string password);
}
}
![]()
代碼段二 Model對象定義
using System;
![]()
namespace CManager.Model.Log
![]()
![]()
{
![]()
/**//// <summary>
/// LoginInfo 的摘要說明。
/// </summary>
public class SignLogInfo
![]()
{
public int SignLogID
![]()
{
![]()
get
{return _SignLogID;}
}
public string UserID
![]()
{
![]()
get
{return _UserID;}
}
public string SessionID
![]()
{
![]()
get
{return _SessionID;}
}
public string ClientIP
![]()
{
![]()
get
{return _ClientIP;}
}
public DateTime SignInDate
![]()
{
![]()
get
{return _SignInDate;}
}
public DateTime SignOutDate
![]()
{
![]()
get
{return _SignOutDate;}
}
![]()
protected int _SignLogID;
protected string _UserID;
protected string _SessionID;
protected string _ClientIP;
protected DateTime _SignInDate;
protected DateTime _SignOutDate;
}
}
![]()
然後是BLL中調用。因爲BLL不依賴於任何DAL,所以通過中間層DALFactory創建DAL的實例,並通過IDAl定義的接口返回給BLL。
代碼段三 BLL方法
using System;
using System.Collections;
using System.Web;
![]()
using CManager.Model.Log;
using CManager.Model.Collections;
using CManager.DALFactory.Log;
using CManager.IDAL.Log;
![]()
![]()
namespace CManager.BLL.Log
![]()
![]()
{
public class Log
![]()
{
![]()
//未完成,應該返回Module.Log.Account
public static bool Login ( string userid, string password, HttpContext context )
![]()
{
ISignLog log = LogFactory.CreateSignLog();
if (log.CheckPassword(userid,password))
![]()
{
log.LogSignIn( userid ,context.Session.SessionID, context.Request.UserHostAddress, DateTime.Now );
return true;
}
else
![]()
{
return false;
}
}
}
}
![]()
代碼段四 DALFactory方法
using System;
using CManager.IDAL.Log;
using System.Reflection;
![]()
namespace CManager.DALFactory.Log
![]()
![]()
{
public class LogFactory
![]()
{
public static ISignLog CreateSignLog()
![]()
{
//獲取web.config裏DAL的設置
string path = System.Configuration.ConfigurationSettings.AppSettings["WebDAL"];
//組合出類名
string className = path + ".Log.SignLog";
//運行時創建類實例,需要類實現實例化
return (ISignLog) Assembly.Load(path).CreateInstance(className);
}
}
}
代碼段五 web.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- 這段大家都熟悉了 -->
<configSections>
<section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</configSections>
<nhibernate>
<add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
<add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
<add key="hibernate.connection.connection_string" value="server=127.0.0.1;database=CManager;uid=sa;pwd=;" />
<add key="hibernate.connection.isolation" value="ReadCommitted"/>
<add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" />
</nhibernate>
<appSettings>
<!-- 默認顯示每頁顯示記錄數 -->
<add key="DefaultRecordCount" value="20" />
<!-- *數據庫層所在命名空間* 實際使用的DAL在這裏設置 -->
<add key="WebDAL" value="CManager.NHDAL" />
</appSettings>
<system.web>
<!-- 這段按下,不佔頁面了 -->
</system.web>
![]()
</configuration>
![]()
理論上Web層並不知道IDAL層定義的原子方法,只使用BLL層給出的方法。這就是所謂的業務層與表現層分開。Web層只接受用戶發出的請求,然後處理參數交給BLL層,並對BLL層返回的結果進行判斷返回給結果。
代碼段六 Web層調用
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
![]()
using CManager.BLL.Log;
using CManager.Model.Log;
![]()
namespace BTTech.CManager.Web
![]()
![]()
{
![]()
/**//// <summary>
/// Login 的摘要說明。
/// </summary>
public class Login : PageBase
![]()
{
protected System.Web.UI.WebControls.TextBox UserName;
protected System.Web.UI.WebControls.TextBox Password;
protected System.Web.UI.HtmlControls.HtmlInputImage ImageButton1;
private void Page_Load(object sender, System.EventArgs e)
![]()
{
}
![]()
private void ImageButton1_ServerClick(object sender, System.Web.UI.ImageClickEventArgs e)
![]()
{
if (Log.Login( UserName.Text, Password.Text, this.Context))
Response.Redirect("",true);
else
Alert("用戶名或密碼錯誤");
}
}
}
![]()
最後是本文的主角NHDAL了,雖然最後出現,卻是所有實際操作的最終執行者。
代碼段七 實現IDAL
using System;
using NHibernate.Cfg;
using NHibernate;
![]()
namespace CManager.NHDAL.Log
![]()
![]()
{
![]()
/**//// <summary>
/// SignLog 的摘要說明。
/// </summary>
public class SignLog : NHObject,CManager.IDAL.Log.ISignLog
![]()
{
public SignLog()
![]()
{
}
![]()
public void LogSignIn(string userid, string sessionid, string clientip, DateTime logindate)
![]()
{
ISession session = CreateSession();
session.Save(new SignLogInfo(userid, sessionid, clientip, logindate));
}
![]()
public bool CheckPassword( string userid, string password)
![]()
{//未完成
return true;
}
}
}
![]()
代碼段八 繼承Model
using System;
using CManager.Model;
![]()
namespace CManager.NHDAL.Log
![]()
![]()
{
![]()
/**//// <summary>
/// SignLog 的摘要說明。
/// </summary>
public class SignLogInfo : CManager.Model.Log.SignLogInfo
![]()
{
private int Id
![]()
{
![]()
get
{return this._SignLogID;}
![]()
set
{this._SignLogID = value;}
}
private string NH_UserID
![]()
{
![]()
get
{return _UserID;}
![]()
set
{_UserID = value;}
}
private string NH_SessionID
![]()
{
![]()
get
{return _SessionID;}
![]()
set
{_SessionID = value;}
}
private string NH_ClientIP
![]()
{
![]()
get
{return _ClientIP;}
![]()
set
{_ClientIP = value;}
}
private DateTime NH_SignInDate
![]()
{
![]()
get
{return _SignInDate;}
![]()
set
{_SignInDate = value;}
}
private DateTime NH_SignOutDate
![]()
{
![]()
get
{return _SignOutDate;}
![]()
set
{_SignOutDate = value;}
}
![]()
private SignLogInfo()
![]()
{
![]()
}
![]()
internal SignLogInfo(string userid, string sessionid, string clientip, DateTime signdate )
![]()
{
this._UserID = userid;
this._SessionID = sessionid;
this._ClientIP = clientip;
this._SignInDate = signdate;
this._SignOutDate = signdate;
}
}
}
![]()
代碼段九 影射文件 SignLogInfo.hbm.xml 這裏用到上篇文章《不讓NH屬性器破壞封裝》提到的方法
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="CManager.NHDAL.Log.SignLogInfo, CManager.NHDAL" table="CM_SignLog">
<id name="Id" type="Int32" unsaved-value="0">
<column name="SignLogID" sql-type="int" not-null="true" unique="true" index="PK__CM_SignLog__79A81403"/>
<generator class="native" />
</id>
<property name="NH_UserID" type="String">
<column name="UserID" length="50" sql-type="nvarchar" not-null="true"/>
</property>
<property name="NH_SessionID" type="String">
<column name="SessionID" length="24" sql-type="nvarchar" not-null="true"/>
</property>
<property name="NH_ClientIP" type="String">
<column name="ClientIP" length="20" sql-type="nvarchar" not-null="true"/>
</property>
<property name="NH_SignInDate" type="DateTime">
<column name="SignInDate" sql-type="datetime" not-null="true"/>
</property>
<property name="NH_SignOutDate" type="DateTime">
<column name="SignOutDate" sql-type="datetime" not-null="false"/>
</property>
</class>
</hibernate-mapping>
代碼段十 小技巧,NHObject基類
定義了一個NHObject的基類,因爲任何實際操作對象is a NHObject,所以均繼承這個類
這樣做的好處是當我們需要更改加載連接字符串方法(比如解密)的時候只需在此出修改,還可以比較大面積地更改NH的使用方法。
using System;
using NHibernate;
using NHibernate.Cfg;
![]()
namespace CManager.NHDAL
![]()
![]()
{
![]()
/**//// <summary>
/// NHConfigBase 的摘要說明。
/// </summary>
public class NHObject
![]()
{
private static Configuration config = new Configuration().AddAssembly(System.Reflection.Assembly.Load("CManager.NHDAL"));
private static ISessionFactory sessionFactory = config.BuildSessionFactory();
protected static NHibernate.ISession CreateSession()
![]()
{
return sessionFactory.OpenSession();
}
}
}
![]()
這樣一個完整的框架就成功地搭建並運行了。:)