2012-05-10 14 views
7

Sto riscontrando problemi nel tentativo di utilizzare un servizio semplice con WCF. Tutto è andato bene finora, tranne quando si tratta di implementare parametri di stringa di query opzionali. L'interfaccia sembra un po 'come questo:Consumo del servizio REST con WCF - Parametri facoltativi di QueryString?

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

Allora questo è consumato con la creazione di una classe che eredita ClientBase<IApi>. Ho provato un paio di modi per rendere i parametri opzionali:

1) Verificare i parametri annullabili

Ciò non ha funzionato. Ricevo un messaggio dal QueryStringConverter come un'altra domanda ha chiesto: Can a WCF service contract have a nullable input parameter?

2) Uno dei parametri alla fine dell'URL

Così, ho pensato di cambiare l'UriTemplate per essere più generico, costruendo la query stringa e passandola come parametro. Anche questo non sembra funzionare, dato che il valore passato viene codificato in modo tale da non essere riconosciuto come una querystring dal server.

Esempio:

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

3) Hackish Soluzione

L'unico modo che ho trovato finora di ottenere questo al lavoro è quello di cambiare tutti i parametri di stringhe e NULL di sembrano essere consentito Qui.

Esempio:

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

Il consumo di questa interfaccia ancora accetta il tipo di variabile corretto, ma ToString viene utilizzato. I parametri della stringa di query appaiono ancora nella richiesta effettiva.

Quindi, c'è un modo quando consuma un servizio REST utilizzando WCF, per rendere facoltativi i parametri della stringa di query?

UPDATE - Come è stato fissato

Il consiglio di creare un servizio di comportamento è stata presa. Questo eredita da WebHttpBehaviour. Sembra come segue:

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

Il NullableWebHttpBehavior si possono trovare presso la seguente questione StackOverflow: Can a WCF service contract have a nullable input parameter?. L'unico problema era, ConvertValueToString non era sovraccarico, così ho montata una veloce up:

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

Questo può non essere perfetto, ma sembra funzionare come previsto.

+1

questo va a mostrare quanto wcf fa schifo. è incredibile quanti cerchi devi saltare per elaborare una cosa così semplice – jere

+0

@jere d'accordo, è deludente. –

+0

Concordato che wcf è estremamente complesso per la creazione di applicazioni di tipo rest-style. Il problema che wcf cerca di risolvere è rendere i servizi visualizzabili su diversi protocolli (tcp, msmq e http) e il resto è per sua natura legato a http. Quindi potresti obiettare che wcf è la scelta sbagliata per l'implementazione dei servizi di riposo. – faester

risposta

1

L'opzione 1) può funzionare per un client WCF perché lo WebHttpBehavior può essere applicato a una classe derivata ClientBase (o ChannelFactory) come mostrato in questo SO question & answer. Basta combinare il codice di riferimento in 1) con la configurazione mostrata nell'acquisizione 500 domande risposta e mostra il lavoro.

+0

Grazie. Ho aggiunto i dettagli di implementazione alla mia risposta. – Mig

0

Hai provato a utilizzare i tipi nullable?

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