2012-03-24 100 views
11

嘿我沒有得到任何地方把wcf變成一個寧靜的服務。所以我在想,如果當你開始一個WCF服務應用程序在這裏的一些人可以利用的基本代碼:將WCF服務轉換爲RESTful應用程序?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.Serialization; 
using System.ServiceModel; 
using System.ServiceModel.Web; 
using System.Text; 

namespace WcfService1 
{ 
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together. 
    [ServiceContract] 
    public interface IService1 
    { 

     [OperationContract] 
     string GetData(int value); 

     [OperationContract] 
     CompositeType GetDataUsingDataContract(CompositeType composite); 

     // TODO: Add your service operations here 
    } 


    // Use a data contract as illustrated in the sample below to add composite types to service operations. 
    [DataContract] 
    public class CompositeType 
    { 
     bool boolValue = true; 
     string stringValue = "Hello "; 

     [DataMember] 
     public bool BoolValue 
     { 
      get { return boolValue; } 
      set { boolValue = value; } 
     } 

     [DataMember] 
     public string StringValue 
     { 
      get { return stringValue; } 
      set { stringValue = value; } 
     } 
    } 
} 

,服務:

namespace WcfService1 
{ 
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together. 
    public class Service1 : IService1 
    { 
     public string GetData(int value) 
     { 
      return string.Format("You entered: {0}", value); 
     } 

     public CompositeType GetDataUsingDataContract(CompositeType composite) 
     { 
      if (composite == null) 
      { 
       throw new ArgumentNullException("composite"); 
      } 
      if (composite.BoolValue) 
      { 
       composite.StringValue += "Suffix"; 
      } 
      return composite; 
     } 
    } 
} 

所有我已經沒有啓動這個WCF服務應用程序,打開了另一個VS2010靈魂提示,它帶有一個帶有文本框按鈕和標籤的基本表單,並在另一個解決方案中拷貝了serviceapp的服務位置,所以當我鍵入一個數字時,我得到服務的響應。

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 

     } 
     public ServiceReference1.Service1Client testClient = new ServiceReference1.Service1Client(); 
     private void button1_Click(object sender, EventArgs e) 
     { 
      label1.Text = testClient.GetData(Convert.ToInt32(textBox1.Text)); 
     } 
    } 
} 

真的很快又髒,但達到其目的。

現在,如果任何人可以幫助代碼,你怎麼把它變成一個寧靜的服務?我的配置文件的

結束部分:

<system.serviceModel> 
    <services> 
     <service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior"> 
     <!-- Service Endpoints --> 
     <endpoint address="" binding="wsHttpBinding" contract="WcfService1.IService1"> 
      <!-- 
       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. 
      --> 
      <identity> 
      <dns value="localhost"/> 
      </identity> 
     </endpoint> 
     <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="WcfService1.Service1Behavior"> 
      <!-- 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> 
    </behaviors> 
    </system.serviceModel> 

</configuration> 

與Justins配置代碼編輯更新:

所以,當過我觸摸配置文件我通常的錯誤是:無法添加服務。服務元數據可能無法訪問。確保您的服務正在運行,揭露元

