2010-03-18 11 views
25

Estoy tratando de construir una interfaz de servicio web genérica utilizando WCF, para permitir que los desarrolladores externos se conecten a nuestro software. Después de mucha lucha y lectura (this question me ayudó mucho), finalmente obtuve SOAP, JSON y XML (POX) trabajando juntos.SOAP/JSON/XML combinados en WCF, usando UriTemplate

Para simplificar, aquí está mi código (para hacer este ejemplo simple, no estoy usando las interfaces - Yo probé esta en ambos sentidos):

<ServiceContract()> _ 
Public Class TestService 
    Public Sub New() 
    End Sub 

    <OperationContract()> _ 
    <WebGet()> _ 
    Public Function GetDate() As DateTime 
     Return Now 
    End Function 


    '<WebGet(UriTemplate:="getdateoffset/{numDays}")> _ 
    <OperationContract()> _ 
    Public Function GetDateOffset(ByVal numDays As Integer) As DateTime 
     Return Now.AddDays(numDays) 
    End Function 

End Class 

y el código web.config:

<services> 
    <service name="TestService" 
      behaviorConfiguration="TestServiceBehavior"> 
    <endpoint address="soap" binding="basicHttpBinding" contract="TestService"/> 
    <endpoint address="json" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="TestService"/> 
    <endpoint address="xml" binding="webHttpBinding" behaviorConfiguration="poxBehavior" contract="TestService"/> 
    <endpoint address="mex" contract="IMetadataExchange" binding="mexHttpBinding" /> 
    </service> 
</services> 
<behaviors> 
    <endpointBehaviors> 
    <behavior name="jsonBehavior"> 
     <enableWebScript/> 
    </behavior> 
    <behavior name="poxBehavior"> 
     <webHttp /> 
    </behavior> 
    </endpointBehaviors> 
    <serviceBehaviors> 
    <behavior name="TestServiceBehavior"> 
     <serviceMetadata httpGetEnabled="true"/> 
     <serviceDebug includeExceptionDetailInFaults="false"/> 
    </behavior> 
    </serviceBehaviors> 
</behaviors> 

Esto realmente funciona - soy capaz de ir a TestService.svc/xml/GetDate para XML, JSON para TestService.svc/json/GetDate, y señalar un cliente SOAP en TestService.svc?wsdl y tienen el jabón funcionan las consultas.

La parte que me gustaría corregir son las consultas. Tengo que usar TestService.svc/xml/GetDateOffset?numDays=4 en lugar de TestService.svc/xml/GetDateOffset/4. Si se especifica la UriTemplate, me sale el error:

Endpoints using 'UriTemplate' cannot be used with 'System.ServiceModel.Description.WebScriptEnablingBehavior'.

Pero, por supuesto, sin necesidad de utilizar <enableWebScript/>, JSON no funciona.

La única otra cosa que he visto que creo que funcionará es hacer 3 servicios diferentes (archivos .svc), que implementen una interfaz que especifique el contrato, pero en las clases especifique diferentes atributos WebGet/WebInvoke en cada clase. Esto parece mucho trabajo extra, francamente, no veo por qué el marco no funciona para mí. La implementación de las clases sería la misma, excepto por los atributos, lo que significa que con el tiempo sería fácil corregir errores/cambios en una implementación, pero no en las otras, lo que generaría un comportamiento incoherente cuando se usa el JSON. Implementación SOAP por ejemplo.

¿Estoy haciendo algo mal aquí? ¿Estoy tomando un enfoque totalmente incorrecto y haciendo mal uso de WCF? ¿Hay una mejor manera de hacer esto?

Con mi experiencia haciendo cosas web, creo que debería ser posible algo de tipo de marco para manejar esto ... Incluso tengo una idea en mi cabeza de cómo construirlo. Parece que se supone que WCF está haciendo esto, y realmente no quiero reinventar la rueda.

+0

¡Tu ejemplo de código aquí fue muy útil! Solo tenía enlaces JSON y descubrí que no podía consumir los servicios de una aplicación .NET, ¡así que esto es lo que buscaba! :) – Shawson

+0

Tenga en cuenta que considero esto completamente obsoleto ahora con [ASP.NET Web API] (http://www.asp.net/web-api); el código que hizo que se formulara esta pregunta hace tiempo que se reescribió utilizando la API web. Recomiendo encarecidamente no usar WCF para nada, a menos que esté [atascado en la edad media y realmente necesite SOAP] (http://stackoverflow.com/questions/11317572/asp-net-webapi-soap). – gregmac

Respuesta

27

En realidad es <enableWebScript />no requerida para el apoyo JSON "pura". El WebScriptEnablingBehavior solo es necesario si desea admitir ASP.NET AJAX. La mayoría de las veces, si intenta trabajar con librerías de scripts estándar, no desea querer habilitar este soporte para sus servicios.

En su lugar, lo que desea hacer para su punto final JSON es simplemente usar el WebHttpBehavior y establecer DefaultOutgoingResponseFormat = "JSON". El problema es que, en .NET 3.5, no puede controlar esta configuración a través de la configuración porque WebHttpElement no expone estas propiedades para la configuración. Para solucionar esto en 3.5 hemos suministrado una implementación para lo que llamo EnhancedWebHttpElementhere in this answer a otra pregunta de StackOverflow.

Afortunadamente Microsoft se dio cuenta de esta limitación y habilitó la configuración de todas las configuraciones WebHttpBehavior a través del WebHttpElement in 4.0.

4

La respuesta de Drew es perfecta, pero creo que la pregunta sigue en pie.¿Hay una manera sensata de tener JSON para AJAX() y las bendiciones de UriTemplate?

Creo que vale la pena mencionar que JSON devuelto es diferente de JSON generado con [WebGet (ResponseFormat = WebMessageFormat.Json)]. El primero se basa en el elemento 'd' de MS AJAX, p. {"re":[{...}]}.

0

Ha especificado parámetros enteros en su operación. La plantilla de URI no funciona bien con los parámetros int. Por favor, cámbialo a una cadena, Funcionará.

Creo que tiene que escribir su propio QuerystringConverter para usar int con URITemplate.

Cuestiones relacionadas