2011-06-22 40 views
10

Tengo una llamada AJAX que deseo ejecutar contra un servicio WCF GET. Básicamente, la llamada al servicio (a través de jQuery) tiene el siguiente aspecto:Pasar una matriz al servicio WCF a través de GET

$.get(serviceEndpoint, {query : "some search text", statusTypes: [1, 2]}, function (result) { /* do something*/ }, 'text'); 

Cuando esta llamada se ejecuta, veo el ponerse en Firebug ir a través correctamente, y se golpean el punto final. Sin embargo, el parámetro statusTypes siempre es nulo.

El GET sí mismo de jQuery parece que está codificado, pero cuando no codifican los soportes, la llamada no entrará en el punto final del todo:

http://localhost/Services/SomeService.svc/Endpoint?statusTypes%5B%5D=1&statusTypes%5B%5D=2&query=some+search+text

Y el servicio WCF sí:

[OperationContract]

[WebInvoke (Method = "GET", Carrocería = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json)]

pública ResultsViewModel getTags (cadena de consulta, int [] statusTypes)

¿Es posible pasar una matriz vía GET a un servicio WCF?

Las permutaciones no son numerosas, por lo que podría escribir un punto final individual "por conjunto", pero prefiero mantenerlo en uno.

+1

Como solución, a convertir su arreglo en una cadena y luego analizarlo en su servicio utilizando String.split () – Zachary

Respuesta

9

Es posible, pero no con el WCF listo para usar. Con el "soporte jQuery" en el WCF codeplex page, puede recibir todos los datos enviados por jQuery (incluyendo matrices, objetos anidados, etc.) en una variable sin tipo, tanto en el cuerpo (para solicitudes POST) como en la cadena de consulta (para OBTENER). La asignación entre las variables de la matriz jQuery (cuyos nombres contienen '[' y ']') y los parámetros de operación no se puede hacer en WCF 4.0 (al menos no sin escribir un formateador de mensajes).

Esto debería ser más simple, sin embargo, en las nuevas API web de WCF (también disponibles en el sitio codeplex).

actualización: este es un ejemplo de un formateador que trabaja para su escenario:

public class StackOverflow_6445171 
{ 
    [ServiceContract] 
    public class Service 
    { 
     [WebGet(ResponseFormat = WebMessageFormat.Json)] 
     public string GetLabelPacketTags(string query, int[] statusTypes) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.Append("Query=" + query); 
      sb.Append(", statusTypes="); 
      if (statusTypes == null) 
      { 
       sb.Append("null"); 
      } 
      else 
      { 
       sb.Append("["); 
       for (int i = 0; i < statusTypes.Length; i++) 
       { 
        if (i > 0) sb.Append(","); 
        sb.Append(statusTypes[i]); 
       } 
       sb.Append("]"); 
      } 

      return sb.ToString(); 
     } 
    } 
    class MyWebHttpBehavior : WebHttpBehavior 
    { 
     protected override IDispatchMessageFormatter GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint) 
     { 
      return new MyArrayAwareFormatter(operationDescription, this.GetQueryStringConverter(operationDescription)); 
     } 

     class MyArrayAwareFormatter : IDispatchMessageFormatter 
     { 
      OperationDescription operation; 
      QueryStringConverter queryStringConverter; 
      public MyArrayAwareFormatter(OperationDescription operation, QueryStringConverter queryStringConverter) 
      { 
       this.operation = operation; 
       this.queryStringConverter = queryStringConverter; 
      } 

      public void DeserializeRequest(Message message, object[] parameters) 
      { 
       if (message.Properties.ContainsKey("UriMatched") && (bool)message.Properties["UriMatched"]) 
       { 
        UriTemplateMatch match = message.Properties["UriTemplateMatchResults"] as UriTemplateMatch; 
        NameValueCollection queryValues = match.QueryParameters; 
        foreach (MessagePartDescription parameterDescr in this.operation.Messages[0].Body.Parts) 
        { 
         string parameterName = parameterDescr.Name; 
         int index = parameterDescr.Index; 
         if (parameterDescr.Type.IsArray) 
         { 
          Type elementType = parameterDescr.Type.GetElementType(); 
          string[] values = queryValues.GetValues(parameterName + "[]"); 
          Array array = Array.CreateInstance(elementType, values.Length); 
          for (int i = 0; i < values.Length; i++) 
          { 
           array.SetValue(this.queryStringConverter.ConvertStringToValue(values[i], elementType), i); 
          } 
          parameters[index] = array; 
         } 
         else 
         { 
          parameters[index] = this.queryStringConverter.ConvertStringToValue(queryValues.GetValues(parameterName)[0], parameterDescr.Type); 
         } 
        } 
       } 
      } 

      public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result) 
      { 
       throw new NotSupportedException("This is a request-only formatter"); 
      } 
     } 
    } 
    public static void Test() 
    { 
     string baseAddress = "http://" + Environment.MachineName + ":8000/Service"; 
     ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress)); 
     host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "").Behaviors.Add(new MyWebHttpBehavior()); 
     host.Open(); 
     Console.WriteLine("Host opened"); 

     WebClient c = new WebClient(); 
     Console.WriteLine(c.DownloadString(baseAddress + "/GetLabelPacketTags?query=some+text&statusTypes[]=1&statusTypes[]=2")); 
     Console.WriteLine(c.DownloadString(baseAddress + "/GetLabelPacketTags?query=some+text&statusTypes%5B%5D=1&statusTypes%5B%5D=2")); 

     Console.Write("Press ENTER to close the host"); 
     Console.ReadLine(); 
     host.Close(); 
    } 
} 
+0

¿Cómo registrarías la clase de comportamiento personalizado a través de app.config en lugar de código? –

+1

Encontré la respuesta yo mismo: debo devolverla desde una extensión de comportamiento personalizado: http://www.codeproject.com/Articles/37156/Focus-on-the-Extension-of-WCF-Behavior y agregar eso a las extensiones de comportamiento en web.config –

2

No, no es posible. No puede asignar una matriz de valores de URL a parámetro. Si quiere pasar una matriz, use HTTP POST.

+0

Realmente puede (ver otra respuesta), simplemente no es fácil de hacer. – carlosfigueira

+0

@carlos: Sí, ya veo. Muy buena respuesta y mucho trabajo para que funcione. Mi respuesta estaba más dirigida a lo que soporte actual de UriTemplate fuera de la caja. No pensé en la extensión. También puede capturar la solicitud sin procesar como una secuencia e intentar extraer la cadena de consulta. –

Cuestiones relacionadas