wenmo8 发布的文章

在Winform方面,基于业务的不同,我们可以利用工具的效率,快速做很多不同的业务系统,前期做了一个缺陷管理系统,想把单位的测试业务规范下,也好统计和分析每个版本的缺陷信息,本篇整理这些数据库设计和界面设计的相关内容,做一个介绍,希望给大家一个对比参照的案例进行学习了解。

1、缺陷管理系统的业务分析

在很多缺陷管理系统里面,我们往往需要管理的就是缺陷信息的记录,以及缺陷记录的开闭过程,从而实现了测试人员-》开发人员-》测试人员的整个闭环过程。

一般情况下,缺陷管理系统可以部署在局域网内,或者公网内方便各个项目组成员的使用,因此可以采用BS的架构,也可以CS架构实现分布式的应用,通常情况下,采用CS的方式,在数据处理方面会友好一些,因此结合需求,我这里采用了我常用的混合型框架,数据采用WCF服务获取,实现数据的共享。

缺陷信息,一般是属于具体某个项目,某个版本,某个模块下的具体信息,因此这些分类必须独立进行维护,才能方便进行后面的统计和分析,一般缺陷信息还需要提交出错的图片附件信息,方便直观的了解和开发人员排错。

缺陷项目的信息,为了分类,我们还可以分为一个域进行管理,也就是分组的概念,如按不同类型的项目,分为不同的项目域,如产品项目、客户项目、研究性项目等分类都可以。

以上这些都是缺陷里面很重要的属性信息,因此我们需要在缺陷管理系统里面很好的设计才能使得我们的系统符合我们的业务流程。

一般情况下,版本和模块是对应不同项目的,缺陷状态、缺陷类型、优先级、紧急程度,这些是通用的字典项目,不会因为项目而变化。

另外,缺陷处理一般是一个闭环流程,最初一般由测试人员发起(状态为未解决),提交给开发人员,开发人员根据缺陷记录,设置合理的状态,如果是正常需要处理的缺陷,一般需要修正错误,并设置状态为已解决,然后测试人员对缺陷进行回归测试,如果缺陷已经解决,则设置缺陷状态为已关闭,否则重新打开缺陷为未解决状态,依次循环,最后大家达到共识,是不解决或者推迟解决等。这些修改的过程也需要在缺陷系统里面进行记录,已进行跟踪历史。

2、缺陷管理系统的数据库设计

为了存储上面的缺陷信息,我们需要设计一些表进行数据的存储,除了一些通用性的信息存储,如字典信息、附件信息,采用通用模块存储外,对于缺陷的相关信息,我们还需要设计如下的表对象来存储信息。

上面的表之间有一定的关系,在红色部分进行了标识。

3、缺陷系统的界面设计

界面设计还是采用常见的工具栏的方式进行布局,根据缺陷的信息关系,我们查看信息 的时候,让用户先在具体的域下面选择具体的项目,然后展示该项目下的缺陷信息。

选择项目信息后,我们一般需要根据项目显示它的缺陷列表,缺陷信息提供重要的信息展示。

双击可以展开具体的缺陷信息,其中包括附件提交和查看管理,缺陷的修改历史等信息。

对于缺陷里面的一些字典属性,我们可以通过统一的字典模块进行维护,如下所示,可以对缺陷状态、缺陷类型、优先级、严重程度等信息进行独立的维护管理。

一般情况下,我们最终还是需要根据缺陷的记录,获得一定的统计分析报表,以便对该版本是否能够正常发布进行一个评估工作,或者是了解缺陷的分类、趋势等信息的需要。

例如,我们可以在缺陷分类统计里面,把缺陷状态、缺陷类型、严重程度、优先级等根据版本信息进行一个分类统计,也可以根据缺陷的趋势进行统计等等。

我们在日常接触到的一些软件界面,往往喜欢深入分析其实现机理,通过学习、分析,可以提高我们对软件架构的分析能力,从而实现更加弹性、可重用的模块。在无意间,看到一个短信模块的设计,模板里面可以包含了很多变量,从而引发我对其深入分析的兴趣,本文主要介绍我对这些实现的一些理解,介绍一个包含动态变量的短信模板的设计分析。

1、短信模板的效果介绍

如下图所示,上面包含了短信模板的列表信息,以及对具体模板的内容设计,可以在其中插入变量的处理。

如果是硬编码对个别的实现应该很容易,如果我们考虑可扩展性、重用性等因素,需要进行弹性的设计,那么就需要寻找好的思路来动态处理这些变量了。

