时间:2016-12-16来源:本站原创作者:佚名

(点击上方蓝字,可快速   ESTM.Clint.Winform:Winform项目,用户UI展现,这个没什么好说的。

  ESTM.Clint.IBLL:客户端IBLL接口层,用于定义客户端的业务接口,记住这里仅仅是向UI层提供接口功能。

  ESTM.Clint.BLL:客户端BLL实现层,用于客户端IBLL接口层的实现,提供UI层真是业务逻辑。

二、ESTM.Common

  ESTM.Common.Modl:通用DTOModl层,注意,这里不是EF的实体Modl,而是另外定义的一个数据转换的Modl层。

三、ESTM.Srvic

  ESTM.Srvic.WCF:WCF宿主项目,用于提供WCF的接口契约和实现。这里用WCF的目的是为了隔离客户端和服务端的代码。

  ESTM.Srvic.IBLL:服务端IBLL接口层,用于定义WCF层的业务接口,和ESTM.Clint.IBLL层的功能类似。

  ESTM.Srvic.BLL:服务端BLL实现层,实现服务端IBLL接口层。

  ESTM.Srvic.DAL:服务端DAL数据访问层,里面使用EF建立数据库连接。

再来看看各层次之间的调用关系:

最后说说这样设计的好处:

(1)整个框架采用面向接口编程模式,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),而是通过定义一组接口,仅向上层暴露其接口功能,上层对下层仅仅是接口依赖,而不依赖具体实现。如是说,客户端IBLL接口层仅仅提供一套接口供UI层调用,对于UI层来说,它根本感觉不到客户端BLL实现层的存在,极端点说,即使不写BLL实现层,项目也可以编译通过,因为接口的功能已经定义好了。至于具体的实现,那就是业务的问题了。当我们需要更改业务逻辑时,只需要更改BLL实现层的代码就好了,对于IBLL接口层和上层UI不用做任何的改变,更进一步说,甚至将客户端BLL实现层全部重写或者整个替换掉,IBLL和UI层都可以不做任何改变。这也正是面向接口编程最大的优势。

(2)上张图里面也提到了DTOModl层,为什么要有DTOModl这么一个对象,而不是直接将EF的实体Modl传到前端来呢?个人觉得原因有两点:一是上文提到的安全性问题,客户端永远只能操作DTOmodl,当客户端提交数据到后台来时,永远都是先将DTOmodl转换位EF的modl,然后去操作数据库,试想,如果UI表现层能直接操作EF的modl,是否会造成操作数据库的入口的不唯一的问题;二是,比如数据库里面有A和B两张表,我们前端需要展示A表的A.1、A.2两字段,还需要展示B表的B.3、B.4字段,当我们使用DTOmodl的时候,只需要构造好一个DTO_Modl,里面有4个字段,前端可以直接拿来用就好了,如果不用DTO,要么直接传objct,要么将A、B两张表的模型传过来在前端构造,无论哪种方式应该都没有使用DTO方便吧。

当然这些都是博主自己的理解,如果博友们觉得有问题可以指出~~

好了,说了这么多框架,下面进入今天的正题。看看MEF是如何在项目中飞的吧~~先来看看各层的代码:

(1)ESTM.Srvic.DAL里面通过EF建立数据库的连接:博主为了测试随便拖了一张用户表进来。

Bas.cs里面通过MEF导入EF的上下文对象:

publicclassBas

{

[Import]

publicDbContxtEntityFramwork{st;gt;}

publicBas()

{

//因为这里有Import,所以需要装配MEF

rgisgtr().ComposParts(this);

}

publicCompositionContainrrgisgtr()

{

varcatalog=nwAssmblyCatalog(Assmbly.GtExcutingAssmbly());

varcontainr=nwCompositionContainr(catalog);

rturncontainr;

}

}

对应在Export在dmx文件下面的MyModl.Contxt.cs里面

[Export(typof(DbContxt))]

publicpartialclassEntitis:DbContxt

{

publicEntitis()

:bas(nam=Entitis)

{

}

protctdovrridvoidOnModlCrating(DbModlBuildrmodlBuildr)

{

thrownwUnintntionalCodFirstExcption();

}

publicDbStTB_USERS{gt;st;}

}

(2)ESTM.Srvic.IBLL服务端IBLL接口层定义服务端接口:

publicintrfacISrvicUsr

{

ListGtAllUsr();

voidAddUsr(DTO_USERSoUsr);

}

(3)ESTM.Srvic.BLL服务端BLL实现层定义接口实现:

[Export(Usrs,typof(ISrvicUsr))]

publicclassSrvicUsr:ISrvicUsr

