2012-03-24 18 views
11

Oye, no estoy llegando a ningún lado con convertir wcf en un servicio de descanso. Así que me preguntaba si alguien puede tomar el código básico cuando se inicia una aplicación de servicio de WCF aquí:convertir un Servicio WCF, a una aplicación 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; } 
     } 
    } 
} 

y el servicio:

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; 
     } 
    } 
} 

Todo lo que me hizo es iniciado esta aplicación de servicio WCF y Abrí otro alma de VS2010 con un formulario básico que tiene un botón y etiqueta de texto y copié la ubicación del servicio de la aplicación de servicio en la otra solución, así que cuando escribo un número recibo una respuesta del servicio.

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)); 
     } 
    } 
} 

Muy rápido y sucio pero cumple su función.

Ahora, si alguien puede ayudar con el código, ¿cómo lo convierte en un servicio de descanso?

parte final de mi archivo de configuración: actualización EDITAR

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

con el código de configuración Justins:

Así, cuando cada vez que toco el archivo de configuración de mi error habitual es la siguiente: No se pudo agregar un servicio. Los metadatos del servicio pueden no ser accesibles. Asegúrese de que su servicio está en funcionamiento y la exposición de metadatos

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/son útiles para comprender el descanso –

+0

Ahh, sí, WCF apesta por REST (como mencioné). Sin embargo, actualicé mi respuesta de un artículo antiguo de MSDN sobre cómo hacer esto más específicamente para su caso. –

Respuesta

8

como se había mencionado, este es un nuevo proyecto, así que tal vez una redirección podría ayudar a hacer que el proceso sea un poco más sencilla?

Here is an MSDN article about what you are asking.

Sin embargo, sugiero especialmente mirar ServiceStack para crear un servicio RESTful, ya que hace que el proceso sea extremadamente fácil. WCF definitivamente no proporciona un medio fácil para lograr esto. Ellos lo complican en este caso IMO.

Eso sería donde me gustaría ir con este cambio, si éste es de hecho el comienzo de un proyecto

Una respuesta más directa proviene de This article that is a bit older, but can probably help both understand REST, and how to implement it in WCF. Y es especificar su GET/POST/PUT/DELETE en una web [Tipo] Atributo

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

Además, tendrá que hacer esto en .config de la aplicación (una vez más para los mayores, 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> 

que se traduciría en su configuración como:

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

Entonces , es probable que necesite agregar un atributo de dirección al punto final para que sepa dónde buscar.

+1

Para el votante anónimo, ¿por qué el voto a la baja? Me doy cuenta de que esta no es una respuesta directa, pero a veces he encontrado que es más útil. Nuestro trabajo no es proporcionar respuestas ciegas si vemos un camino mejor. –

+0

Te he votado solo porque odio a los videntes anónimos.Desearía SO forzaría un comentario cuando se disminuye el voto – flq

+0

@flq Gracias, estoy de acuerdo y me pregunto si eso se ha planteado en meta (probablemente ... comprobará en breve :)). Terminé proporcionando una respuesta más específica después de ver la pregunta de Garrith a continuación. –

1

Use el atributo WebGet en las operaciones que desea que estén disponibles como un servicio RESTful.

Use webHttpBinding.

Recuerde agregar a sus comportamientos en config.

Debería ser suficiente para que comience.

EDIT:

Añadir un nuevo vinculante en virtud de su servicio:

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

etc - a continuación, más que añadir a

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

como endpointbehavior.

[WebGet] atributo - busque en las diversas opciones para desarrollarlo aún más.

+0

allí lo tiene. ¡actualizado! :) – Chris

3

Al configurar un servicio WCF REST simple, en el pasado he tenido un error similar al que tienes. En el artículo mencionado por Justin:
A Guide to Designing and Building RESTful Web Services with WCF 3.5
(búsqueda de - Definición de la interfaz HTTP: [WebGet])

Se dará cuenta de que los métodos Get toman todas las cadenas.

El error que tiene es común cuando intenta convertir uno de los proyectos WCF de muestra en uno RESTful. Para solucionar, simplemente cambiar la firma del método y la interfaz para aceptar una cadena, en contraposición a una int, esto es lo que la excepción interna se queja:

'GetData' Operación en el contrato ' IService1 'tiene una variable de ruta llamada' value 'que no tiene el tipo' string '. Variables para los segmentos de trazado UriTemplate deben tener tipo 'cadena'

el original:

public string GetData(int value) 

modificación:

public string GetData(string value) 

Aquí es una sección .config simple a partir de un proyecto de ejemplo que tengo, que yo saber funciona:

<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

Esto es e proyecto xample de codeproject.com. No hay necesidad de hacer

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

en lugar de

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