1. 什么是REST?
Rest的全称是Representational State Transfer, 普通的WCF使用SOAP,而使用REST构建的WCF服务
使用其他数据传输方式,例如JSON
Rest的四种操作:
- GET - Requests a specific representation of a resource
- PUT - Creates or updates a resource with the supplied representation
- DELETE - Deletes the specified resource
- POST - Submits data to be processed by the identified resource
2. 什么情况下使用REST?
- Less overhead (no SOAP envelope to wrap every call in)
- Less duplication (HTTP already represents operations like
DELETE
,PUT
,GET
, etc. that have to otherwise be represented in a SOAP envelope). - More standardized - HTTP operations are well understood and operate consistently. Some SOAP implementations can get finicky.
- More human readable and testable (harder to test SOAP with just a browser).
- Don't need to use XML (well, you kind of don't have to for SOAP either but it hardly makes sense since you're already doing parsing of the envelope).
- Libraries have made SOAP (kind of) easy. But you are abstracting away a lot of redundancy underneath as I have noted. Yes, in theory, SOAP can go over other transports so as to avoid riding atop a layer doing similar things, but in reality just about all SOAP work you'll ever do is over HTTP.
3. 简单的例子
1) 首先,制作服务契约的接口
IHelloService
using System.ServiceModel;
using System.ServiceModel.Web;
namespace Perseus.WCF.REST.Contract.Service
{
[ServiceContract]
public interface IHelloService
{
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "xml/{name}/{age}")]
string HelloXml(string name, string age);
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "json/{name}/{age}")]
string HelloJson(string name, string age);
}
}
using System.ServiceModel.Web;
namespace Perseus.WCF.REST.Contract.Service
{
[ServiceContract]
public interface IHelloService
{
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "xml/{name}/{age}")]
string HelloXml(string name, string age);
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "json/{name}/{age}")]
string HelloJson(string name, string age);
}
}
2) 然后, 新建一个WCF服务项目,在项目中添加WCF服务文件svc
HelloService.svc
using Perseus.WCF.REST.Contract.Service;
namespace Perseus.WCF.REST.Service
{
public class HelloService : IHelloService
{
public string HelloXml(string name, string age)
{
return "Hello " + name + " "
+ "Your Age: " + age;
}
public string HelloJson(string name, string age)
{
return "Hello " + name + " "
+ "Your Age: " + age;
}
}
}
namespace Perseus.WCF.REST.Service
{
public class HelloService : IHelloService
{
public string HelloXml(string name, string age)
{
return "Hello " + name + " "
+ "Your Age: " + age;
}
public string HelloJson(string name, string age)
{
return "Hello " + name + " "
+ "Your Age: " + age;
}
}
}
3) 配置文件
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="NorthwindConnectionString" connectionString="Data Source=localhost;Initial Catalog=Northwind;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="Perseus.WCF.REST.Service.HelloService" behaviorConfiguration="ServiceBehaviour">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="webHttpBinding" contract="Perseus.WCF.REST.Contract.Service.IHelloService" behaviorConfiguration="web">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
</endpoint>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
<configuration>
<connectionStrings>
<add name="NorthwindConnectionString" connectionString="Data Source=localhost;Initial Catalog=Northwind;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="Perseus.WCF.REST.Service.HelloService" behaviorConfiguration="ServiceBehaviour">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="webHttpBinding" contract="Perseus.WCF.REST.Contract.Service.IHelloService" behaviorConfiguration="web">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
</endpoint>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
4) 地址栏调试
http://localhost:7695/HelloService.svc/xml/david/30
返回结果:
<HelloXmlResponse xmlns="http://tempuri.org/">
<HelloXmlResult>Hello david Your Age: 30</HelloXmlResult>
</HelloXmlResponse>
<HelloXmlResult>Hello david Your Age: 30</HelloXmlResult>
</HelloXmlResponse>
http://localhost:7695/HelloService.svc/json/david/30
返回结果:
{"HelloJsonResult":"Hello david Your Age: 30"}
5) 编写客户端调用代码
HelloRestTest
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Web;
using Perseus.WCF.REST.Contract.Service;
namespace Perseus.WCF.Client
{
class HelloRestTest : ITestCase
{
public void Run()
{
Console.Write("Please Input Your Name: ");
string name = Console.ReadLine();
Console.Write("Please Input Your Age: ");
string age = Console.ReadLine();
string url = "http://localhost:7695/HelloService.svc";
using (WebChannelFactory<IHelloService> wcf
= new WebChannelFactory<IHelloService>(new Uri(url)))
{
var channel = wcf.CreateChannel();
IClientChannel clientchanel = channel as IClientChannel;
string result = channel.HelloJson(name, age);
Console.WriteLine(result);
}
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Web;
using Perseus.WCF.REST.Contract.Service;
namespace Perseus.WCF.Client
{
class HelloRestTest : ITestCase
{
public void Run()
{
Console.Write("Please Input Your Name: ");
string name = Console.ReadLine();
Console.Write("Please Input Your Age: ");
string age = Console.ReadLine();
string url = "http://localhost:7695/HelloService.svc";
using (WebChannelFactory<IHelloService> wcf
= new WebChannelFactory<IHelloService>(new Uri(url)))
{
var channel = wcf.CreateChannel();
IClientChannel clientchanel = channel as IClientChannel;
string result = channel.HelloJson(name, age);
Console.WriteLine(result);
}
}
}
}
运行结果:
Hello david Your Age: 30