如它的每个模板的变量都是可以不同的,如其中一个模板有如下变量可以插入到模板内容里面,变量本身用左右的括弧{}进行标识,还是很有规律的。

2、短信模板的设计分析

由于模板是针对某个企业的,企业可能根据需要进行一定的调整,模板可以恢复为最初的版本,因此我们可以考虑设计两个部分,一个部分是基础模板,一个部分是对企业的消息模板,前者不变,后者可以根据需要修改,如无修改保存的,则采用对应的基础模板,也就是模板的模板了。

由于模板是包含有不同变量的,因此我们需要在设计的时候,动态解析这些变量。我们如果能够把传入的对象动态获取它的属性,并给对应的变量赋值,应该就可以实现这个功能。

那么我们就需要通过反射方式,动态获取对应object对象的各种属性名称和值了,这个处理操作如下所示。

        /// <summary>
        ///把object对象的属性反射获取到字典列表中/// </summary>
        /// <param name="data">object对象</param>
        /// <returns></returns>
        public static Dictionary<string, string> GetProperties(objectdata)
{
Dictionary
<string, string> dict = new Dictionary<string, string>();

Type type
=data.GetType();string[] propertyNames = type.GetProperties().Select(p =>p.Name).ToArray();foreach (var prop inpropertyNames)
{
object propValue = type.GetProperty(prop).GetValue(data, null);string value = (propValue != null) ? propValue.ToString() : "";if(!dict.ContainsKey(prop))
{
dict.Add(prop, value);
}
}
returndict;
}

前面介绍了,模板的内容,是包含有左右括弧{}的变量的,因此我们可以通过正则表达式,把它们提取出来备用,这样我们就可以把前面反射对应属性的值赋值给模板内容,从而形成新的待发送的具体消息了。

            var regex = @"\{(?<name>.*?)\}";
List
<string> itemList = GetList(template, regex, "name");

其中GetList就是一个正则表达式获取对应正则内容的函数,函数代码如下所示。

        /// <summary>
        ///多个匹配内容/// </summary>
        /// <param name="sInput">输入内容</param>
        /// <param name="sRegex">表达式字符串</param>
        /// <param name="sGroupName">分组名, ""代表不分组</param>
        public static List<string> GetList(string sInput, string sRegex, stringsGroupName)
{
List
<string> list = new List<string>();
Regex re
= new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace |RegexOptions.Multiline);
MatchCollection mcs
=re.Matches(sInput);foreach (Match mc inmcs)
{
if (sGroupName != "")
{
list.Add(mc.Groups[sGroupName].Value);
}
else{
list.Add(mc.Value);
}
}
returnlist;
}

