1、Winform數(shù)據(jù)訪問模式定義
傳統(tǒng)的Winform程序模塊:用于傳統(tǒng)的數(shù)據(jù)庫通訊獲取數(shù)據(jù),這種方式獲取數(shù)據(jù),方便快捷,可以用于常規(guī)的業(yè)務系統(tǒng)的場景,用于單機版軟件或者基于局域網(wǎng)內(nèi)的業(yè)務系統(tǒng)軟件。
WCF的Winform程序模塊:采用了WCF技術(shù)的分布式開發(fā)模式,系統(tǒng)能夠通過遠程的WCF服務獲取數(shù)據(jù),而不用直接和數(shù)據(jù)庫相連,提高數(shù)據(jù)的安全性和可維護性,適用于互聯(lián)網(wǎng)、局域網(wǎng)環(huán)境下的業(yè)務系統(tǒng)的搭建,是一種穩(wěn)定、安全的框架應用。
混合式Winform程序模塊:是指混合了傳統(tǒng)數(shù)據(jù)訪問和WCF數(shù)據(jù)訪問的特點,可以在兩者之間自由切換,統(tǒng)一了系統(tǒng)界面層對業(yè)務服務的調(diào)用模式,所有組件模塊均實現(xiàn)兩種方式的調(diào)用,是一種彈性化非常好的框架應用,既可用于單機版軟件或者基于局域網(wǎng)內(nèi)的應用軟件,也可以用于分布式技術(shù)的互聯(lián)網(wǎng)環(huán)境應用。
每種技術(shù)都有其存在的合理性,對于混合式的Winform程序而言,也是一樣。在數(shù)據(jù)越發(fā)集中的今天,單機版的數(shù)據(jù)很難進行共享,只在一定范圍內(nèi)進行使用;混合式的Winform程序,結(jié)合了Winform程序豐富的體驗和強大的功能外,還整合了B/S的這種分布式特點,因此這種模式的存在生命力很強,有一些程序的操作使用Winform方式能夠給客戶提供非常好的界面效果體驗。
2、混合式框架的原理
混合式框架,結(jié)合了普通Winform方式和WCF訪問數(shù)據(jù)的分布式框架,因此他們是基于一個跳轉(zhuǎn)開關(guān)進行指定,如下示意圖所示。

為了適應模塊化的特點,所有使用混合式框架的業(yè)務模塊,除了一個啟動的主程序模塊外,其他的都是一個個獨立的模塊,這樣方便我們業(yè)務橫向的劃分,可以使大家按照統(tǒng)一模式進行開發(fā),然后再進行統(tǒng)一集成,這種模式可以有效提高開發(fā)效率,并且能夠使得模塊能夠反復使用,組合出更多更強的業(yè)務系統(tǒng)模塊。
下面是一個字典模塊的內(nèi)部設計圖,我們可以看到,整個混合式的架構(gòu),分為了UI層、接口調(diào)用層、Facade接口層、Winform調(diào)用層、WCF服務調(diào)用層、業(yè)務層、實體層、以及數(shù)據(jù)庫層等;其中的業(yè)務層還可以細化為BLL業(yè)務邏輯層、數(shù)據(jù)接口層、數(shù)據(jù)訪問層、實體層等,整個模塊通過實體層進行數(shù)據(jù)的傳輸載體。

3、混合式模塊的項目結(jié)構(gòu)

混合型框架把業(yè)務系統(tǒng)的WCF服務和輔助性公用模塊的WCF服務分開,首先是服務分開,然后是客戶端配置文件分開。
下面是一個實際業(yè)務系統(tǒng)的WCF服務的截圖,可以看出里面的主業(yè)務服務和基礎(chǔ)服務模塊的服務層是分開的,這樣方便管理,不至于太多太亂。

