本人在2013年就做过一个WCF的项目,但最近又开始看相关的文章,才发现当年的认识实在太浅显,这里我把WCF的几个重要知识点总结以下。
ABC概念
WCF服务的构成如下图
如你所见,Host即为宿主,因为WCF不能自运行,所以需要依附于宿主,通常可以是Windows程序(Winform/wpf/控制台等.net应用均可)、IIS、Windows服务。
Endpoint
Endpoint是WCF实现通信的核心要素。一个WCF Service由一个Endpoint集合组成,每个Endpoint就是用于通信的入口,客户端和服务端通过Endpoint交换信息。
Endpoint由三部分组成:Address,Binding,Contract。
Address
Address通过一个URI唯一地标识一个Endpoint,并告诉潜在的WCF service的调用者如何找到这个Endpoint。
Binding
Binding实现在Client和Service通信的所有底层细节。比如Client与Service之间传递的Message是如何编码的—— text/XML, binary,MTOM;这种Message的传递是采用的哪种Transport——TCP, Http, Named Pipe, MSMQ; 以及采用怎样的机制解决Secure Messaging的问题——SSL,Message Level Security。
Contract
Contract的主要的作用是定义通信协议,具体Service提供了哪些方法。
WCF一些容易被忽略的特性
跨平台
Wcf服务可以被javascript调用,首先需要对WCF配置文件进行一些配置
<behavior name="ajaxServiceBehavior"> <enableWebScript/> </behavior>
有时还需要给锲约接口添加特性
[WebInvoke(Method = "GET",ResponseFormat = WebMessageFormat.Json)]
调用方法有多种,下面一一介绍。
第一种与调用webservice类似,经过了数天的验证该方法未生效,如果有大神实现该方式希望能赐教,但理论上该方法可行。
1 function myFunction() { 2 var URL = "http://192.168.209.117/UserService.asmx/GetUser"; 3 var Params = "name=leftfist&age=28";//传给WCF的参数 4 var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); 5 xmlhttp.Open("POST",URL, false);//用POST方法,此处可改为GET方法 6 xmlhttp.SetRequestHeader("Content-Type","application/x-www-form-urlencoded"); 7 xmlhttp.SetRequestHeader ("Content-Length",Params.length); 8 xmlhttp.send(Params); 9 var result = xmlhttp.status; 10 //OK 11 if (result == 200) { 12 document.write(xmlhttp.responseText); 13 } 14 xmlhttp = null; 15 }
第二种方法与C#调用WCF服务类似,先添加服务引用
1 <asp:ScriptManager ID="ScriptManager" runat="server"> 2 <Services> 3 <asp:ServiceReference Path="http://192.168.6.47:8080/HelloService.svc" /> 4 </Services> 5 </asp:ScriptManager>
在调用函数中用以下方法即可进行调用,
1 var wcfProxy = new Valsun.Service1(); 2 wcfProxy.GetTestList(id, OnSucceededCallback, OnFailedCallback);
第三种方法是Ajax
1 $.ajax 2 ( 3 { 4 type: 'GET', 5 url: 'Services/RestTestService.svc/GetTest', 6 dataType: 'json', 7 data: 'a=a&b=b', 8 success: function (response, type, xhr) 9 { 10 window.alert('A: ' + response.A); 11 }, 12 error: function (xhr) 13 { 14 window.alert('error: ' + xhr.statusText); 15 } 16 } 17 );
分布式事务
WCF服务的执行可添加事务,也可进行服务传递,通过在方法上添加属性TransactionScopeRequired可实现对该方法启动事务,例如
1 [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)] 2 public bool Add(Model.User user, Model.Shop shop) 3 { 4 int shopID; 5 int UserID; 6 7 if (Add(user, out UserID)) //数据库插入方法1 8 { 9 shop.UserID = UserID; 10 11 return Add(shop, out shopID); //数据库插入方法2 12 } 13 14 return false; 15 }
在上述方法中,只有代码正确执行到return,方法1和方法2的结果才能正确提交,否则将会回滚。
如果在配置文件中添加以下代码,还能实现客户端事务到服务端的传递,
<bindings> <wsHttpBinding> <binding name="WSHttpBinding_IService1" transactionFlow="true" />
</wsHttpBinding> </bindings>
并在WCF服务方法上添加
[TransactionFlow(TransactionFlowOption.Allowed)]
如果在客户端将服务的调用放在一个事务里,如下所示
1 using (TransactionScope ts = new TransactionScope()) 2 { 3 //调用服务 4 using (TestService.Service1Client service = new TestService.Service1Client()) 5 { 6 service.AddData_1("1"); 7 } 8 Console.WriteLine("第一次调用:成功插入一条数据"); 9 10 //重新去调用WCF服务 11 using (TestService.Service1Client service2 = new TestService.Service1Client())
{ 12 //WCF中的AddData_2会报错 13 service2.AddData_2("2"); 14 } 15 ts.Complete(); 16 } 17
此时,如果在客户端的调用方法的事务中出现报错,服务端的方法AddData_1方法AddData_2 即使已执行也会回滚。
消息队列
MSMQ的实现原理是:消息的发送者把自己想要发送的信息放入一个容器,然后把它保存到一个系统公用空间的消息队列中,本地或异地的消息接收程序再从该队列中取出发给它的消息进行处理。
MSMQ中主要有两个概念
- 一个是消息Message:Message是通信双方需要传递的消息,它可以是文本、图片、视频等。消息包含发送和接收者的标识,只有指定的用户才能取得消息。
- 一个是队列Queue:用来保存消息的存储空间。
消息队列的优缺点
- 采用消息队列的好处是:由于是异步通信,无论是发送方还是接收方都不同等待对方返回成功消息,就可以执行余下的代码,大大提高了处理的能力;在信息传递过程中,具有故障恢复能力;MSMQ的消息传递机制使得通信的双方具有不同的物理平台成为可能。
- 消息队列缺点是:不适合Client需要Server端实时交互情况,大量请求时候,响应可能延迟。对于客户端,必须是Windows系统。可以通过连接器跟其他的非微软技术集成。
首先呢得先在服务器新建一个msmq队列
MessageQueue.Create(@".\Private$\LMXQueue ")
部署服务时需指定消息队列
using (ServiceHost host =new ServiceHost(typeof(MSMQOrderService), new Uri("net.msmq://localhost/Private/LMXQueue"))) { NetMsmqBinding binding = new NetMsmqBinding(NetMsmqSecurityMode.None); binding.ExactlyOnce = false; binding.Durable = true; host.AddServiceEndpoint( typeof(IMSMQService).FullName, binding, ""); host.Open(); Console.Read(); }
在客户端调用时也需指定队列
NetMsmqBinding binding = new NetMsmqBinding(NetMsmqSecurityMode.None); binding.ExactlyOnce = false; binding.Durable = true; ChannelFactory<IMSMQService> channel = new ChannelFactory<IMSMQService>( //这里面解释一下:localhost代表是本机服务器,Private字面上是私有,这里面表示是“消息队列”里面的“专用队列”,“LMXQueue”是我们专用队列的一个类似“消息组”的一个名称。 binding, new EndpointAddress("net.msmq://localhost/Private/LMXQueue")); IMSMQService client = channel.CreateChannel();
至此有关WCF的一些容易遗漏的重要知识点就介绍完毕了,希望对大家有帮助。