最后我们可以把内容对应上,给模板替换为最新的属性值了。

        private void button1_Click(objectsender, EventArgs e)
{
//模板文本 var template = "姓名 = {姓名}, 性别 = {性别}, 卡号 = {卡号}, 公司 = {公司}";//数据对象 var data = new { 姓名 = "伍华聪", 性别 = "", 卡号 = "10000", 公司 = "广州爱奇迪软件科技有限公司"};

ReplaceTemplate(template, data);
}
private void ReplaceTemplate(string template, objectdata)
{
var regex = @"\{(?<name>.*?)\}";
List
<string> itemList = GetList(template, regex, "name");

Console.WriteLine(
"列出模板变量对象:");foreach(string item initemList)
{
Console.WriteLine(item);
}

Dictionary
<string, string> dict =GetProperties(data);foreach(string item initemList)
{
//如果属性存在,则替换模板,并修改模板值 if(dict.ContainsKey(item))
{
template
= Replace(template, regex, dict.Values.ToList());//替换第一个 }
}

Console.WriteLine(template);
}

测试上面的代码,我们注意到我们的对象是动态构建的,也就是使用匿名类的方式构建一个类,包含有对应的属性值,把这个给模板进行解析,从而赋值形成真正的消息内容的。

var data = new { 姓名 = "伍华聪", 性别 = "", 卡号 = "10000", 公司 = "广州爱奇迪软件科技有限公司" };

测试案例,我们可以得到的消息,如下所示。

我们从上面截图可以看到,真正的消息已经正确得到,这些是替换具体的模板内容形成的,如果我们在整体的模板设计里面,采用这个思路,就可以实现动态的模板消息发送,从而实现了比较弹性化的设计处理。

本文只是对模板变量这种场景进行了分析,我们在实际项目中,可以更加完善,实现更加强大的模板消息处理,以及利用微信模板消息进行一起发送,实现短信、微信,甚至邮件的同步通知,给客户更好的体验。

以上是微信的模板消息介绍,我们也可以结合动态变量,把对应模板消息替换为我们要发送的消息,从而也实现了微信消息的动态发送。

利用好的界面控件,往往能做成比较界面体验效果。在一些界面操作里面,我们可能把它拆分为几部进行处理,这个时候引入WizardControl向导控件应该是比较不错的选择了。多步的处理方式,可以让用户避免一次性输入太多内容的烦躁心情,也可以针对性的校验部分内容,本文以利用WizardControl控件来设计找回密码的结果来进行介绍,使大家对基于DevExpress的WizardControl向导控件的使用有一个大概的了解。

1、界面效果的规划

在一般APP或者基于网络的软件界面里面,都有一个为了帮助用户找回账号密码的功能,可以让用户自助通过手机、邮件等方式获得充值密码的机会。如一般的APP界面效果如下所示。


但是一般Winform的界面,可以利用向导控件做的更好,其中DevExpress的WizardControl向导控件就是一个很好的选择。

我们一般在DevExpress的VS工具栏里面选择导航布局选项卡,就可以找到对应的WizardControl向导控件了。

最终我们实现的效果如下所示。

2、控件的使用及代码处理

上面介绍了,在在DevExpress的VS工具栏里面选择导航布局选项卡,就可以找到对应的WizardControl向导控件了。

我们拖动能这个控件到一个空白的窗体界面上,就可以看到默认有一些界面了,我们在其中可以看到一个完整的向导界面效果的。

拖动过来的控件,初始化界面效果都是英文的,可以通过控件属性对其中的文字进行修改即可。

修改后的界面效果如下所示。

然后我们修改向导控件的一些属性,如图片、文字等内容,最后在其中空白的位置,拖入一些界面控件,实现我们的界面效果即可。

另外默认的向导控件是三个界面页的,因此我们可以根据需要增加或者删除一些,如本例我就移除了一个,仅仅使用两个页面来处理密码的找回处理即可。

另外,我们为了实现向导控件界面的输入验证和处理,我们往往还需要对其中下一步、完成、取消、帮助等事件进行处理,这样才能达到较好的处理效果。

其中部分处理代码如下所示。

        private void wizardControl1_NextClick(objectsender, DevExpress.XtraWizard.WizardCommandButtonClickEventArgs e)
{
string pageText =e.Page.Text;if(pageText == "验证账号")
{
if (this.txtMobile.Text.Length == 0 || this.txtValidateCode.Text.Length == 0)
{
MessageDxUtil.ShowTips(
"请输入手机号码和验证码");
e.Handled
= true;this.txtValidateCode.Focus();return;
}
else if(!ValidateUtil.IsValidMobile(this.txtMobile.Text))
{
MessageDxUtil.ShowTips(
"请输入正确的手机号码");
e.Handled
= true;this.txtMobile.Focus();return;
}
else{bool result = CallerFactory<ISmsCodeService>.Instance.CheckSmsCode(this.txtMobile.Text, this.txtValidateCode.Text);if (!result)
{
MessageDxUtil.ShowTips(
"验证码校验不正确,请检查验证码是否在有效时间内。");this.txtValidateCode.Focus();return;
e.Handled
= true;
}
}
}
else if(pageText == "重置密码")
{
MessageDxUtil.ShowTips(pageText);
}
}

在这些Next下一步事件里面,有一个代码是需要阻塞下一步的处理的。

e.Handled = true;

这样我们就可以实现对用户输入的验证处理了,如果处理不通过,那么就停留在这个页面上,让用户校正输入即可。

如果是完成按钮页面,它的处理也是差不多。

        private void wizardControl1_FinishClick(objectsender, CancelEventArgs e)
{
if (this.txtCorpAccount.Text.Length == 0)
{
this.txtCorpAccount.Focus();
MessageDxUtil.ShowTips(
"公司账号不能为空!");
e.Cancel
= true;return;
}
else if(this.txtNewPassword.Text.Length == 0)
{
this.txtNewPassword.Focus();
MessageDxUtil.ShowTips(
"密码不能为空!");
e.Cancel
= true;return;
}
else if (!this.txtNewPassword.Text.Equals(this.txtRePassword.Text))
{
this.txtRePassword.Focus();
MessageDxUtil.ShowTips(
"两次密码不一致!");
e.Cancel
= true;return;
}


...............

最后我们实现的效果就是前面所说的一样了。

结合短信平台,我们可以给用户发送验证码以及提示消息即可。

最近一直在整合WebAPI、Winform界面、手机短信、微信公众号、企业号等功能,希望把它构建成一个大的应用平台,把我所有的产品线完美连接起来,同时也在探索、攻克更多的技术问题,并抽空写写博客,把相应的技术心得和成果进行一定的介绍,留下开拓的印记。本文主要介绍混合框架整合Web API应用过程中,分析Winform界面如何一步步对Web API的调用处理的。

1、Winform界面的应用方向

在很多场合,分布式采用Web方式构建应用,不过相对Winform来说,Web界面的体验性没有那么好,界面呈现也相对单调 一些,而且涉及到和打印、摄像、读卡等硬件处理的时候,Winform的优势就更加明显了,Winform唯一被诟病的是其分布性的处理和安装发布的问题,分布性可以通过直接利用Web API的方式进行处理,从而逻辑集中在Web API层,而安装发布,则可以通过自动更新的模式进行处理,如目前很多桌面程序,都是自动更新的方式进行迭代更新。

因此Winform可以基于一个Web API的整体性平台,构建很多应用生态链。例如我们常见的微信应用(企业号,公众号,订阅号等)、以及Winform应用、原生APP、Web网站应用等等,如下图所示。

其中是把Web API作为核心层,可以在上面开发我们各种企业业务应用就可以了。

在前面介绍过相应的Web API的封装和调用规则,如下图所示,红色部分为Web API 的调用路线,从Winform客户端开始,经过统一门面结构Facade接口层,对Web API的服务层进行调用,下面这个图从大的方向来阐述了整个调用的路线,不过于调用细节的理解并不很准确,因为涉及到很多内容已经省略了。 下面我们将把整个调用的路线进行完整的阐述说明。

2、Winfrom界面调用WebAPI的过程

在前面的小节里面,我们说到了Winform调用Web API的过程,这个过程可以通过下面这个图示进行讲解。

1)
首先我们在界面一般是通过定义一个Winform窗体,并在其中放置相应的控件来承载信息的,这个和普通的Winform是一样的,例如我们定义一个窗体对象FrmMember,以及FrmEditMember。

2)
在主体界面里面,我们需要调用FrmMember这个窗体,可以通过对话框的方式,或者是多文档的方式进行调用显示。

            FrmEditMember dlg = newFrmEditMember();