WCF服務的客戶端配置文件是分開管理的,基礎(chǔ)服務和業(yè)務服務的配置信息分別用不同的文件表示,如基礎(chǔ)模塊服務的WCF配置文件為BaseWcfConfig.config,業(yè)務系統(tǒng)的WCF配置文件為WcfConfig.config,通過這樣的分離設置,我們在主配置文件app.Config文件里面,就清爽很多了。
<!--WCF服務的配置文件地址-->
<add key="BaseWcfConfig" value="BaseWcfConfig.config"/>
<add key="WcfConfig" value="WcfConfig.config"/>
4、開發(fā)使用混合式Winform模塊
例如,我們在業(yè)務邏輯層里面增加一個方法,根據(jù)客戶名稱獲取客戶列表,如下所示。
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>
/// 根據(jù)客戶名稱獲取客戶列表
/// </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);
}
}
}
圖上紅色部分的函數(shù)是我們新增的內(nèi)容,完成這個函數(shù),我們來看看完成整個混合式框架,需要增加哪些東西。
1)添加Facade接口
為了統(tǒng)一的接口調(diào)用需要,需要先定義Facade層的接口,這是一切的開始。
namespace WHC.TestProject.Facade
{
[ServiceContract]
public interface ICustomerService : IBaseService<CustomerInfo>
{
/// <summary>
/// 根據(jù)客戶名稱獲取客戶列表
/// </summary>
/// <param name="name">客戶名稱</param>
/// <returns></returns>
[ServiceContract]
List<CustomerInfo> FindByName(string name);
}
}
2)增加Winform接口調(diào)用層實現(xiàn)
基于Winform的實現(xiàn),就是根據(jù)接口封裝對業(yè)務邏輯層BLL的調(diào)用,BaseLocalService基類,可以看成是具有常規(guī)增刪改查等等的基礎(chǔ)性API,是基于泛型的強類型接口基類。
namespace WHC.TestProject.WinformCaller
{
/// <summary>
/// 基于傳統(tǒng)Winform方式,直接訪問本地數(shù)據(jù)庫的Facade接口實現(xiàn)類
/// </summary>
public class CustomerCaller : BaseLocalService<CustomerInfo>, ICustomerService
{
private Customer bll = null;
public CustomerCaller() : base(BLLFactory<Customer>.Instance)
{
bll = baseBLL as Customer;
}
/// <summary>
/// 根據(jù)客戶名稱獲取客戶列表
/// </summary>
/// <param name="name">客戶名稱</param>
/// <returns></returns>
public List<CustomerInfo> FindByName(string name)
{
return bll.FindByName(name);
}
}
}
3)增加WCF的接口調(diào)用層實現(xiàn)
基于WCF的實現(xiàn),就是根據(jù)接口封裝對WCF服務層的調(diào)用,BaseWCFService基類,可以看成是具有常規(guī)增刪改查等等的基礎(chǔ)性API,是基于泛型的強類型接口基類。
namespace WHC.TestProject.ServiceCaller
{
/// <summary>
/// 基于WCF服務的Facade接口實現(xiàn)類
/// </summary>
public class CustomerCaller : BaseWCFService<CustomerInfo>, ICustomerService
{
public CustomerCaller() : base()
{
this.configurationPath = EndPointConfig.WcfConfig; //WCF配置文件
this.endpointConfigurationName = EndPointConfig.CustomerService;
}
/// <summary>
/// 子類構(gòu)造一個IChannel對象轉(zhuǎn)換為基類接口,方便給基類進行調(diào)用通用的API
/// </summary>
/// <returns></returns>
protected override IBaseService<CustomerInfo> CreateClient()
{
return CreateSubClient();
}
/// <summary>
/// 創(chuàng)建一個強類型接口對象,供本地調(diào)用
/// </summary>
/// <returns></returns>
private ICustomerService CreateSubClient()
{
CustomClientChannel<ICustomerService> factory = new CustomClientChannel<ICustomerService>(endpointConfigurationName, configurationPath);
return factory.CreateChannel();
}
/// <summary>
/// 根據(jù)客戶名稱獲取客戶列表
/// </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的接口封裝層相對內(nèi)容比較復雜一些,這里介紹一下。
構(gòu)造函數(shù)通過代碼指定具體的配置文件:this.configurationPath = EndPointConfig.WcfConfig; //WCF配置文件
并通過代碼指定具體的WCFEndPoint節(jié)點名稱:this.endpointConfigurationName = EndPointConfig.CustomerService;
構(gòu)造WCF服務的代理類,我們通過CustomClientChannel的輔助方法,傳入配置文件和配置節(jié)點名稱,使得它能順利通過函數(shù) **CreateSubClient **構(gòu)造出一個對應類型的WCF代理類。
CustomClientChannel<ICustomerService> factory = new CustomClientChannel<ICustomerService>(endpointConfigurationName, configurationPath);
return factory.CreateChannel();
每次調(diào)用WCF服務類接口的時候,我們就使用創(chuàng)建的代理類進行調(diào)用,調(diào)用操作如下所示。
ICustomerService service = CreateSubClient();
ICommunicationObject comm = service as ICommunicationObject;
comm.Using(client =>
{
result = service.FindByName(name);
});
4)增加WCF服務邏輯層的實現(xiàn)
我們通過上面的代碼可以了解到,已經(jīng)創(chuàng)建了Winform的調(diào)用層、WCF服務的調(diào)用層,但是這里,我們對WCF服務還沒有實現(xiàn),這樣我們就需要實現(xiàn)WCF服務層的內(nèi)容了,否則程序試用WCF方式訪問的時候,就找不到這個FindByName的接口實現(xiàn)了。

我們看看WCF服務層里面,看看具體如何實現(xiàn),雙擊打開里面的CustomerService.Svc看到只是一個服務的聲明,沒有任何背后的代碼邏輯。
因為為了便于管理,WCF服務一般是定義和具體的實現(xiàn)是分開的,這樣就引入了一個WCF服務邏輯層的概念。

這樣它的接口實現(xiàn),就放在了WHC.TestProject.WCFLibrary項目里面了,WCF服務邏輯層的接口調(diào)用封裝如下所示。這里我們看到,他和Winform的調(diào)用邏輯幾乎一樣,只是他們的類名稱不同而已。
namespace WHC.TestProject.WCFLibrary
{
/// <summary>
/// 基于WCFLibrary的Customer對象調(diào)用類
/// </summary>
public class CustomerService : BaseLocalService<CustomerInfo>, ICustomerService
{
private Customer bll = null;
public CustomerService() : base(BLLFactory<Customer>.Instance)
{
bll = baseBLL as Customer;
}
/// <summary>
/// 根據(jù)客戶名稱獲取客戶列表
/// </summary>
/// <param name="name">客戶名稱</param>
/// <returns></returns>
public List<CustomerInfo> FindByName(string name)
{
return bll.FindByName(name);
}
}
}
5)界面層的調(diào)用操作
界面層的調(diào)用操作代碼如下所示。
string name = "張"List<CustomerInfo> list= CallerFactory<ICustomerService>.Instance.FindByName(name)
這個操作模式,和普通使用BLLFactory的方式非常相似的。
5、混合式框架的業(yè)務模塊組成
混合型框架可以看成是Winform框架高級版本,除了它本身是一個完整的業(yè)務系統(tǒng)外,它外圍的所有輔助性模塊均(如通用權(quán)限、通用字典、通用附件管理、通用人員管理。。。。)都實現(xiàn)了這種混合型的框架,因此使用非常方便,整個框架如果簡化來看,就是在原有的Winform界面層,用接口調(diào)用方式,避免和業(yè)務邏輯類的緊耦合關(guān)系。由于他是通過接口方式的調(diào)用方式,它本身又可以通過配置指定指向WCF的實現(xiàn),因此也囊括了WCF框架的一切特點。

