2011-06-22 18 views
10

私はWCF GETサービスに対して実行したいAJAX呼び出しを持っています。基本的には、(jqueryの経由)サービスへの呼び出しは次のようになります。このコールが実行されます場合はGET経由でWCFサービスに配列を渡す

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

、私は放火犯でGETが正しくて行くのを見て、私はエンドポイントをヒット行います。ただし、パラメータstatusTypesは常にnullです。

jqueryのからGET自体は、それがエンコードされているように見えますが、私はブラケットをコードしていないとき、コールは全くのエンドポイントになりません。

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

をとWCFサービス自体:

[OperationContract]

[WebInvoke( METHOD = "GET"、bodyStyle属性= WebMessageBodyStyle.WrappedRequest、
ResponseFormat = WebMessageFormat.Json)]

公共 ResultsViewModel GetTags(文字列のクエリ、[] statusTypesをint型)

はそれが可能ですGET経由でWCFサービスに配列を渡すには?

順列は数多くないので、私は個々のエンドポイントを「配列ごと」書くことができますが、それを1つに保ちたいと思います。

+1

、あなたは(あなたの配列を文字列に変換し、その後のstring.Splitを使用して、あなたのサービスでそれを解析)。 – Zachary

答えて

9

アウトオブザボックスWCFでは可能ですが、不可能です。 WCF codeplex pageの "jQuery support"を使用すると、ボディ(POST要求の場合)とクエリ文字列(forの場合)の両方で、型なし変数のjQuery(配列、入れ子オブジェクトなど)から送信されたすべてのデータを受け取ることができます。取得する)。 jQuery配列変数(名前に '['と ']'が含まれる)と操作パラメータのマッピングは、WCF 4.0では(少なくともメッセージフォーマッタを記述しなくても)実行できません。

ただし、これは新しいWCF Web API(codeplexサイトでも使用可能)で簡単になります。

更新:これはあなたのシナリオのために働くのフォーマッタの例である:回避策として

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

コードの代わりにapp.configを使用してカスタム動作クラスを登録する方法はありますか? –

+1

自分自身で答えを見つけました - カスタムビヘイビア拡張から返す必要があります:http://www.codeproject.com/Articles/37156/Focus-on-the-Extension-of-WCF-Behaviorそしてビヘイビア拡張web.configで –

2

不可能です。 URLの値の配列をパラメータにマップすることはできません。配列を渡す場合は、HTTP POSTを使用します。

+0

あなたは実際に(他の答えを見ることができます)、それは簡単ではありません。 – carlosfigueira

+0

@carlos:はいわかります。非常に良い答えとそれを動作させるための多くの仕事。私の答えは、現在のUriTemplateがサポートしているものをよりターゲットとしていました。私は拡張について考えなかった。生のリクエストをストリームとして取得し、クエリ文字列を抽出することもできます。 –

関連する問題