dlg.ShowDialog();

或者多文档界面展示

ChildWinManagement.LoadMdiForm(this, typeof(FrmMember));

3)
在界面里面,我们需要调用接口对象(Web API的客户端包装类)进行获取对应的信息,这里使用到了接口工厂CallerFactory<T>这种方式进行调用。

MemberInfo info = CallerFactory<IMemberService>.Instance.FindByID(ID);

4)
上面这个工厂类CallerFactory<T>是负责获取到对应的接口实现类并创建对象,方便我们进行调用处理。它的逻辑主要是通过IMemberService接口所在的程序集(例如WHC.CloudMember.WebApiCaller),然后获取对应接口的实现类,并构建一个这样的接口实例出来使用的。

例如字典模块,混合框架里面,他们的各个模块的实现类是放在程序集里面的,我们的目标就是根据接口的名称,从对应的部分获取相应的Web API接口调用包装类进行使用。

5)
我们构建的Web API接口调用包装类(WebApiCaller里面的内容),为了实现更加方便的调用,我们为它进行了一定的封装,使它在基于泛型的基础上具有基础增删改查、分页等功能的调用处理。

从这个类的定义里面,我们可以看到Web API的调用包装类MemberCaller是继承自BaseApiService<MemberInfo>这样的泛型基类的。这个BaseApiService<MemberInfo>就具有对特定对象的增删改查、分页等基础调用功能了。

例如在基类BaseApiService里面的查找对应对象的接口代码如下所示

        /// <summary>
        ///查询数据库,检查是否存在指定ID的对象(用于字符型主键)/// </summary>
        /// <param name="key">对象的ID值</param>
        /// <returns>存在则返回指定的对象,否则返回Null</returns>
        public virtual T FindByID(stringkey)
{
var action = "FindByID";string url = GetTokenUrl(action) + string.Format("&id={0}", key);return JsonHelper<T>.ConvertJson(url);
}

