当前位置: 首页 > news >正文

基于我的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框架进行改进,并总结开发过程中遇到的问题及解决思路。 

本文转自博客园伍华聪的博客,原文链接:基于我的Winform开发框架扩展而成的WCF开发框架,如需转载请自行联系原博主。



相关文章:

  • 「面试题」如何实现一个圣杯布局?
  • .NET开发不可不知、不可不用的辅助类(三)(报表导出---终结版)
  • 预加载机制及变量提升
  • proguaid混淆maven工程问题总结
  • 图片编辑类
  • tcpdump
  • UGUI
  • mysql -- 优化之ICP(index condition pushdown)
  • 感恩送书第1期:2019年快来了,感谢各位网友,送《Spring 5开发大全》
  • 用工作单元(IUnitOfWork)带给我们的是什么?
  • EF架构~将数据库注释添加导入到模型实体类中
  • PHP生成随机字符串
  • JMeter接口测试中文乱码问题总结
  • loongson官方PMON使用
  • 系统单据号生成规则推荐
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • [译]Python中的类属性与实例属性的区别
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • 2017 年终总结 —— 在路上
  • 回顾2016
  • 基于webpack 的 vue 多页架构
  • 解析带emoji和链接的聊天系统消息
  • 排序(1):冒泡排序
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 微信小程序开发问题汇总
  • 协程
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • Hibernate主键生成策略及选择
  • ​2020 年大前端技术趋势解读
  • ​Linux·i2c驱动架构​
  • !$boo在php中什么意思,php前戏
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (C++17) std算法之执行策略 execution
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (一)Java算法:二分查找
  • (一)Thymeleaf用法——Thymeleaf简介
  • (转)为C# Windows服务添加安装程序
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • .NET CF命令行调试器MDbg入门(一)
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .NET Framework 服务实现监控可观测性最佳实践
  • .NET 材料检测系统崩溃分析
  • .Net 知识杂记
  • .NET委托:一个关于C#的睡前故事
  • @AliasFor注解
  • [17]JAVAEE-HTTP协议
  • [Android学习笔记]ScrollView的使用
  • [BZOJ 4129]Haruna’s Breakfast(树上带修改莫队)
  • [C#]winform制作仪表盘好用的表盘控件和使用方法