一.介绍
WCF4.0为开发者带来了很多新的特性.能与工作流服务高度整合,WCF REST服务更友好.总之WCF4.0在服务端与客户端通信中给我们带来了更多的选项,随下是4.0中的新特性:
1.动态服务和端点发现
2.中间路由模式(路由服务)
3.发现通知
4.简化配置
5.协议绑定和容错处理
6.默认端点
7.REST URI更友好
8.默认协议映射
9.开启了WCF REST服务的帮助页面
在本篇文章我们将探索WCF4.0中令人激动的3个新特性.其他的特性我们将在随下的文章中描述.本篇文章我们将讨论:
1.端点发现
2.默认端点
3.开启了WCF REST服务的帮助页面
二.问题
服务端暴露服务端点,客户端通过端点引用服务,当服务端绑定发生根本性的变化,那么客户端不得不去更新服务.这将是一个很繁重的任务.去解决这个问题,我们用一个叫端点发现或者动态服务的机制.
用技术的话说,WCF4.0支持WS-Discovery标准或者协议.
三.WS-Discovery标准
WS-Discovery是在UDP之上发出SOAP消息的多播协议
WS-Discovery是一个标准,它定义了轻量级的机制基于多播消息发现服务.当它初始化的时候允许服务发送Hello的通知消息,当它从网络中移除的时候发送一个By消息.
客户端通过发送探测消息到服务,服务回应与探测匹配的信息,这样客户端就能找到服务
客户端能够找到改变端口的服务,通过发出一个解析消息到服务,服务回应解析匹配消息
我们能可以说WS-Discovery是基于UDP的多播消息交换.一个客户端通过发信息去找到网络上有效的服务
四.WCF Service Discovery API
WCF提供WCF Discovery API.这个API帮助服务发布以及客户端在网络上找到服务
模型:
托管模式
在托管模式中有一个叫发现代理的集中服务器,服务用来发布,客户端用来检索有效的服务信息.
当一个新的服务开启,它发送一个通知消息给发现代理.
发现代理保存有效的服务信息
当一个客户端搜索服务的时候,它发送一个探测请求到发现代理,发现代理检测是否有相匹配的服务.如果有匹配,那么发现代理发送一个匹配探测响应客户端
客户端用那代理返回的服务信息直接连接服务
点对点模式
没有集中服务器,服务通知和客户请求用多播的方式发送
如果服务配置在启动的时候发送一个Hello的通知,客户端不得不监听这个通知,并且做出相应的处理
当客户端发送一个探测请求,每个服务接收到这个请求后都去检测是否匹配探测请求的条件,如果匹配就回应一个探测匹配消息给客户端,
五.例子
在下面例子中我们创建一个基本的服务和一个客户端,客户端用点对点模式发现服务并使用它.
去运行如下例子你需要安装Visual Studio 201
去实现一个可发现的服务,服务发现行为必须添加到服务主机,发现端点必须添加到特定的监听位置
打开VS2010,选择WCF Service应用程序项目模板创建一个新的项目,删除Visual Studio生成的所有代码
IService1.cs实现如下:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Runtime.Serialization;
5: using System.ServiceModel;
6: using System.ServiceModel.Web;
7: using System.Text;
8: namespace WcfService1
9: {
10: [ServiceContract]
11: public interface IService1
12: {
13: [OperationContract]
14: string GetMessage(string msg);
15: }
16: }
Service1.cs:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Runtime.Serialization;
5: using System.ServiceModel;
6: using System.ServiceModel.Web;
7: using System.Text;
8: namespace WcfService1
9: {
10: public class Service1 : IService1
11: {
12: public string GetMessage(string msg)
13: {
14: return msg;
15: }
16: }
17: }
上面的例子示范了一个简单的服务契约和它的实现
打开Web.config,修改System.ServiceModel元素,效果如下:
1: <<>system.serviceModel>
2: <<>services>
3: <<>service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior">
4: <<>endpoint address="" binding="wsHttpBinding" contract="WcfService1.IService1">
5: <<>identity>
6: <<>dns value="localhost"/>
7: identity>
8: endpoint>
9: <<>endpoint name ="udpDiscovery" kind="udpDiscoveryEndpoint" />
10: <<>endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
11: service>
12: services>
13: <<>behaviors>
14: <<>serviceBehaviors>
15: <<>behavior name="WcfService1.Service1Behavior">
16: <<>serviceMetadata httpGetEnabled="true"/>
17: <<>serviceDebug includeExceptionDetailInFaults="false"/>
18: <<>serviceDiscovery />
19: behavior>
20: serviceBehaviors>
21: behaviors>
22: system.serviceModel>
1.上面代码中我们添加了一个新的端点
2.新添加的端点的类别是udpDiscoveryEndpoint
3.这个端点用来找到服务
4.服务发现行为也被添加
按下F5运行服务,这个服务将托管在内嵌的ASP.NET WEB服务器中
现在添加一个控制台项目到解决方法,引用System.ServiceModel.Discovery.dll到控制台项目中,添加名称空间System.ServiceModel.Discovery
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using ConsoleApplication1.ServiceReference1;
6: using System.ServiceModel;
7: using System.ServiceModel.Discovery;
8: namespace ConsoleApplication1
9: {
10: class Program
11: {
12: static void Main(string[] args)
13: {
14: DiscoveryClient discoverclient = new DiscoveryClient(new UdpDiscoveryEndpoint());
15: FindResponse response = discoverclient.Find(new FindCriteria(typeof(IService1)));
16: EndpointAddress address = response.Endpoints[0].Address;
17: Service1Client client = new Service1Client(new WSHttpBinding(), address);
18: string str = client.GetMessage("Hello WCF 4 ");
19: Console.WriteLine(str);
20: Console.ReadKey(true);
21: }
22:
23: }
24: }
六.默认端点和协议映射
在WCF 3.x时代在配置文件中配置端点是一件很繁琐的事情,在WCF4中如果没有配置任何端点,那么会有一个默认端点与服务关联.随下例子将演示默认端点的使用:
首先创建一个service应用程序,然后创建两个契约
IService1.cs:
1: [ServiceContract]
2: public interface IService1
3: {
4:
5: [OperationContract]
6: string GetData();
7:
8: }
1: [ServiceContract]
2: public interface IService2
3: {
4:
5: [OperationContract]
6: string GetMessage();
7:
8: }
实现服务:
1: public class Service1 : IService1, IService2
2: {
3:
4: public string GetData()
5: {
6: return "Hello From Iservice1 " ;
7: }
8: public string GetMessage()
9: {
10:
11: return " Hello From Iservice2";
12: }
13: }
我们现在创建一个控制台程序托管,引用服务:
1: ServiceHost host = new ServiceHost(typeof(WcfService1.Service1),
2: new Uri("http://localhost:8080/service"),
3: new Uri("net.tcp://localhost:8081/service"));
到目前为止,我们没有创建任何的服务端点,因此ServiceHost将为两个地址创建默认的端点
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.ServiceModel;
6: using System.ServiceModel.Description;
7: using WcfService1;
8: namespace ConsoleApplication1
9: {
10: class Program
11: {
12: static void Main(string[] args)
13: {
14: ServiceHost host = new ServiceHost(typeof(WcfService1.Service1),
15: new Uri("http://localhost:8080/service"),
16: new Uri("net.tcp://localhost:8081/service"));
17: host.Open();
18: foreach (ServiceEndpoint se in host.Description.Endpoints)
19: {
20: Console.WriteLine("Address: " + se.Address.ToString() +
21: " Binding: " + se.Binding.Name +
22: " Contract :"+ se.Contract.Name);
23: }
24: Console.ReadKey(true);
25: }
26: }
27: }
如果我们添加了端点,那么WCF将不支持默认端点
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.ServiceModel;
6: using System.ServiceModel.Description;
7: using WcfService1;
8: namespace ConsoleApplication1
9: {
10: class Program
11: {
12: static void Main(string[] args)
13: {
14: ServiceHost host = new ServiceHost(typeof(WcfService1.Service1),
15: new Uri("http://localhost:8080/service"),
16: new Uri("net.tcp://localhost:8081/service"));
17: host.AddServiceEndpoint(typeof(IService1),
18: new WSHttpBinding(),
19: "myBinding");
20: host.Open();
21: foreach (ServiceEndpoint se in host.Description.Endpoints)
22: {
23: Console.WriteLine("Address: " + se.Address.ToString() +
24: " Binding: " + se.Binding.Name +
25: " Contract :"+ se.Contract.Name);
26: }
27: Console.ReadKey(true);
28: }
29: }
30: }
所以,如果我们没有配置任何的端点,WCF创建的默认端点将是basicHttpBinding
类型net.tcp类型将被映射为netTcpBinding
如我们想改变这个,我们可以改变默认映射:
1: <<>protocolMapping>
2: <<>add scheme="http" binding="wsHttpBinding" bindingConfiguration="" />
3: protocolMapping>
随着上面的改变,如果我们不创建任何端点,WCF将创建默认端点,绑定wsHttpBinding,去演示这个,我们创建一个WCF服务应用程序,然后创建服务契约:
1: [ServiceContract]
2: public interface IService1
3: {
4: [OperationContract]
5: string GetData();
6: }
实现服务:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Runtime.Serialization;
5: using System.ServiceModel;
6: using System.ServiceModel.Web;
7: using System.Text;
8: namespace WcfService1
9: {
10: public class Service1 :IService1
11: {
12: public string GetData( )
13: {
14: return "Hello From Iservice1 ";
15:
16: }
17: }
18: }
现在我们添加控制台程序,引用服务,在控制台程序中添加app.config:
1: "1.0" encoding="utf-8" ?>
2:
3:
4:
5: "http" binding ="wsHttpBinding" bindingConfiguration ="" />
6:
7:
8:
下面我们去取默认端点:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.ServiceModel;
6: using System.ServiceModel.Description;
7: using WcfService1;
8: namespace ConsoleApplication1
9: {
10: class Program
11: {
12: static void Main(string[] args)
13: {
14: ServiceHost host = new ServiceHost(typeof(WcfService1.Service1),
15: new Uri("net.tcp://localhost:8081/service"));
16: host.Open();
17: foreach (ServiceEndpoint se in host.Description.Endpoints)
18: {
19: Console.WriteLine("Address: " + se.Address.ToString() +
20: " Binding: " + se.Binding.Name +
21: " Contract :"+ se.Contract.Name);
22: }
23: Console.ReadKey(true);
24: }
25: }
26: }
从上面我们可以看出我们已经修改了默认映射
七.开启WCF REST服务的帮助页面
首先我们创建一个项目,选择控制台程序作为项目类型
添加一个类库项目到解决方案
在两个项目中添加如下的引用:
下一步我们创建服务契约:
在类库项目中删除Class1.cs,添加一个接口文件,标记接口为public,并添加服务契约属性,定义两个操作契约,增加一个WebGet属性到第一个,添加
WebInvoke属性到第二个
IService.cs
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.ServiceModel;
6: using System.ServiceModel.Web;
7: namespace Contracts
8: {
9: [ServiceContract]
10: public interface IService
11:
12: {
13: [OperationContract]
14: [WebGet]
15: string GetMessage(string inputMessage);
16: [OperationContract]
17: [WebInvoke]
18: string PostMessage(string inputMessage);
19:
20: }
21: }
实现契约,在控制台下添加类文件:
Service.cs
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using Contracts;
6: namespace SelfHostedRESTService
7: {
8: public class Service :IService
9: {
10: public string GetMessage(string inputMessage)
11: {
12: return "Calling Get for you " + inputMessage;
13:
14: }
15: public string PostMessage(string inputMessage)
16: {
17: return "Calling Post for you " + inputMessage;
18: }
19: }
20: }
1: WebServiceHost host = new WebServiceHost(typeof(Service), new Uri("http://localhost:800));
添加一个服务端点:
1: ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), "");
随着帮助页的开启,添加一个托管服务行为:
1: host.Description.Endpoints[0].Behaviors.Add(new WebHttpBehavior { HelpEnabled = true });
众所周知,REST服务用webHttpBindding
,我们在这里开启帮助页:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.ServiceModel;
6: using System.ServiceModel.Description;
7: using System.ServiceModel.Web;
8: using Contracts;
9: namespace SelfHostedRESTService
10: {
11: class Program
12:
13: {
14: static void Main(string[] args)
15:
16: {
17: WebServiceHost host = new WebServiceHost(typeof(Service), new Uri("http://localhost:8000"));
18: ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), "");
19: host.Description.Endpoints[0].Behaviors.Add(new WebHttpBehavior { HelpEnabled = true });
20: host.Open();
21: Console.WriteLine("Service is up and running");
22: Console.WriteLine("Press enter to quit ");
23: Console.ReadLine();
24: host.Close();
25:
26: }
27: }
28: }
按下F5,运行服务,输出效果如下:
如果服务运行正常,我们通过输入http://localhost:8000/help测试帮助页
下面的文章我们将探索其他的WCF4.0特性