先来点理论知识,来自 http://www.cnblogs.com/simonchen/articles/2220838.html
REST软件架构是由Roy Thomas Fielding博士2000年在他的论文《Architectural Styles and the Design of Network- based Software Architectures》首次提出的。他提出的理论对后来的Web技术的发展产生了巨大的影响,他是许多重要Web架构标准的设计者,这些标准就是 HTTP、URI等。
由于Rest遵守的这些规范,因此Rest架构的特点也非常的明显:
既然Rest风格有这些特点,那么也就具备了许多优点:
REST架构是针对Web应用而设计的,其目的是为了降低开发的复杂性,提高系统的可伸缩性。REST提出了如下设计准则:
甩过一遍理论,那么就趁热实践一番吧!
按正常步骤新建一个WCF应用,常见的CRUD操作
[ServiceContract] public interface IExampleService { [OperationContract] string GetData(string value); [OperationContract] string AddData(string value); [OperationContract ] string UpdateData(string value); [OperationContract ] string DeleteData(string value); }
那么rest模式该是如何呢?
[ServiceContract] public interface IExampleService { [OperationContract] [WebGet(UriTemplate = "/Rest/Get/{value}", ResponseFormat = WebMessageFormat.Json)] string GetData(string value); [OperationContract] [WebInvoke(UriTemplate = "/Rest/Add/{value}", Method = "POST")] string AddData(string value); [OperationContract ] [WebInvoke(UriTemplate = "/Rest/Update/{value}", Method = "PUT")] string UpdateData(string value); [OperationContract ] [WebInvoke (UriTemplate="/Rest/Delete/{value}",Method="DELETE")] string DeleteData(string value); }
比较下就很容易看出多加了些标签,并且也从方法的使用上可以对应出GET、POST、PUT、DELETE的使用。
wcf可以看元数据,那么rest也有对应的方式,在web.config中添加如下配置就可以查看help页面
<services> <service name="RestWCFTest.ExampleService"> <endpoint address="" behaviorConfiguration="HelpBehavior" binding="webHttpBinding" bindingConfiguration="" contract="RestWCFTest.IExampleService" /> </service> </services> <behaviors> <endpointBehaviors> <behavior name="HelpBehavior"> <webHttp helpEnabled="true" /> </behavior> </endpointBehaviors> </behaviors>
help页面如下
点击方法进去可以看见调用方式
我们的接口实现
public string GetData(string value) { return string.Format("You entered: {0}", value); } public string AddData(string value) { return string.Format("You added: {0}", value); } public string UpdateData(string value) { return string.Format("You updated: {0}", value); } public string DeleteData(string value) { return string.Format("You deleted: {0}", value); }
现在我们用fiddler来模拟请求测试下
在composer选项里有模拟请求的功能,very good!我们先来调用GetData操作,根据参数获取数据,根据设置的URI模板,“123456”为匹配
的参数,执行它!
看请求的信息
GET http://localhost/REST4/ExampleService.svc/Rest/Get/123456 HTTP/1.1
User-Agent: Fiddler
Content-type: application/json
Host: localhost
Content-Length: 0
看响应的数据
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 21
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 27 Sep 2013 05:16:52 GMT
"You entered: 123456"
200 OK 调用正常,content-type是json,因为我们指定的,IIS是7.5,对,我的确是部署在7.5上。。。看结果也是和预期一模一样,so easy~
可能有同学会问,这是返回的json数据么?我也觉得不是,如果在方法标签上修改为如下
[OperationContract]
[WebGet(UriTemplate = "/Rest/Get/{value}",BodyStyle=WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
string GetData(string value);
多加了个修饰bodystyle,它的功能是对结果进行包装,包装后再看返回的结果
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 39
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 27 Sep 2013 06:34:24 GMT
{"GetDataResult":"You entered: 123456"}
果然,被包装了,它是一个json格式的数据了。
POST
请求
POST http://localhost/REST4/ExampleService.svc/Rest/Add/1234 HTTP/1.1
User-Agent: Fiddler
Content-type: application/json
Host: localhost
Content-Length: 0
响应
HTTP/1.1 200 OK Cache-Control: private Content-Length: 92 Content-Type: application/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET Date: Fri, 27 Sep 2013 05:06:41 GMT <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">You added: 1234</string>
这个时候我们没有指定返回的格式,默认为XML。
PUT
请求
PUT http://localhost/REST4/ExampleService.svc/Rest/Update/123 HTTP/1.1
User-Agent: Fiddler
Content-type: application/json
Host: localhost
Content-Length: 0
响应
HTTP/1.1 200 OK Cache-Control: private Content-Length: 93 Content-Type: application/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET Date: Fri, 27 Sep 2013 05:23:04 GMT <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">You updated: 123</string>
DELETE
请求
DELETE http://localhost/REST4/ExampleService.svc/Rest/Delete/123 HTTP/1.1
User-Agent: Fiddler
Content-type: application/json
Host: localhost
Content-Length: 0
响应
HTTP/1.1 200 OK Cache-Control: private Content-Length: 93 Content-Type: application/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET Date: Fri, 27 Sep 2013 05:14:56 GMT <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">You deleted: 123</string>
有同学可能DELETE请求发出去没反应(IIS 7.5),请在web.config里加上以下节点
<system.webServer> <modules runAllManagedModulesForAllRequests="true"> <remove name="WebDAVModule" /> </modules> <handlers> <remove name="WebDAV" /> </handlers> </system.webServer>
至此一般的传参情况就是如此了,下面列举一些其它传参情况
[OperationContract] [WebGet(UriTemplate = "/Rest/GetList2/", ResponseFormat = WebMessageFormat.Json)] List<ExampleData> GetDataLs2(); [OperationContract] [WebInvoke(UriTemplate = "/Rest/AddLs3", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, Method = "POST")] List<ExampleData> AddDataLs3(List<ExampleData> datas); [OperationContract] [WebInvoke(UriTemplate = "/Rest/AddLs4", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, Method = "POST")] List<ExampleData> AddDataLs4(List<ExampleData> datas1, List<ExampleData> datas2);
实体
public class ExampleData { public string Name { get; set; } public string Age { get; set; } }
接口实现
public List<ExampleData> GetDataLs2() { List<ExampleData> result = new List<ExampleData> { new ExampleData{ Name="张三", Age="20"} ,new ExampleData {Name="李四",Age="21"} ,new ExampleData {Name="王五",Age="30"} }; return result; } public List<ExampleData> AddDataLs3(List<ExampleData> datas) { return datas; } public List<ExampleData> AddDataLs4(List<ExampleData> datas1, List<ExampleData> datas2) { List<ExampleData> result = new List<ExampleData>(); result.AddRange(datas1); result.AddRange(datas2); return result; }
我们看到有获取实体集合了,还有传参的时候也是实体集合了
首先看看获取集合的情况
请求
GET http://localhost/REST4/ExampleService.svc/Rest/GetList2/ HTTP/1.1
User-Agent: Fiddler
Content-type: application/json
Host: localhost
Content-Length: 0
响应
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 88
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 27 Sep 2013 05:21:52 GMT
[{"Age":"20","Name":"张三"},{"Age":"21","Name":"李四"},{"Age":"30","Name":"王五"}]
嗯,返回的格式不错。
看看怎样做新增操作的
AddDataLs3
请求
POST http://localhost/REST4/ExampleService.svc/Rest/AddLs3 HTTP/1.1
User-Agent: Fiddler
Content-type: application/json
Host: localhost
Content-Length: 41
{"datas":[{"Name":"xiaohua","Age":"13"}]}
这时候我们会注意到,多了request body了,并且datas就是参数名
响应
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 52
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 27 Sep 2013 06:59:55 GMT
{"AddDataLs3Result":[{"Age":"13","Name":"xiaohua"}]}
被包装了的数据。
AddDataLs4
请求
POST http://localhost/REST4/ExampleService.svc/Rest/AddLs4 HTTP/1.1
User-Agent: Fiddler
Content-type: application/json
Host: localhost
Content-Length: 78
{"datas1":[{"Name":"xiaohua","Age":"13"}],"datas2":[{"Name":"li","Age":"13"}]}
响应
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 77
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 27 Sep 2013 07:02:58 GMT
{"AddDataLs4Result":[{"Age":"13","Name":"xiaohua"},{"Age":"13","Name":"li"}]}
面对茫茫多的CRUD的时候,我们也许会显得不耐烦,因为每个操作都去写方法,真是烦躁,不妨可以试下如下的方式
[OperationContract] [WebInvoke(UriTemplate = "/Rest/*", Method = "*", ResponseFormat = WebMessageFormat.Json)] string ExecuteData();
用星号来匹配所有的请求,让程序区识别请求到底是GET、POST、PUT还是DELETE
实现
public string ExecuteData() { var request = WebOperationContext.Current.IncomingRequest; var method = request.Method; var args = request.UriTemplateMatch.WildcardPathSegments; switch (method) { case "POST": return "POST..."; case "DELETE": return "DELETE..."; case "PUT": return "UPDATE..."; default: return "GET..."; } }
嗯,不知不觉就贴了这么多代码了,其实我字没写多少,今天就到这吧,算是入门了吧。
以上例子所有源码下载