雖然整體性的混合型框架比其他兩種框架模塊,總體增加了一些難度及復雜性,不過,為了使得整個混合型框架開發(fā)和使用更加方便,我已經(jīng)在設計上做了很多相關(guān)的工作,力求更好、更高效的使用好這種混合型框架,下面是我對整體性的框架做了的優(yōu)化改進工作。
1)把所有通用的模塊開發(fā)好,方便更好的集成使用,更加高效利用通用模塊,重復利用度更高;
2)把WCF服務發(fā)布和服務邏輯分開,更好管理和發(fā)布WCF服務,服務發(fā)布只需要svc文件,不含任何后臺代碼;
3)統(tǒng)一的業(yè)務調(diào)用規(guī)則和命名規(guī)則,所有模塊的接口調(diào)用統(tǒng)一為CallerFactory<I***Service>方式,通用模塊和框架的命名規(guī)則和機制完全一樣。
4)WCF服務配置文件分離,通用性的輔助模塊的配置文件為BaseWcfConfig.config,業(yè)務系統(tǒng)的WCF配置文件為WcfConfig.config,配置文件分離更方便管理和維護,減少主配置文件app.Config的復雜性。
5)最后一條,也是最重要的一條,就是代碼生成工具Database2Sharp的同步支持。通過代碼生成工具,更好、更快的生成整個混合性框架的代碼和項目工程,一鍵解決所有的煩惱。Winform界面,利用代碼生成工具Database2Sharp進行生成,然后在項目中整合即可。
循序漸進開發(fā)WInform項目--系列文章導引:
循序漸進開發(fā)WinForm項目(6)--開發(fā)使用混合式Winform模塊
循序漸進開發(fā)WinForm項目(5)--Excel數(shù)據(jù)的導入導出操作
循序漸進開發(fā)WinForm項目(4)--Winform界面模塊的集成使用
循序漸進開發(fā)WinForm項目(3)--Winform界面層的項目設計
循序漸進開發(fā)WinForm項目(2)--項目代碼的分析
循序漸進開發(fā)WinForm項目(1) --數(shù)據(jù)庫設計和項目框架的生成