循序漸進開發WinForm項目(6)--開發使用混合式Winform模塊


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項目(2)--項目代碼的分析

 《循序漸進開發WinForm項目(1) --數據庫設計和項目框架的生成

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM