一.WCF创建:
常规的创建WCF服务是通过SOAP传输的,很多网站开发人员想放弃使用XML而使用JSON,这个时候可以参照:http://www.cnblogs.com/zhili/p/WCFRestService.html?utm_source=tuicool&utm_medium=referral
WCF 3.5中对Rest服务做了支持。WCF在System.ServiceModel.Web组件中新增了ResT编程,Rest编程有两个主要的新属性: WebGetAttribute 和 WebInvokeAttribute ,还有一个URI模板机制,帮助你声明每种方法响应使用的URI和动词。.NET Framework还提供了一个新的绑定(WebHttpBinding)和新的行为(WebHttpBehavior),此外,还提供了WebServiceHost和WebServiceHostFactory类来对Rest服务进行支持。
以前我们都是把WCF服务抽象为操作的概念,而Rest最早是由Roy Thomas Fielding 在他的博士论文( “体系结构风格和基于网络软件体系的设计 ”)中提出的。Rest服务是将服务抽象为资源,每个资源都有一个唯一的统一资源标识符(URI),我们不再是通过调用操作的方式与服务进行交互了,而是通过HTTP标准动词(GET、POST、PUT和DELETE)的统一接口来完成。总之一句话概括,Rest服务换了一种思维方式,把服务也当成一种资源,通过Get、Post、Put和Delete这些HTTP动词来进行交互。这样,问题就来了,Rest服务具有什么好处呢?即我们为什么要去关注Rest和实现它呢?
Rest优势就在于其使用极其简单,Rest服务要求很少的编码工作量,可以减少很多不必要的工作。Rest服务主要有以下优点:
- 无需引入SOAP消息传输层,轻量级和高效率的HTTP格式可直接被应用。
- 可以轻易地在任何编程语言中实现,尤其是在JS中。使用SOAP的服务与JS交互非常繁琐,而使用Rest服务与JS交互非常简单。
- 可以不使用任何编程语言就能访问服务,而只需要使用Web浏览器即可。
- 更好的性能和缓存支持。使用Rest服务可以改善响应时间和改善用户体验。
- 可扩展性和无状态性。Rest服务基于HTTP协议,每个请求都是独立的,一旦被调用,服务器不保留任何会话,这样可以更具响应性,通过减少通讯状态的维护工作来提供服务的可扩展性。
Rest和SOAP比较:
REST目前只基于HTTP和HTTPS协议,而SOAP可支持任何传输协议,包括HTTP/HTTPS、TCP、SMTP等协议。另外Rest服务除了能使用XML作为数据承载外,还有JSON,RSS和 ATOM 形式。
Rest与SOAP对应的比较如下所示:
- SOAP是一种工业标准,面对的应用需求时RPC(远程过程调用),而Rest面对的应用需求是分布式Web系统。
- Rest服务强调数据,请求和响应消息都是数据的封装,而SOAP服务更强调接口,SOAP消息封装的是过程调用。Rest是面向资源的,而SOAP是面向接口的。
- Rest架构下,HTTP是承载协议,也是应用协议,而SOAP架构下,HTTP只是承载协议,SOAP才是应用协议。
那在什么情况下使用Rest,什么情况下使用SOAP呢?这要看具体的实际情况。具体应用场景如下所示:
- 远程调用用SOAP。如果服务是作为一种功能提供,客户端调用服务是为了执行一个功能,用SOAP,比如常见的需求是认证授权。而数据服务用Rest。
- 要更多的考虑非功能需求时使用SOAP,如需考虑安全、传输和协议等需求的情况下。
- 低带宽、客户端的处理能力受限的场合可以考虑使用Rest。如在PDA或手机上消费服务。
第一步:创建Rest服务接口和实现。
[ServiceContract(Namespace ="http://www.cnblogs.com/zhili/")]//也可以不加直接通过服务url作为地址 public interface IEmployees { // 契约操作不再使用操作契约的方式来标识,而是使用WebGetAttribute特性来标识,从而表明该服务是Rest服务 //[OperationContract]//Rest可以不适用OperactionContract标识 [WebGet(UriTemplate = "all")] //[WebGet(UriTemplate = "all", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)] IEnumerable<Employee> GetAll(); [WebGet(UriTemplate = "{id}")] ////[WebGet(UriTemplate = "MySplit/{id}", Method = "POST" ,ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)] Employee Get(string id); [WebInvoke(UriTemplate="/", Method="PUT")] void Create(Employee employee); [WebInvoke(UriTemplate = "/", Method = "POST")] void Update(Employee employee); [WebInvoke(UriTemplate = "/", Method = "DELETE")] void Delete(string id); } //[Serializable],如果不是使用SOAP协议,可以不加 [DataContract(Namespace = "http://www.cnblogs.com.zhili/")] public class Employee { //注意:对外访问的数据属性必须保证其get和set都是public,不然,数据传输不了的 [DataMember] public string Id { get; set; } [DataMember] public string Name { get; set; } [DataMember] public string Department { get; set; } }
从上面代码可以看出,Rest服务不再使用OperactionContract的方式来标识操作了,此时在Rest架构下,每个操作都被当做一种资源对待,所以这里的操作使用了WebGetAttribute特性和WebInvokeAttribute来标识。下面具体看看契约的具体实现,即Rest服务的实现代码。实现服务的代码就不加了。
第二步:实现Rest服务宿主。这里还是使用控制台程序来作为宿主程序
namespace RestServiceHost { class Program { static void Main(string[] args) { // Rest服务使用WebServiceHost类来为服务提供宿主 using (WebServiceHost webHost = new WebServiceHost(typeof(EmployeesService))) { webHost.Opened += delegate { Console.WriteLine("Rest Employee Service 开启成功!"); }; webHost.Open(); Console.Read(); } } } }
对应的配置文件内容如下所示:
<configuration> <system.serviceModel> <services> <service name="WCFContractAndService.EmployeesService"> <!--这里Rest服务只能使用WebHttpBinding来作为绑定--> <endpoint address="http://localhost:9003/employeeService" binding="webHttpBinding" contract="RestContract.IEmployees"/> </service> </services> </system.serviceModel> </configuration>
第三步:实现Rest服务调用客户端。这里通过通道工厂的方式来创建代理对象的
namespace WCFClient { class Program { static void Main(string[] args) { using (ChannelFactory<IEmployees> channelFactory = new ChannelFactory<IEmployees>("employeeService")) { // 创建代理类 IEmployees proxy = channelFactory.CreateChannel(); Console.WriteLine("所有员工信息:"); // 通过代理类来对Rest服务进行操作 Array.ForEach<Employee>(proxy.GetAll().ToArray(), emp => Console.WriteLine(emp.ToString())); Console.WriteLine(" 添加一个新员工{0003}:"); proxy.Create(new Employee { Id = "0003", Name="李四", Department="财务部" }); Array.ForEach<Employee>(proxy.GetAll().ToArray(), emp => Console.WriteLine(emp.ToString())); Console.WriteLine(" 修改员工(0003)信息:"); proxy.Update(new Employee { Id = "0003", Name="李四", Department = "销售部" }); Array.ForEach<Employee>(proxy.GetAll().ToArray(), emp => Console.WriteLine(emp.ToString())); Console.WriteLine(" 删除员工(0002)信息:"); proxy.Delete("0002"); Array.ForEach<Employee>(proxy.GetAll().ToArray(), emp => Console.WriteLine(emp.ToString())); Console.Read(); } } } }
客户端对应的配置文件内容如下所示:
<configuration> <system.serviceModel> <behaviors> <endpointBehaviors> <behavior name="webBehavior"> <webHttp/> </behavior> </endpointBehaviors> </behaviors> <client> <endpoint name="employeeService" address="http://localhost:9003/employeeService" binding="webHttpBinding" behaviorConfiguration="webBehavior" contract="RestContract.IEmployees"> </endpoint> </client> </system.serviceModel> </configuration>
二.WCF配置文件
配置也是WCF编程中的主要组成部分。在以往的.net应用程序中,我们会把DBConn和一些动态加载类及变量写在配置文件里。但WCF有所不同。他指定向客户端公开的服务,包括服务的地址、服务用于发送和接收消息的传输和消息编码,以及服务需要的安全类型等。
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.serviceModel> <!--配置服务和终结点开始--> <services> <service> <endpoint></endpoint> </service> </services> <!--配置服务和终结点结束--> <!--配置绑定开始--> <bindings> <netTcpBinding> <binding> </binding> </netTcpBinding> </bindings> <!--配置绑定结束--> <!--配置行为开始--> <behaviors> <!--endpointBehaviors在Rest时候用,也可以不配置,可以加入一些自定义的,自由发挥--> <endpointBehaviors> <behavior name="WebBehavior"> <webHttp /> </behavior> </endpointBehaviors> <serviceBehaviors> <behavior> </behavior> </serviceBehaviors> </behaviors> <!--配置行为结束--> </system.serviceModel> </configuration>
Service配置节[必须有]:配置服务、接口和终结点。每个Service都会有以下两个属性。name:名称空间.类名[服务的具体实现类]。behaviorConfiguration:一个在behaviors节点中找到的名称。
Binding配置节[可有可无]:配置绑定,如http,tcp等。
Behavior配置节[可有可无]:配置行为,如认证等。
//附一个各种自定义配置的,英文基本代表了各个意思 <bindings> <basicHttpBinding> <binding name="BasicHttpBinding0" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <security mode="None"> <transport clientCredentialType="None" proxyCredentialType="None" realm="" /> <message clientCredentialType="UserName" algorithmSuite="Default" /> </security> </binding> </basicHttpBinding> </bindings>
三.WCF测试:
调试:将Web.config中的 <webHttp /> 修改为 <webHttp helpEnabled="true" />,将可以在浏览器页面中列举出可用接口,并提供提交的数据样例。打开IE浏览器,在地址栏输入:http://localhost:3000/MyService.svc/help 即可。
1) 使用微软VisualStuio的wcf测试客户端(Common7IDEWcfTestClient.exe):
双击接口方法名,输入参数,测试。
2) 借用chrome扩展工具PostMan测试(Rest方式,也可以直接在地址栏输入地址)