1、Winform數據訪問模式定義
傳統的Winform程序模塊:用於傳統的數據庫通訊獲取數據,這種方式獲取數據,方便快捷,可以用於常規的業務系統的場景,用於單機版軟件或者基於局域網內的業務系統軟件。
WCF的Winform程序模塊:采用了WCF技術的分布式開發模式,系統能夠通過遠程的WCF服務獲取數據,而不用直接和數據庫相連,提高數據的安全性和可維護性,適用於互聯網、局域網環境下的業務系統的搭建,是一種穩定、安全的框架應用。
混合式Winform程序模塊:是指混合了傳統數據訪問和WCF數據訪問的特點,可以在兩者之間自由切換,統一了系統界面層對業務服務的調用模式,所有組件模塊均實現兩種方式的調用,是一種彈性化非常好的框架應用,既可用於單機版軟件或者基於局域網內的應用軟件,也可以用於分布式技術的互聯網環境應用。
每種技術都有其存在的合理性,對於混合式的Winform程序而言,也是一樣。在數據越發集中的今天,單機版的數據很難進行共享,只在一定范圍內進行使用;混合式的Winform程序,結合了Winform程序豐富的體驗和強大的功能外,還整合了B/S的這種分布式特點,因此這種模式的存在生命力很強,有一些程序的操作使用Winform方式能夠給客戶提供非常好的界面效果體驗。
2、混合式框架的原理
混合式框架,結合了普通Winform方式和WCF訪問數據的分布式框架,因此他們是基於一個跳轉開關進行指定,如下示意圖所示。
為了適應模塊化的特點,所有使用混合式框架的業務模塊,除了一個啟動的主程序模塊外,其他的都是一個個獨立的模塊,這樣方便我們業務橫向的划分,可以使大家按照統一模式進行開發,然后再進行統一集成,這種模式可以有效提高開發效率,並且能夠使得模塊能夠反復使用,組合出更多更強的業務系統模塊。
下面是一個字典模塊的內部設計圖,我們可以看到,整個混合式的架構,分為了UI層、接口調用層、Facade接口層、Winform調用層、WCF服務調用層、業務層、實體層、以及數據庫層等;其中的業務層還可以細化為BLL業務邏輯層、數據接口層、數據訪問層、實體層等,整個模塊通過實體層進行數據的傳輸載體。
3、混合式模塊的項目結構
混合型框架把業務系統的WCF服務和輔助性公用模塊的WCF服務分開,首先是服務分開,然后是客戶端配置文件分開。
下面是一個實際業務系統的WCF服務的截圖,可以看出里面的主業務服務和基礎服務模塊的服務層是分開的,這樣方便管理,不至於太多太亂。
WCF服務的客戶端配置文件是分開管理的,基礎服務和業務服務的配置信息分別用不同的文件表示,如基礎模塊服務的WCF配置文件為BaseWcfConfig.config,業務系統的WCF配置文件為WcfConfig.config,通過這樣的分離設置,我們在主配置文件app.Config文件里面,就清爽很多了。
<!--WCF服務的配置文件地址--> <add key="BaseWcfConfig" value="BaseWcfConfig.config"/> <add key="WcfConfig" value="WcfConfig.config"/>
4、開發使用混合式Winform模塊
例如,我們在業務邏輯層里面增加一個方法,根據客戶名稱獲取客戶列表,如下所示。
namespace WHC.TestProject.BLL { /// <summary> /// 客戶信息 /// </summary> public class Customer : BaseBLL<CustomerInfo> { public Customer() : base() { base.Init(this.GetType().FullName, System.Reflection.Assembly.GetExecutingAssembly().GetName().Name); } /// <summary> /// 根據客戶名稱獲取客戶列表 /// </summary> /// <param name="name">客戶名稱</param> /// <returns></returns> public List<CustomerInfo> FindByName(string name) { string condition = string.Format("Name like '%{0}%'", name); return baseDal.Find(condition); } } }
圖上紅色部分的函數是我們新增的內容,完成這個函數,我們來看看完成整個混合式框架,需要增加哪些東西。
1)添加Facade接口
為了統一的接口調用需要,需要先定義Facade層的接口,這是一切的開始。
namespace WHC.TestProject.Facade { [ServiceContract] public interface ICustomerService : IBaseService<CustomerInfo> { /// <summary> /// 根據客戶名稱獲取客戶列表 /// </summary> /// <param name="name">客戶名稱</param> /// <returns></returns> [ServiceContract] List<CustomerInfo> FindByName(string name); } }
2)增加Winform接口調用層實現
基於Winform的實現,就是根據接口封裝對業務邏輯層BLL的調用,BaseLocalService基類,可以看成是具有常規增刪改查等等的基礎性API,是基於泛型的強類型接口基類。
namespace WHC.TestProject.WinformCaller { /// <summary> /// 基於傳統Winform方式,直接訪問本地數據庫的Facade接口實現類 /// </summary> public class CustomerCaller : BaseLocalService<CustomerInfo>, ICustomerService { private Customer bll = null; public CustomerCaller() : base(BLLFactory<Customer>.Instance) { bll = baseBLL as Customer; } /// <summary> /// 根據客戶名稱獲取客戶列表 /// </summary> /// <param name="name">客戶名稱</param> /// <returns></returns> public List<CustomerInfo> FindByName(string name) { return bll.FindByName(name); } } }
3)增加WCF的接口調用層實現
基於WCF的實現,就是根據接口封裝對WCF服務層的調用,BaseWCFService基類,可以看成是具有常規增刪改查等等的基礎性API,是基於泛型的強類型接口基類。
namespace WHC.TestProject.ServiceCaller { /// <summary> /// 基於WCF服務的Facade接口實現類 /// </summary> public class CustomerCaller : BaseWCFService<CustomerInfo>, ICustomerService { public CustomerCaller() : base() { this.configurationPath = EndPointConfig.WcfConfig; //WCF配置文件 this.endpointConfigurationName = EndPointConfig.CustomerService; } /// <summary> /// 子類構造一個IChannel對象轉換為基類接口,方便給基類進行調用通用的API /// </summary> /// <returns></returns> protected override IBaseService<CustomerInfo> CreateClient() { return CreateSubClient(); } /// <summary> /// 創建一個強類型接口對象,供本地調用 /// </summary> /// <returns></returns> private ICustomerService CreateSubClient() { CustomClientChannel<ICustomerService> factory = new CustomClientChannel<ICustomerService>(endpointConfigurationName, configurationPath); return factory.CreateChannel(); } /// <summary> /// 根據客戶名稱獲取客戶列表 /// </summary> /// <param name="name">客戶名稱</param> /// <returns></returns> public List<CustomerInfo> FindByName(string name) { List<CustomerInfo> result = new List<CustomerInfo>(); ICustomerService service = CreateSubClient(); ICommunicationObject comm = service as ICommunicationObject; comm.Using(client => { result = service.FindByName(name); }); return result; } } }
由於WCF的接口封裝層相對內容比較復雜一些,這里介紹一下。
構造函數通過代碼指定具體的配置文件:this.configurationPath = EndPointConfig.WcfConfig; //WCF配置文件
並通過代碼指定具體的WCFEndPoint節點名稱:this.endpointConfigurationName = EndPointConfig.CustomerService;
構造WCF服務的代理類,我們通過CustomClientChannel的輔助方法,傳入配置文件和配置節點名稱,使得它能順利通過函數 CreateSubClient 構造出一個對應類型的WCF代理類。
CustomClientChannel<ICustomerService> factory = new CustomClientChannel<ICustomerService>(endpointConfigurationName, configurationPath); return factory.CreateChannel();
每次調用WCF服務類接口的時候,我們就使用創建的代理類進行調用,調用操作如下所示。
ICustomerService service = CreateSubClient(); ICommunicationObject comm = service as ICommunicationObject; comm.Using(client => { result = service.FindByName(name); });
4)增加WCF服務邏輯層的實現
我們通過上面的代碼可以了解到,已經創建了Winform的調用層、WCF服務的調用層,但是這里,我們對WCF服務還沒有實現,這樣我們就需要實現WCF服務層的內容了,否則程序試用WCF方式訪問的時候,就找不到這個FindByName的接口實現了。
我們看看WCF服務層里面,看看具體如何實現,雙擊打開里面的CustomerService.Svc看到只是一個服務的聲明,沒有任何背后的代碼邏輯。
因為為了便於管理,WCF服務一般是定義和具體的實現是分開的,這樣就引入了一個WCF服務邏輯層的概念。
這樣它的接口實現,就放在了WHC.TestProject.WCFLibrary項目里面了,WCF服務邏輯層的接口調用封裝如下所示。這里我們看到,他和Winform的調用邏輯幾乎一樣,只是他們的類名稱不同而已。
namespace WHC.TestProject.WCFLibrary { /// <summary> /// 基於WCFLibrary的Customer對象調用類 /// </summary> public class CustomerService : BaseLocalService<CustomerInfo>, ICustomerService { private Customer bll = null; public CustomerService() : base(BLLFactory<Customer>.Instance) { bll = baseBLL as Customer; } /// <summary> /// 根據客戶名稱獲取客戶列表 /// </summary> /// <param name="name">客戶名稱</param> /// <returns></returns> public List<CustomerInfo> FindByName(string name) { return bll.FindByName(name); } } }
5)界面層的調用操作
界面層的調用操作代碼如下所示。
string name = "張" List<CustomerInfo> list= CallerFactory<ICustomerService>.Instance.FindByName(name)
這個操作模式,和普通使用BLLFactory的方式非常相似的。
5、混合式框架的業務模塊組成
混合型框架可以看成是Winform框架高級版本,除了它本身是一個完整的業務系統外,它外圍的所有輔助性模塊均(如通用權限、通用字典、通用附件管理、通用人員管理。。。。)都實現了這種混合型的框架,因此使用非常方便,整個框架如果簡化來看,就是在原有的Winform界面層,用接口調用方式,避免和業務邏輯類的緊耦合關系。由於他是通過接口方式的調用方式,它本身又可以通過配置指定指向WCF的實現,因此也囊括了WCF框架的一切特點。
雖然整體性的混合型框架比其他兩種框架模塊,總體增加了一些難度及復雜性,不過,為了使得整個混合型框架開發和使用更加方便,我已經在設計上做了很多相關的工作,力求更好、更高效的使用好這種混合型框架,下面是我對整體性的框架做了的優化改進工作。
1)把所有通用的模塊開發好,方便更好的集成使用,更加高效利用通用模塊,重復利用度更高;
2)把WCF服務發布和服務邏輯分開,更好管理和發布WCF服務,服務發布只需要svc文件,不含任何后台代碼;
3)統一的業務調用規則和命名規則,所有模塊的接口調用統一為CallerFactory<I***Service>方式,通用模塊和框架的命名規則和機制完全一樣。
4)WCF服務配置文件分離,通用性的輔助模塊的配置文件為BaseWcfConfig.config,業務系統的WCF配置文件為WcfConfig.config,配置文件分離更方便管理和維護,減少主配置文件app.Config的復雜性。
5)最后一條,也是最重要的一條,就是代碼生成工具Database2Sharp的同步支持。通過代碼生成工具,更好、更快的生成整個混合性框架的代碼和項目工程,一鍵解決所有的煩惱。Winform界面,利用代碼生成工具Database2Sharp進行生成,然后在項目中整合即可。
循序漸進開發WInform項目--系列文章導引:
《循序漸進開發WinForm項目(5)--Excel數據的導入導出操作》
《循序漸進開發WinForm項目(4)--Winform界面模塊的集成使用》
《循序漸進開發WinForm項目(3)--Winform界面層的項目設計》
《循序漸進開發WinForm項目(1) --數據庫設計和項目框架的生成》