c# - 将 WCF 服务转换为 RESTful 应用程序?

标签 c# wcf visual-studio-2010 rest

嘿,我没有将 wcf 变成一个 Restful 服务。所以我想知道当您在这里启动 WCF 服务应用程序时是否有人可以使用基本代码:

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 soultion,它的基本形式有一个文本框按钮和标签,并在另一个解决方案中复制了 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));
        }
    }
}

确实又快又脏,但达到了目的。

现在,如果有人可以帮助编写代码,您如何将它变成一个 Restful 服务?

我的配置文件的结束部分:

 <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)-->--.

最佳答案

正如您所提到的,这是一个新项目,因此重定向可能有助于简化流程?

Here is an MSDN article about what you are asking .

但是,我特别建议查看 ServiceStack创建一个 RESTful 服务,因为它使这个过程非常简单。 WCF 绝对没有提供一种简单的方法来实现这一点。在这种情况下,IMO 将其过于复杂化。

如果这确实是一个项目的开始,那将是我会去的地方

更直接的答案来自This article that is a bit older, but can probably help both understand REST, and how to implement it in WCF .并且是在 Web[Type]Attribute 中指定你的 GET/POST/PUT/DELETE

[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>

然后,您可能需要向端点添加一个地址属性,以便它知道要查找的位置。

关于c# - 将 WCF 服务转换为 RESTful 应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9854052/

相关文章:

asp.net - 从 ASP.NET 调用 WCF 服务器

c# - 如何使用WF4检索MVC5中的页面流逻辑

c# - Visual Studio 2010 调试器(x86 模式)未显示未处理的错误

c# - 如何获取在特定点接收鼠标点击的 Control/Windows Handle/AutomationElement?

c# - 我可以停止 .NET 4 执行尾调用消除吗?

c# - VB.NET WithEvents 关键字行为 - VB.NET 编译器限制?

c# - 我应该使用线程异步访问连接到 PCI 总线的设备吗?

c# - 为什么附加字段 "Specified"的字段总是空的?

c++ - VC++ 编译器看不到我的任何命名空间和类

windows - 将项目类型更改为 .wixproj 的 cmake 配置是什么?