2012-03-24 59 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}")]