这里面的逻辑就是构建一个带有token(用户身份标识)的连接字符串和参数字符串,从而获取HTML内容后把它转换为具体对象的处理了。

其中转换的代码就是利用了Newtonsoft.Json的对象的转换,具体代码如下所示。

        /// <summary>
        ///转换Json字符串到具体的对象/// </summary>
        /// <param name="url">返回Json数据的链接地址</param>
        /// <returns></returns>
        public static T ConvertJson(stringurl)
{
HttpHelper helper
= newHttpHelper();
helper.ContentType
= "application/json";string content =helper.GetHtml(url);
VerifyErrorCode(content);

T result
= JsonConvert.DeserializeObject<T>(content);returnresult;
}

6)
用户的访问令牌(Token信息)

当然我们调用这个接口前,我们需要获取到对应的Token(用户令牌)然后才能进行API的调用了。这个Token的机制采用了JWT的令牌生成方式,具有很好的通用性。

例如我使用自己的Web API调试工具,获取到对应的token方式如下所示。下面的1-5的标识就是获取token所需要的签名数据,当然连接还带有几个账号认证所需要的信息了,如账号密码、所在公司等信息。

当然我们也可以使用浏览器进行测试获取Token的信息,只是没有那么方便而已。

系列文章如下所示:

Web API应用架构在Winform混合框架中的应用(1)

Web API应用架构在Winform混合框架中的应用(2)--自定义异常结果的处理

Web API接口设计经验总结

Web API应用架构在Winform混合框架中的应用(3)--Winfrom界面调用WebAPI的过程分解

Web API应用架构在Winform混合框架中的应用(4)--利用代码生成工具快速开发整套应用

Web API应用架构在Winform混合框架中的应用(5)--系统级别字典和公司级别字典并存的处理方式

前面几篇介绍了Web API的基础信息,以及如何基于混合框架的方式在WInform界面里面整合了Web API的接入方式,虽然我们看似调用过程比较复杂,但是基于整个框架的支持和考虑,我们提供了代码生成工具的整合,使得开发整套应用是非常方便和高效的。本文主要介绍如何利用代码生成工具Database2Sharp,如何迅速生成基于Web API的Winform应用。

1、代码生成工具的功能介绍

代码生成工具Database2Sharp,是我为整个开发过程开发的一款核心软件,已经走过了10个年头,随着开发项目的多样化,这个工具也逐渐整合更多的功能,以期提高我们的开发效率。

Database2Sharp能够支持Winform开发框架、WCF开发框架、混合式Winfrom开发框架、Entity Framework实体框架、基于MVC4+EasyUI的Web开发框架、基于Metronic的Bootstrap
的Web
项目等
开发框架的代码生成和整合工作;可以生成各种架构代码、生成Web界面代码、Winform界面代码,导出数据库文档等功能。软件
生成的框架代码具有统一的架构风格和统一调用规则,并在多年的软件开发应用中得到实践验证,具有非常高的生产效率。

该软件的目的在整合、简化各种框架的开发流程,并统一整个开发的继承和结构关系,提高开发效率。

为了生成整个基于Web API的Winform应用,我们选择Enterprise Library的框架生成混合式框架项目进行简单的介绍,希望大家对代码生成有一个初步的了解。

首先选择数据库需要生成代码的表,操作如下所示。

接着我们选择框架的主命名空间,如我们实体类的整个命名空间为WHC.CloudMember.Entity,那么主命名空间就是前面部分WHC.CloudMember了。

最后会让我们确认整个生成过程的,如下所示。

这样单击【完成】按钮后,我们就可以顺利生成我们所需的项目代码了。为了快速开发一个完善的项目,我们一般基于各种不同的框架基础上,增量开发一些不同的业务模块,这样就可以快速整合到我们的项目里面进行使用了。

2、基于WebAPI接入的Winform项目结构

1)框架总体介绍

前面随笔,我介绍了整个混合框架中基于Web API 的Winform界面的整合过程,其中大的方面设计图如下所示。

而对应的从Winform界面调用Web API的过程则如下所示。

但是这两个可能没有项目结构查看的话,对整体的了解可能还是有所欠缺,本文继续以实际项目的结构,也就是我以Web API方式改造的会员管理系统项目结构进行展示,以实践的项目开发过程来阐述整个开发过程,希望读者对这些有更好的了解和更直观的认识。

整个会员管理系统项目结构如下所示。