Error: Cannot obtain Metadata from http://localhost:26535/Service1.svc If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address. For help enabling metadata publishing, please refer to the MSDN documentation at http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata Exchange Error URI: http://localhost:26535/Service1.svc Metadata contains a reference that cannot be resolved: 'http://localhost:26535/Service1.svc'. The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.HTTP GET Error URI: http://localhost:26535/Service1.svc There was an error downloading 'http://localhost:26535/Service1.svc'. The request failed with the error message:--<html> <head>  <title>Operation 'GetData' in contract 'IService1' has a path variable named 'value' which does not have type 'string'. ÿVariables for UriTemplate path segments must have type 'string'.</title>  <style>   body {font-family:"Verdana";font-weight:normal;font-size: .7em;color:black;}   p {font-family:"Verdana";font-weight:normal;color:black;margin-top: -5px}   b {font-family:"Verdana";font-weight:bold;color:black;margin-top: -5px}   H1 { font-family:"Verdana";font-weight:normal;font-size:18pt;color:red }   H2 { font-family:"Verdana";font-weight:normal;font-size:14pt;color:maroon }   pre {font-family:"Lucida Console";font-size: .9em}   .marker {font-weight: bold; color: black;text-decoration: none;}   .version {color: gray;}   .error {margin-bottom: 10px;}   .expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:hand; }  </style> </head> <body bgcolor="white">   <span><H1>Server Error in '/' Application.<hr width=100% size=1 color=silver></H1>   <h2> <i>Operation 'GetData' in contract 'IService1' has a path variable named 'value' which does not have type 'string'. ÿVariables for UriTemplate path segments must have type 'string'.</i> </h2></span>   <font face="Arial, Helvetica, Geneva, SunSans-Regular, sans-serif ">   <b> Description: </b>An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.   <br><br>   <b> Exception Details: </b>System.InvalidOperationException: Operation 'GetData' in contract 'IService1' has a path variable named 'value' which does not have type 'string'. ÿVariables for UriTemplate path segments must have type 'string'.<br><br>   <b>Source Error:</b> <br><br>   <table width=100% bgcolor="#ffffcc">    <tr>     <td>      <code>An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.</code>     </td>    </tr>   </table>   <br>   <b>Stack Trace:</b> <br><br>   <table width=100% bgcolor="#ffffcc">    <tr>     <td>      <code><pre>[InvalidOperationException: Operation 'GetData' in contract 'IService1' has a path variable named 'value' which does not have type 'string'. Variables for UriTemplate path segments must have type 'string'.] System.ServiceModel.Dispatcher.UriTemplateClientFormatter.Populate(Dictionary`2& pathMapping, Dictionary`2& queryMapping, Int32& totalNumUTVars, UriTemplate& uriTemplate, OperationDescription operationDescription, QueryStringConverter qsc, String contractName) +726 System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter..ctor(OperationDescription operationDescription, IDispatchMessageFormatter inner, QueryStringConverter qsc, String contractName, Uri baseAddress) +94 System.ServiceModel.Description.WebHttpBehavior.GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint) +137 System.ServiceModel.Description.WebHttpBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) +659 System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost) +3864 System.ServiceModel.ServiceHostBase.InitializeRuntime() +37 System.ServiceModel.ServiceHostBase.OnBeginOpen() +27 System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) +49 System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +261 System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +121 System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +479[ServiceActivationException: The service '/Service1.svc' cannot be activated due to an exception during compilation. The exception message is: Operation 'GetData' in contract 'IService1' has a path variable named 'value' which does not have type 'string'. Variables for UriTemplate path segments must have type 'string'..] System.ServiceModel.AsyncResult.End(IAsyncResult result) +11655726 System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) +194 System.ServiceModel.Activation.HostedHttpRequestAsyncResult.ExecuteSynchronous(HttpApplication context, Boolean flowContext) +176 System.ServiceModel.Activation.HttpModule.ProcessRequest(Object sender, EventArgs e) +275 System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +68 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75</pre></code>     </td>    </tr>   </table>   <br>   <hr width=100% size=1 color=silver>   <b>Version Information:</b>ÿMicrosoft .NET Framework Version:2.0.50727.5448; ASP.NET Version:2.0.50727.5456   </font> </body></html><!-- [InvalidOperationException]: Operation 'GetData' in contract 'IService1' has a path variable named 'value' which does not have type 'string'. Variables for UriTemplate path segments must have type 'string'. at System.ServiceModel.Dispatcher.UriTemplateClientFormatter.Populate(Dictionary`2& pathMapping, Dictionary`2& queryMapping, Int32& totalNumUTVars, UriTemplate& uriTemplate, OperationDescription operationDescription, QueryStringConverter qsc, String contractName) at System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter..ctor(OperationDescription operationDescription, IDispatchMessageFormatter inner, QueryStringConverter qsc, String contractName, Uri baseAddress) at System.ServiceModel.Description.WebHttpBehavior.GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint) at System.ServiceModel.Description.WebHttpBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) at System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost) at System.ServiceModel.ServiceHostBase.InitializeRuntime() at System.ServiceModel.ServiceHostBase.OnBeginOpen() at System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) at System.ServiceModel.ServiceHostingEnvironment.HostingManager.ActivateService(String normalizedVirtualPath) at System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath)[ServiceActivationException]: The service '/Service1.svc' cannot be activated due to an exception during compilation. The exception message is: Operation 'GetData' in contract 'IService1' has a path variable named 'value' which does not have type 'string'. Variables for UriTemplate path segments must have type 'string'.. at System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result) at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.ExecuteSynchronous(HttpApplication context, Boolean flowContext) at System.ServiceModel.Activation.HttpModule.ProcessRequest(Object sender, EventArgs e) at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)-->--. 
+2

http://en.wikipedia.org/wiki/Representational_state_transfer http://www.ibm.com/developerworks/webservices/library/ ws-restful /有助於理解其他 – 2012-03-24 18:10:50

+0

啊,是的,WCF很喜歡REST(正如我所提到的)。不過,我已經從一篇舊的MSDN文章更新了我的答案,即如何針對您的情況更具體地實現這一點。 – 2012-03-24 18:25:00

回答

8

正如你所提到,這是一個新的項目,所以也許重定向可能有助於使這一過程稍微簡單嗎?

