2012-05-10 30 views
7

Tengo problemas para intentar consumir un servicio simple usando WCF. Todo ha ido bien hasta ahora, excepto cuando se trata de implementar parámetros de cadena de consulta opcionales. La interfaz se ve un poco como esto:¿Consumo de servicio REST con WCF - Parámetros de Querystring opcionales?

[ServiceContract] 
[XmlSerializerFormat] 
public interface IApi 
{ 
    [OperationContract] 
    [WebGet(UriTemplate = "/url/{param}?top={top}&first={first}")] 
    object GetStuff(string param, int top, DateTime first); 
} 

Entonces este es consumido por la creación de una clase que hereda ClientBase<IApi>. He intentado un par de maneras de hacer que los parámetros opcionales:

1) Hacer los parámetros nullable

Esto no funcionó. Me sale un mensaje de la QueryStringConverter como otra cuestión ha preguntado: Can a WCF service contract have a nullable input parameter?

2) Un parámetro al final de la URL

lo tanto, pensé en cambiar el UriTemplate para ser más genérico, la construcción de la consulta cadena y pasándolo como un parámetro. Esto tampoco pareció funcionar, ya que el valor pasado se codifica de tal manera que el servidor no lo reconoce como una cadena de consulta.

Ejemplo:

[WebGet(UriTemplate = "/url/{query}")] 

3) hacker Solución

La única manera que he encontrado hasta el momento de conseguir que esto funcione es cambiar todos los parámetros en cadenas, y NULL de parecen estar permitido aquí.

Ejemplo:

[WebGet(UriTemplate = "/url/{param}?top={top}&first={first}")] 
object GetStuff(string param, string top, string first); 

El consumo de esta interfaz todavía acepta el tipo de variable correcto, pero ToString se utiliza. Los parámetros de cadena de consulta siguen apareciendo en la solicitud real.

Entonces, ¿hay alguna manera cuando consume un servicio REST usando WCF, para hacer que los parámetros de cadena de consulta sean opcionales?

ACTUALIZACIÓN - ¿Cómo se fija

El consejo para crear un comportamiento en servicio fue tomada. Esto hereda de WebHttpBehaviour. Se ve de la siguiente manera:

public class Api : ClientBase<IApi> 
{ 
    public Api() : base("Binding") 
    { 
     Endpoint.Behaviors.Add(new NullableWebHttpBehavior()); 
    } 
} 

El NullableWebHttpBehavior se puede encontrar en la siguiente pregunta Stackoverflow: Can a WCF service contract have a nullable input parameter?. El único problema era, ConvertValueToString no estaba sobrecargado, así que sacó una rápida un gol arriba:

public override string ConvertValueToString(object parameter, Type parameterType) 
    { 
     var underlyingType = Nullable.GetUnderlyingType(parameterType); 

     // Handle nullable types 
     if (underlyingType != null) 
     { 
      var asString = parameter.ToString(); 

      if (string.IsNullOrEmpty(asString)) 
      { 
       return null; 
      } 

      return base.ConvertValueToString(parameter, underlyingType); 
     } 

     return base.ConvertValueToString(parameter, parameterType); 
    } 

Esto puede no ser perfecto, pero parece que funciona según lo previsto.

+1

esto va a mostrar cuánto wcf apesta. es increíble cuántos aros tienes que saltar para resolver algo tan simple – jere

+0

@jere estuvo de acuerdo, es decepcionante. –

+0

Estoy de acuerdo en que wcf es abiertamente complejo para crear aplicaciones de estilo de descanso. El problema que trata de resolver es hacer que los servicios sean visibles en diferentes protocolos (tcp, msmq y http) y el resto está vinculado por naturaleza a http. Entonces, podría argumentar que wcf es la opción incorrecta para implementar servicios de descanso. – faester

Respuesta

1

Su opción 1) puede funcionar para un cliente WCF porque WebHttpBehavior se puede aplicar a una clase derivada ClientBase (o ChannelFactory) como se muestra en este SO question & answer. Simplemente combine el código al que hace referencia en 1) con la configuración que se muestra en la captura 500 respuestas pregunta y muestra el trabajo.

+0

Gracias. He agregado los detalles de implementación a mi respuesta. – Mig

0

¿Has probado el uso de tipos que aceptan nulos?

object GetStuff(string param, int? top, DateTime? first);