利用WCF技术降低系统之间的耦合度

为了降低本系统各个组件之间的耦合度,本系统将BLL层采用WCF技术发布为Web Service,以供UI层调用。

  前面我们已经介绍过,为什么UI层不直接调用BLL层,而是要经过UI->Service.Wrapper->Service.Host->Service->BLL这样绕一大圈的方式来调用BLL层呢?

  笔者认为至少有以下几个原因:

  第一,直接调用会导致系统耦合度太高,任何后台的改动都会导致前台需要重新编译、发布,而这样做了之后,只要Contract不改变,则前台不用做任何改动;

  第二,这样做了之后,比较适合SOA的理念,系统的扩展性、交互性和灵活性大大提高;

  第三,直接调用会导致Solution中会有过多的Project,编译非常慢,导致开发人员的时间浪费过多。

  下面让我们来看看WCF是如何在系统中得到应用的。

  首先,我们需要事先实现一个Contract,让相关的各个组件共同遵守。一个Contract,实际上就是一个interface,为了使它能用于WCF,我们需要添加ServiceContract、OperationContract标识。如果该interface用到了一些自定义的Info类,则需要使用ServiceKnownType一一指明。

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 1 using System;
 2 using System.Collections;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Text;
 6 using System.ServiceModel;
 7 using System.Runtime.Serialization;
 8 using Eallies.OA.Service.Contract.Fault;
 9 using Eallies.OA.Info;
10 
11 namespace Eallies.OA.Service.Contract
12 {
13     [ServiceContract]
14     [ServiceKnownType(typeof(EmployeeInfo))]
15     public interface IEmployeeContract
16     {
17         [OperationContract]
18         [FaultContract(typeof(FaultInfo))]
19         void SaveEmployee(EmployeeInfo employeeInfo);
20 
21         [OperationContract]
22         IList GetEmployees();
23     }
24 }

  另外,FaultContract用于WCF的错误处理,我们可以在配置文件中将includeExceptionDetailInFaults设为true,这样我们就能将错误的详细信息通过Web Service传到UI层。而FaultInfo则是一个简单的类,用于保存需要传递的消息,如错误信息。

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
 1 <?xml version="1.0"?>
 2 <configuration xmlns="[url]http://schemas.microsoft.com/.NetConfiguration/v2.0[/url]">
 3   <system.serviceModel>
 4     <behaviors>
 5       <serviceBehaviors>
 6         <behavior name="metadataSupport">
 7           <serviceDebug includeExceptionDetailInFaults="true" />
 8           <serviceMetadata httpGetEnabled="true" />
 9         </behavior>
10       </serviceBehaviors>
11     </behaviors>
12   </system.serviceModel>
13 </configuration>

  之后,我们就可以用一个继承于Contract的类将BLL层进行包装。

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 1 using System;
 2 using System.Collections;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Text;
 6 using Eallies.OA.Service.Contract;
 7 using Eallies.OA.Info;
 8 using Eallies.OA.BLL;
 9 
10 namespace Eallies.OA.Service
11 {
12     public class EmployeeService : IEmployeeContract
13     {
14         #region IEmployeeContract Members
15 
16         public void SaveEmployee(EmployeeInfo employeeInfo)
17         {
18             try
19             {
20                 EmployeeBLL bll = new EmployeeBLL();
21                 bll.SaveEmployee(employeeInfo);
22             }
23             catch
24             {
25                 throw;
26             }
27         }
28 
29         public IList GetEmployees()
30         {
31             try
32             {
33                 EmployeeBLL bll = new EmployeeBLL();
34                 return bll.GetEmployees();
35             }
36             catch
37             {
38                 throw;
39             }
40         }
41 
42         #endregion
43     }
44 }

完成之后的这样一个类我们就可以采用WCF技术Host到合适的应用程序中了。本系统将WCF给Host到IIS中了。要做到这点,只需要创建一个ASP.NET Web Service Application,将该项目发布为虚拟目录。

  具体的类则是通过svc文件来完成Host的。其代码则非常简单:

双击代码全选
1
1 <%@ ServiceHost Language="C#" Debug="true" Service="Eallies.OA.Service.EmployeeService" %>

  这样一来,该BLL层的所有函数就发布成Web Service了。不论客户端的形式是怎样的,我们都可以调用这个Web Service来完成客户端的功能。当然,为了使客户端的调用更为简单,我们需要将Web Service进行进一步的包装。这个过程可以使用Microsoft自带的svcutil.exe工具来完成。

代码全选
1
1 svcutil.exe "http://localhost/Eallies.OA.Service.Host/EmployeeHost.svc?wsdl" /o:"..Eallies.OA.Service.WrapperEmployeeWrapper.cs" /r:"..Eallies.OA.InfobinDebugEallies.OA.Info.dll" /r:"..Eallies.OA.Info.EnumbinDebugEallies.OA.Info.Enum.dll" /r:"..Eallies.OA.Service.Contract.FaultbinDebugEallies.OA.Service.Contract.Fault.dll" /n:*,Eallies.OA.Service.Wrapper /noConfig

  值得注意的是,如果我们的Web Service引用了其它的类,则svcutil.exe工具会帮我们将所有的这些类重新生成一次,当然,这不是我们期望的。为此,我们采用参数/r的方式将需要引用的各个dll传入,这样就可以避免svcutil.exe工具自动生成了。另外/r参数可以多次指定,这为多个dll的引用提供了可能。

上一篇:js面试题知识点全解(一作用域和闭包)


下一篇:微擎系统BUG漏洞解决方法汇总