Here is an MSDN article about what you are asking

但是,我特別建議看看ServiceStack來創建一個RESTful服務,因爲它使過程變得非常簡單。 WCF絕對不提供一個簡單的方法來完成這一點。他們在這種情況下過度複雜的國際海事組織。

這將是在那裏我會用這個代替走,如果這確實是一個項目

更直接的答案來自This article that is a bit older, but can probably help both understand REST, and how to implement it in WCF的開端。而且是指定的GET/POST/PUT /在Web刪除[類型]屬性

[WebGet(UriTemplate = @"Data?value={value}")] 
[OperationContract] 
string GetData(int value); 

此外,你需要做到這一點在你的應用程序的.config(同樣對於上了年紀,MSDN article by Skonnard

<configuration> 
    <system.serviceModel> 
    <services> 
     <service name="Service1"> 
      <endpoint binding="webHttpBinding" contract="Service1" 
         behaviorConfiguration="webHttp"/> 
     </service> 
    </services> 
    <behaviors> 
     <endpointBehaviors> 
      <behavior name="webHttp"> 
       <webHttp/> 
      </behavior> 
     </endpointBehaviors> 
    </behaviors> 
    </system.serviceModel> 
<configuration> 

這將轉化爲你的配置爲:

<system.serviceModel> 
<services> 
    <service name="WcfService1.Service1" 
     behaviorConfiguration="WcfService1.Service1Behavior"> 
    <!-- Service Endpoints --> 
    <endpoint address="" binding="webHttpBinding" contract="WcfService1.IService1" 
     behaviorConfiguration="webHttp"> 
     <!-- 
      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. 
     --> 
     <identity> 
     <dns value="localhost"/> 
     </identity> 
    </endpoint> 
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> 
    </service> 
</services> 
<behaviors> 
    <serviceBehaviors> 
    <behavior name="WcfService1.Service1Behavior"> 
     <!-- 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> 

然後,您可能需要向端點添加地址屬性,以便知道在哪裏查找。

+1

對於匿名downvoter,爲什麼downvote。我意識到這不是一個直接的答案,但有時我發現更有幫助。如果我們看到更好的路徑,我們的工作不是提供盲目的答案。 – 2012-03-24 18:02:24

+0

我只是因爲我討厭匿名downvoters而高舉你。希望所以強迫評論當downvoting – flq 2012-03-24 18:13:34

+0

@ flq謝謝,我同意並懷疑這是否已在元(可能...將檢查很快:))。在看到Garrith的問題後,我最終提供了更具體的答案。 – 2012-03-24 18:18:54

1

對您希望作爲REST式服務可用的操作使用WebGet屬性。

使用webHttpBinding。

記得在config中添加你的行爲。

應該足以讓它開始。

編輯:

添加一個新的綁定在你的服務下:

<service><endpoint binding="webHttpBinding"... behavior="myBehavior"/> 

等 - 然後進一步增加

<behavior name="myBehavior"><webHttp/></behavior> 

爲endpointbehavior。

[WebGet]屬性 - 查看各種選項以供您進一步開發它。

+0

你去了。更新! :) – Chris 2012-03-24 18:36:34

3

當配置一個簡單的WCF REST服務時,過去我的錯誤類似於你的錯誤。在由Justin文章提到:
A Guide to Designing and Building RESTful Web Services with WCF 3.5
(搜索 - 定義HTTP接口:[WebGet]

你會發現,獲取方法都接受字符串。

當您嘗試將示例WCF項目之一轉換爲REST風格項目時,您遇到的錯誤很常見。要修復,簡單地改變方法和接口的簽名接受,而不是一個INT,這是內部異常抱怨:在合同

操作「的GetData」' IService1'有一個名爲'value'的路徑變量,它沒有'string'類型。爲UriTemplate路徑段變量的類型必須是 '字符串'

原:

public string GetData(int value) 

修改:

public string GetData(string value) 

下面是一個示例項目我有一個簡單的.config部分,我知道作品:

<system.serviceModel> 
    <behaviors> 
     <endpointBehaviors> 
     <behavior name="Service1Behavior"> 
      <webHttp/> 
     </behavior> 
     </endpointBehaviors> 
    </behaviors> 
    <services> 
     <service name="Wcf.Service1"> 
     <endpoint address="" 
       behaviorConfiguration="Service1Behavior" 
       binding="webHttpBinding" 
       contract="Wcf.IService1"/> 
     </service> 
    </services> 
    </system.serviceModel> 
0

這是e來自codeproject.com的xample項目。有必要使

[WebGet(UriTemplate = "?id={id}")] 

,而不是

[WebGet(UriTemplate = "{id}")]