项目结构的总体说明如下所示。

项目名称 项目说明
WHC.CloudMember.ClientDx 基于Web API的WInform界面项目
WHC.CloudMember.Caller 接口调用封装类模块
CloudMemberApi Web API的服务发布项目
WHC.CloudMember.Core 业务逻辑模块的项目,包含数据访问层、接口、实体类等

2)Web API服务项目介绍

我们在Winform界面里面调用的最终服务就是Web API服务,那么我们需要围绕这个内容进行介绍,首先介绍其中的Web API项目CloudMemberApi,它的详细内容就是包含前面几篇关于Web API随笔介绍的内容,包括服务接口的定义、异常的处理、令牌权限认证及识别、Web API客户端的调用的知识点。

在控制器里面,通过不同的文件来区分不同的业务应用,当然如在必要的时候,也可以考虑引入Area的概念,对不同业务进行归类处理。

在上面的API项目里面,主要的内容就是控制器的生成了,利用代码生成工具的Web API控制器的生成功能,可以快速生成相关的代码。

代码生成后,会生成对应类的继承关系,以及部分接口的实例代码,方便我们进行使用。

3)服务调用包装项目Caller项目

在Caller项目里面,就是为客户端提供一致的调用方式,不管是WCF方式、直接访问数据库方式,还是目前介绍的Web API方式,我们通过Caller项目类的封装处理,就能屏蔽他们之间的差异,使得我们的界面调用实现统一性,并且也方便在各个方式的调用中进行切换。利用在这个项目里面,Web API的Caller层项目结构如下所示。

这个项目里面包含了门面层的接口定义层Facade接口层,由于我们考虑了WCF的接入方式,因此需要增加一些WCF的接口标识,如果仅仅是考虑Web API的接入,则可以不用[ServiceContract]和[OperationContract]的声明内容。

对于Web API的调用,我们一般通过继承基类的方式,可以直接使用基类定义的增删改接口的封装处理,这样可以极大简化我们所需的代码,同时降低代码编写的复杂度,常规的功能我们也不用重复编写了。

同时,我们一般都保留直接调用数据库的包装类项目代码【WinformCaller】,这样我们可以在开发的时候,先着重调试好直接访问数据库的模式,然后在调试基于Web API的方式,这样可以避免很多低层次的错误,同时也可以快速调试跟踪代码,为我们后面的Web API接入排除更多的错误,提高开发效率和代码质量。

4)业务模块核心项目Core项目

在各个框架以及Web API的服务里面,数据库访问的核心逻辑都在Core项目里面的,这个项目其实包含了BLL层、DAL层、IDAL层、Entity层的模块内容,封装了多种数据库的访问方式,默认框架支持SQLServer、Oracle、MySql、SQLite、Access、达梦等数据库的支持,我们在DAL层进行相应的扩展处理即可,一般情况下,我们为了方便,也可以仅仅设置我们所需要的数据访问层即可。如会员管理模块的Core项目截图如下所示。

如之前的架构设计图,介绍如下所示。

4)基于Web API接口的云会员管理系统

我们先来了解下基于Web API接口的云会员管理系统的总体界面效果。整个系统采用的是混合式的Winform结构,但是数据的来源采用基于Web API的提供方式,也就是我们目前常用到的一种数据提供方式。所有的模块都是基于混合式架构的基础上,对各种接口进行了基类封装,结合代码生成工具,可以生成整体的框架代码:包括Core层业务代码;Web API层控制器代码;以及对Web API调用进行封装的Caller层代码;还有就是最为重要的,Winform界面的动态生成,界面的生成可以省却大量的低效率工作,并且可以绑定一致的访问代码,使得我们开发效率有了质的提高,并且能够和整个框架有更好的整合和一致性。

基于这个基础上我们开发了很多业务系统,并且也为客户向相同领域扩展了很多信息管理系统,拥有了丰富的Winform项目建设经验。下面是云会员管理系统的界面截图。

系列文章如下所示:

Web API应用架构在Winform混合框架中的应用(1)

Web API应用架构在Winform混合框架中的应用(2)--自定义异常结果的处理

Web API接口设计经验总结

Web API应用架构在Winform混合框架中的应用(3)--Winfrom界面调用WebAPI的过程分解

Web API应用架构在Winform混合框架中的应用(4)--利用代码生成工具快速开发整套应用

Web API应用架构在Winform混合框架中的应用(5)--系统级别字典和公司级别字典并存的处理方式