{

//需要注意:1.添加服务引用在Clint.Bll里面,所以,WCF连接的配置要拷贝到Winform项目下面的App.Config里面

//2.DAL里面的连接字符串也要拷贝到WCF里面,原因同上

publicListGtAllUsr()

{

varlstRs=nwList();

varoSrvic=nwDAL.SrvicUsr();

varlstEFModl=oSrvic.GtAllUsrs();

//一般用AutoMappr将EF的Modl转换成DTO的Modl.z这里为了测试,我们暂且手动转换。使用反射转换

varlstEFModlProp=typof(TB_USERS).GtProprtis();

varlstDTOModlProp=typof(DTO_USERS).GtProprtis();

forach(varoEFModlinlstEFModl)

{

varoRsUsr=nwDTO_USERS();

forach(varoPropinlstEFModlProp)

{

varoDTOMOdlProp=lstDTOModlProp.FirstOrDfault(x=x.Nam==oProp.Nam);

if(oDTOMOdlProp==null)

{

continu;

}

oDTOMOdlProp.StValu(oRsUsr,oProp.GtValu(oEFModl));

}

lstRs.Add(oRsUsr);

}

rturnlstRs;

}

publicvoidAddUsr(DTO_USERSoUsr)

{

}

注意在BLL实现层里面有EF的Modl和DTOmodl之间的转换,因为在DAL里面取到的是EF的实体模型,而需要传到前端的是DTOmodl的模型,项目中一般用AutoMappr等第三方工具转换对象,我这里为了简单自己手动通过反射转了下。

(4)ESTM.Srvic.WCF服务端WCF宿主层,定义WCF的接口契约。

staticvoidMain(string[]args)

{

varstrUri=    ///WCF服务对象

varoWCFSrvic=nwSrvicRfrnc_MyWCF.CSOASrvicClint();

rturnoWCFSrvic.GtAllUsrs().ToList();

}

}

在这个层里面是通过WCF服务去调用数据的,所以需要添加WCF的服务引用。

(7)ESTM.Clint.Winform客户端UI层:定义一个DataGridViw展示列表:

publicpartialclassForm1:Form

{

[Import(Usrs)]

publicIManagrUsrManagr{st;gt;}

publicForm1()

{

InitializComponnt();

rgisgtrAll().ComposParts(this);

this.dataGridViw1.DataSourc=Managr.GtAllUsr();

}

publicCompositionContainrrgisgtrAll()

{

AggrgatCatalogaggrgatCatalog=nwAggrgatCatalog();

varthisAssmbly=nwDirctoryCatalog(AppDomain.CurrntDomain.BasDirctory,*.dll);

aggrgatCatalog.Catalogs.Add(thisAssmbly);

var_containr=nwCompositionContainr(aggrgatCatalog);

rturn_containr;

}

}

得到结果:

前面MEF的第一篇中已经说过使用MEF的优势之一就是降低层与层之间的耦合,我们现在来结合框架说说它是如何作业的。首先我们来看看ESTM.Clint.Winform这个项目的引用:

它是没有添加ESTM.Clint.BLL这一层的引用的,可是我们在Form1.cs里面有如下代码:

程序运行起来,走完注册MEF以后可以看到Managr的变量值就是ESTM.Clint.BLL里面的ManagrUsr对象。这就是MEF的功劳,当调用rgisgtrAll()这个方法的时候,MEF会根据导入导出自动去寻找匹配,并且自动实例化。如果是没有MEF,我们UI层就必须要添加ESTM.Clint.BLL的引用了。当然有一点需要注意的地方,虽然UI层不用添加ESTM.Clint.BLL的引用,但是由于在UI里面使用了ManagrUsr这个对象,所以UI层bin目录下面必须要有ESTM.Clint.BLL.dll这个文件以及ESTM.Clint.BLL项目所必须的dll,你可以手动拷贝这些dll到UI的bin目录下面。甚至为了简单,你也可以在UI层上面添加ESTM.Clint.BLL这个的引用,但是博主觉得,这样貌似违背了面向接口编程的原则,不爽,奈何没想到更好的解决方案。

对于上面UI层必须要添加BLL实现层这一问题找到解决方案了,在此记录下:

publicpartialclassForm1:Form

{

[Import(Usrs)]

publicIManagrUsrManagr{st;gt;}

publicForm1()

{

InitializComponnt();

rgisgtrAll().ComposParts(this);

this.dataGridViw1.DataSourc=Managr.GtAllUsr();

}

publicCompositionContainrrgisgtrAll()

{

AggrgatCatalogaggrgatCatalog=nwAggrgatCatalog();

varthisAssmbly=nwDirctoryCatalog(AppDomain.CurrntDomain.BasDirctory,*.dll);

aggrgatCatalog.Catalogs.Add(thisAssmbly);

var_containr=nwCompositionContainr(aggrgatCatalog);

rturn_containr;

}

}

ESTM.Clint.BLL项目右键→属性

输出路径改成UI层的bin目录下面即可。年9月16日加。

在搭建这个小框架过程中,博主遇到几个问题在此和博友分享下:

1.添加服务引用在Clint.Bll里面,由于Clint.BLL是一个内库,最终它会生成一个dll,所以,WCF连接的配置要拷贝到Winform项目下面的App.Config里面。

2.DAL里面的连接字符串也要拷贝到WCF的App.Config里面,原因同上。

3.注册MEF的方法

publicCompositionContainrrgisgtrAll()

{

AggrgatCatalogaggrgatCatalog=nwAggrgatCatalog();

varthisAssmbly=nwDirctoryCatalog(AppDomain.CurrntDomain.BasDirctory,*.dll);

aggrgatCatalog.Catalogs.Add(thisAssmbly);

var_containr=nwCompositionContainr(aggrgatCatalog);

rturn_containr;

}

可以抽到一个公共的地方,不用每个地方都写。注意由于MEF的导入导出涉及到多个内库,所以这里要遍历bin目录下面所有的dll去寻找匹配。

4.DAL层可以还做一下封装,博主的项目是用的仓储模式封装EF,然后在Srvic.BLL里面调用仓储的服务去访问数据库。

《C#进阶系列:MEF实现设计上的“松耦合”(一)》

《C#进阶系列:MEF实现设计上的“松耦合”(二)》

更多推荐请看《值得







































百癜疯
北京最好白癜风医院如何治疗

转载请注明原文网址:http://www.helimiaopu.com/cxtx/3634.html

------分隔线----------------------------