首先,給wcf restful下個定義,WCF 很好的支持了 REST 的開發, 而 RESTful 的服務通常是架構層面上的考慮。 因爲它天生就具有很好的跨平臺跨語言的集成能力,幾乎所有的語言和網絡平臺都支持 HTTP 請求,無需去實現複雜的客戶端代理,無需使用複雜的數據通訊方式既可以將我們的服務暴露給任何需要的人,無論他使用 VB、Ruby、JavaScript,甚至是 HTML FORM,或者直接在瀏覽器地址欄輸入。
WCF 中通過 WebGetAttribute、WebInvokeAttribute (GET/PUT/POST/DELETE)、UriTemplate 定義 REST 的服務的調用方式, 通過 WebMessageFormat (Xml/Json) 定義消息傳遞的格式。
在網上有很多關於如何使用WCF Restful的教程,我也學習了不少,但是網上的教程發佈是通過WebServiceHost的,而我想實現的是通過svc文件發佈的方式來實現。在這種方式中,配置文件上我碰到了很多問題,但最終我實現了這個方式。最終發現很簡單,可能是我對WCF不夠了解。例子很簡單,我主要對這兩種方式的不同做個比較。
通過WebServiceHost發佈
1. 定義接口,與soap格式不同,在方法上不需要OperationContract,而是WebGet或WebInvoke。WebGet表示該方法是通過Http Get請求的。WebInvoke可以定義Method,這裏是Post請求。
namespace WcfServiceRestTest
{
[ServiceContract]
public interface IUserService
{
[WebGet(UriTemplate="{id}")]
UserInfo GetUser(string id);
[WebGet(UriTemplate = "all",ResponseFormat=WebMessageFormat.Json)]
IEnumerable<UserInfo> GetAll();
[WebInvoke(UriTemplate = "Create",Method="Post", ResponseFormat = WebMessageFormat.Json)]
int Create(UserInfo info);
}
}
1.接口實現,這裏有個小細節,對於參數id,本來是int值,但是wcf運行後不支持,報錯錯誤“約定“IUserService”中的操作“GetUser”具有非“字符串”類型的路徑變量“id”。UriTemplate 路徑段的變量類型必須爲“字符串”。”,所以改成類型string,說明wcf只支持string類型的參數。namespace WcfServiceRestTest
{
public class UserService : IUserService
{
List<UserInfo> userList;
public UserService()
{
userList = new List<UserInfo>
{
new UserInfo{ID= 1, Name= "Wesley"},
new UserInfo{ID= 2, Name= "Jack"},
new UserInfo{ID= 2, Name= "Eric"}
};
}
public UserInfo GetUser(string id)
{
return userList.Where(o => o.ID == int.Parse(id)).FirstOrDefault();
}
public IEnumerable<UserInfo> GetAll()
{
return userList;
}
public int Create(UserInfo info)
{
if (userList != null && info != null)
{
userList.Add(info);
return 1;
}
else
{
return 0;
}
}
}
}
3.服務配置,Address Binding Contract,與WCF SOAP類似,不過需要注意如下紅色部分,webHttpBinding,這是Restful格式的綁定方式。endpoint的address如監聽地址一樣,如果請求到這兒“http://127.0.0.1:11191/UserService”,就會調用此服務。<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="WcfServiceRestTest.UserService">
<endpoint address="http://127.0.0.1:11191/UserService" binding="<span style="color:#FF0000;">webHttpBinding</span>" contract="WcfServiceRestTest.IUserService"/>
</service>
</services>
</system.serviceModel>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/>
</system.web>
</configuration>
4.啓動服務
class Program
{
static void Main(string[] args)
{
using (WebServiceHost host = new WebServiceHost(typeof(UserService)))
{
host.Open();
Console.Read();
}
}
}
5.啓動程序後,便可以通過endpoint的address加上方法的UriTemplate去請求。如 http://127.0.0.1:11191/UserService/all,調用服務中GetAll方法。
通過svc文件發佈
代碼跟上面的一樣,只是配置文件不一樣,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="WcfServiceRestTest.UserService" behaviorConfiguration="ServiceBehavior">
<endpoint binding="webHttpBinding" contract="WcfServiceRestTest.IUserService" behaviorConfiguration="webHttp" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true" />
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webHttp">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<directoryBrowse enabled="true" />
</system.webServer>
</configuration>
這種方式讓我測試了很久。其實這裏只是沒有定義address,別的都差不多。
這樣就可以通過 localhost + web項目定義的端口號 + svc文件名稱 + UriTemplate 來訪問了。如 http://localhost:11191/UserService.svc/all,這請求中與上面的請求略有不同。
這個請求有.svc,是先找到svc,再去調用svc對應的服務。
之前我在配置中一直有address,總是報“沒有與給定的地址“http://127.0.0.1:11191/UserService”匹配的協議綁定。協議綁定在 IIS 或 WAS 配置中的站點級別配置。”的錯誤。
通過svc文件發佈不需要給servcie定義address,我想了下原因,可能是因爲wcf服務項目已經定義了ip和端口號,所以不需要再定義address了。
寫此篇在這裏做個記錄,讓自己對WCF加深印象。如果有不對的地方,希望各位不吝賜教。