• 基于我的Winform开发框架扩展而成的WCF开发框架


    一直以来,多数时间在开发一些Winform共享软件,经过多年的积累,逐渐形成比较成熟稳定的Winform开发框架,并结合Web项目开发经验、代码生成工具、相关的控件开发及项目开发经验,逐渐形成一个相对比较完善的.NET开发体系。不过由于种种原因,甚少涉足WCF的相关应用,只是在09年初的时候,开发一个送水软件网络版的时候,玩过WCF,那时候主要是把WCF作为一个送水各种业务数据的同步服务实现。由于研究兴趣及工作便利等原因,最近学习研究,把WCF服务搭建在我传统的Winform开发框架基础上,完成一个分布式的WCF开发框架,本文主要介绍相关的框架实现过程及总结碰到的问题,逐步深入研究,力求把其设计为我的Winform开发框架外的一个补充,可以作为分布式应用开发框架。

    首先总结一下WCF的一些特点,WCF主要是基于客户端-服务端通讯模式来实现分布式应用,并通过服务公布的节点进行访问,实现数据的交换等服务。下面是其中应用的几个示意图。

     

     

    我们先来看看我的传统Winform开发框架的设计图,如下所示。其中界面层UI直接访问BLL层,不需要通过网络,其中公用辅助类库Common层、实体类层可以在各个层中访问,并把常用的权限管理、字典管理封装为组件模块,直接调用,底层则使用工厂方式,来支持各种不同的数据库,其中UI层、BLL层、DAL层、实体层均使用继承类方式实现最良好的封装、最优的代码设计。

     

    关于我的Winform开发框架相关内容,可以参考下面几篇文章:

     (1)Winform开发框架之字典数据管理

     (2)Winform开发框架之权限管理系统

     (3)Winform开发框架之终极应用

     (4)Winform开发框架之Office Ribbon界面

     另外还有未发布的基于DevExpress样式的Winform开发框架,整个多样式界面的Winform框架工程如下图所示。

     

    由于工程管理的需求,我倾向于尽可能减少工程的项目,因此框架业务层把BLL层、DAL层、IDAL层、Entity层均融合放到一个工程项目中,通过不同的目录进行区分即可,这样既方便应用,也方便部署管理。

     

    下面开始介绍基于以上Winform框架的WCF框架扩展,首先我们在界面层和BLL层插入一层WCF服务层,界面层UI不再业务层BLL打交道,而是代之以WCF服务层的客户端代理类打交道,而WCF服务层则是BLL层更进一步的包装,设计图如下所示。

     

    项目工程截图如下所示

     

    客户端调用WCF服务非常方便简单,构造一个WCF服务客户端代理类实例即可应用,如下所示,如果有多个服务,创建多个实例服务即可。

            private ManufacturerServiceClient client = new ManufacturerServiceClient();
            private CompanyParkServiceClient companyParkClient = new CompanyParkServiceClient(); 

     

    由于WCF服务是直接对BLL层的封装,因此也需要提供BLL层基础的增删改查等操作,我们把它定义基类接口IBaseService,并实现该基类接口即可。如下代码所示。

        [ServiceContract]
        public interface IBaseService<T> where T : BaseEntity
        {
            [OperationContract]
            bool Delete(string key);

            [OperationContract]
            bool DeleteByCondition(string condition);
            
            [OperationContract]
            List<T> FindWithPager(string condition, PagerInfo info);

            [OperationContract]
            List<T> Find(string condition);

            [OperationContract]
            T FindByID(string key);

            [OperationContract]
            List<T> FindByIDs(string idString);

            [OperationContract]
            T FindFirst();

            [OperationContract]
            T FindLast();

            [OperationContract]
            T FindSingle(string condition);

            [OperationContract]
            DataTable FindToDataTable(string condition);

            [OperationContract]
            List<T> GetAllWithPager(PagerInfo info);

            [OperationContract]
            List<T> GetAll();

            [OperationContract]
            DataSet GetAllToDataSet(PagerInfo info);

            [OperationContract]
            DataTable GetAllToDataTable();

            [OperationContract]
            int GetRecordCount2(string condition);

            [OperationContract]
            int GetRecordCount();

            [OperationContract]
            bool Insert(T obj);

            [OperationContract]
            int Insert2(T obj);

            [OperationContract]
            bool IsExistKey(string fieldName, object key);

            [OperationContract]
            bool IsExistRecord(string condition);

            [OperationContract]
            bool Update(T obj, string primaryKeyValue);
        } 

     基类的实现如下所示,其中看到,基本是封装了BLL业务层的封装,和传统Winform框架界面层的调用很类似。另外该类通过泛型来识别对应的实体类,并通过实体类的类型名称来构造对应的业务层实例,这个和DAL、IDAL的继承关系很接近,因此不难理解。

         public class BaseService<T> : IBaseService<T> where T : BaseEntity, new()    {
            BaseBLL<T> bll = null;

            public BaseService()
            {
                bll = (BaseBLL<T>)Assembly.Load("ParkDeviceUserBiz").
                    CreateInstance(typeof(T).FullName.Replace("Entity""BLL").Replace("Info"""));
            }

            #region 对象添加、修改、查询接口

            /// <summary>
            
    /// 插入指定对象到数据库中
            
    /// </summary>
            
    /// <param name="obj">指定的对象</param>
            
    /// <returns>执行成功返回新增记录的自增长ID。</returns>
            public virtual bool Insert(T obj)
            {
                return bll.Insert(obj);
            }

            /// <summary>
            
    /// 插入指定对象到数据库中
            
    /// </summary>
            
    /// <param name="obj">指定的对象</param>
            
    /// <returns>执行成功返回新增记录的自增长ID。</returns>
            public virtual int Insert2(T obj)
            {
                return bll.Insert2(obj);
            }

            /// <summary>
            
    /// 更新对象属性到数据库中
            
    /// </summary>
            
    /// <param name="obj">指定的对象</param>
            
    /// <returns>执行成功返回<c>true</c>,否则为<c>false</c></returns>
            public virtual bool Update(T obj, string primaryKeyValue)
            {
                return bll.Update(obj, primaryKeyValue);
            }

            /// <summary>
            
    /// 查询数据库,检查是否存在指定ID的对象(用于字符型主键)
            
    /// </summary>
            
    /// <param name="key">对象的ID值</param>
            
    /// <returns>存在则返回指定的对象,否则返回Null</returns>
            public virtual T FindByID(string key)
            {
                return bll.FindByID(key);
            }

            /// <summary>
            
    /// 根据条件查询数据库,如果存在返回第一个对象
            
    /// </summary>
            
    /// <param name="condition">查询的条件</param>
            
    /// <returns>指定的对象</returns>
            public virtual T FindSingle(string condition)
            {
                return bll.FindSingle(condition);
            }

            /// <summary>
            
    /// 查找记录表中最旧的一条记录
            
    /// </summary>
            
    /// <returns></returns>
            public T FindFirst()
            {
                return bll.FindFirst();
            }

            /// <summary>
            
    /// 查找记录表中最新的一条记录
            
    /// </summary>
            
    /// <returns></returns>
            public T FindLast()
            {
                return bll.FindLast();
            }

            /// <summary>
            
    /// 获取表的所有记录数量
            
    /// </summary>
            
    /// <returns></returns>
            public int GetRecordCount2(string condition)
            {
                return bll.GetRecordCount(condition);
            }

            /// <summary>
            
    /// 获取表的所有记录数量
            
    /// </summary>
            
    /// <returns></returns>
            public int GetRecordCount()
            {
                return bll.GetRecordCount();
            }

            /// <summary>
            
    /// 根据condition条件,判断是否存在记录
            
    /// </summary>
            
    /// <param name="condition">查询的条件</param>
            
    /// <returns>如果存在返回True,否则False</returns>
            public bool IsExistRecord(string condition)
            {
                return bll.IsExistRecord(condition);
            }

            /// <summary>
            
    /// 查询数据库,检查是否存在指定键值的对象
            
    /// </summary>
            
    /// <param name="fieldName">指定的属性名</param>
            
    /// <param name="key">指定的值</param>
            
    /// <returns>存在则返回<c>true</c>,否则为<c>false</c></returns>
            public virtual bool IsExistKey(string fieldName, object key)
            {
                return bll.IsExistKey(fieldName, key);
            }

            /// <summary>
            
    /// 根据指定对象的ID,从数据库中删除指定对象(用于整型主键)
            
    /// </summary>
            
    /// <param name="key">指定对象的ID</param>
            
    /// <returns>执行成功返回<c>true</c>,否则为<c>false</c></returns>
            public virtual bool Delete(string key)
            {
                return bll.Delete(key);
            }

            /// <summary>
            
    /// 根据指定条件,从数据库中删除指定对象
            
    /// </summary>
            
    /// <param name="condition">删除记录的条件语句</param>
            
    /// <returns>执行成功返回<c>true</c>,否则为<c>false</c></returns>
            public virtual bool DeleteByCondition(string condition)
            {
                return bll.DeleteByCondition(condition);
            }

            #endregion

            #region 返回集合的接口

            /// <summary>
            
    /// 根据ID字符串(逗号分隔)获取对象列表
            
    /// </summary>
            
    /// <param name="idString">ID字符串(逗号分隔)</param>
            
    /// <returns>符合条件的对象列表</returns>
            public virtual List<T> FindByIDs(string idString)
            {
                return bll.FindByIDs(idString);
            }

            /// <summary>
            
    /// 根据条件查询数据库,并返回对象集合
            
    /// </summary>
            
    /// <param name="condition">查询的条件</param>
            
    /// <returns>指定对象的集合</returns>
            public virtual List<T> Find(string condition)
            {
                return bll.Find(condition);
            }

            /// <summary>
            
    /// 根据条件查询数据库,并返回对象集合(用于分页数据显示)
            
    /// </summary>
            
    /// <param name="condition">查询的条件</param>
            
    /// <param name="info">分页实体</param>
            
    /// <returns>指定对象的集合</returns>
            public virtual List<T> FindWithPager(string condition, PagerInfo info)
            {
                return bll.Find(condition, info);
            }

            /// <summary>
            
    /// 返回数据库所有的对象集合
            
    /// </summary>
            
    /// <returns>指定对象的集合</returns>
            public virtual List<T> GetAll()
            {
                return bll.GetAll();
            }

            /// <summary>
            
    /// 返回数据库所有的对象集合(用于分页数据显示)
            
    /// </summary>
            
    /// <param name="info">分页实体信息</param>
            
    /// <returns>指定对象的集合</returns>
            public virtual List<T> GetAllWithPager(PagerInfo info)
            {
                return bll.GetAll(info);
            }

            public virtual DataSet GetAllToDataSet(PagerInfo info)
            {
                return bll.GetAllToDataSet(info);
            }

            public DataTable GetAllToDataTable()
            {
                return bll.GetAllToDataTable();
            }

            public DataTable FindToDataTable(string condition)
            {
                return bll.FindToDataTable(condition);
            }

            #endregion
        }

    创建服务的时候,我们在工程上创建一个WCF服务类接口,类的名称和BLL层的类名称一样,不过后面增加一个Service后缀即可,如下所示。

     

    接下来要修改相关的实现代码,主要是继承关系,如下代码所示。

        public class ManufacturerService : BaseService<ManufacturerInfo>, IManufacturerService
        {
            /// <summary>
            
    /// 检查是否存在重复的单位名称(排除ID本身的)
            
    /// </summary>
            
    /// <param name="companyName">单位名称</param>
            
    /// <param name="ID"></param>
            
    /// <returns></returns>
            public bool CheckExist(string companyName, string ID)
            {
                return BLLFactory<Manufacturer>.Instance.CheckExist(companyName, ID);
            }
        }

    编译服务后,在WinformUI层添加WCF服务应用即可,如下所示 。

     

    引用、创建WCF服务客户端代理类,并调用,即可调用IBaseService里面定义的接口和扩展接口IManufacturerService里面的接口实现。WCF接口测试可以使用WCFStorm Lite 来进行接口查看及调试,如下所示。

     

    整个项目可以在局域网或者广域网中部署,实现更大范围的分布式应用,最后呈上该项目的运行界面,供参考验证。

     以上界面层在传统的Winform框架界面中和WCF+winform框架界面中表现一致,在局域网中部署测试,客户端 + WCF服务器 + Oracle数据库服务器这种部署模式,非常流畅,由于是基于WCF框架结构,可以应用在广域网中,不过可能服务相应及Winform的体验要依赖于带宽的大小吧。

    后续的文章继续就改WCF框架进行改进,并总结开发过程中遇到的问题及解决思路。 

    主要研究技术:代码生成工具、会员管理系统、客户关系管理软件、病人资料管理软件、Visio二次开发、酒店管理系统、仓库管理系统等共享软件开发
    专注于Winform开发框架/混合式开发框架Web开发框架Bootstrap开发框架微信门户开发框架的研究及应用
      转载请注明出处:
    撰写人:伍华聪  http://www.iqidi.com 
        
  • 相关阅读:
    mysql操作
    Linux内核事件通知链学习
    C++双端队列学习
    tune的结果图是什么
    conda环境备份
    Could not load dynamic library 'libcudart.so.11.0';
    Unexpected error while saving file: xxx.ipynb database or disk is full
    友元函数与友元类
    构造函数初始化必须采用初始化列表的情况
    模型集成04-GMM
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/2185619.html
Copyright © 2020-2023  润新知