2011-07-07 124 views
4

我無法將參數傳遞給wcf Web服務。我的Web方法:RESTful WCF Web服務POST問題

[OperationContract] 
    [WebInvoke(Method = "POST", 
     ResponseFormat = WebMessageFormat.Json, 
     UriTemplate = "playersJson2")] 
    List<Person> GetPlayers(string name1, string name2); 

當我做HTTP POST請求,我得到正確的JSON形式200 OK響應,但Web服務似乎輪不到paramters(1,名稱)。 Wireshark顯示如下:
enter image description here

你看到有什麼不對嗎?

更新:不確定它很重要,但我的服務使用「webHttpBinding」和發佈請求來自Android。

回答

4

WCF不支持表格/編碼數據盒子外面。其他答案提到了一些替代方法(將輸入作爲Stream接收,將請求更改爲JSON)。另一種不強制你改變請求或操作的選擇是使用一個能夠理解表單urlencoded請求的自定義格式器。下面的代碼顯示了一個這樣做。

public class MyWebHttpBehavior : WebHttpBehavior 
{ 
    protected override IDispatchMessageFormatter GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint) 
    { 
     bool isRequestWrapped = this.IsRequestWrapped(operationDescription.Behaviors.Find<WebInvokeAttribute>()); 
     IDispatchMessageFormatter originalFormatter = base.GetRequestDispatchFormatter(operationDescription, endpoint); 
     if (isRequestWrapped) 
     { 
      return new MyFormUrlEncodedAwareFormatter(
       operationDescription, 
       originalFormatter, 
       this.GetQueryStringConverter(operationDescription)); 
     } 
     else 
     { 
      return originalFormatter; 
     } 
    } 

    private bool IsRequestWrapped(WebInvokeAttribute wia) 
    { 
     WebMessageBodyStyle bodyStyle; 
     if (wia.IsBodyStyleSetExplicitly) 
     { 
      bodyStyle = wia.BodyStyle; 
     } 
     else 
     { 
      bodyStyle = this.DefaultBodyStyle; 
     } 

     return bodyStyle == WebMessageBodyStyle.Wrapped || bodyStyle == WebMessageBodyStyle.WrappedRequest; 
    } 

    class MyFormUrlEncodedAwareFormatter : IDispatchMessageFormatter 
    { 
     const string FormUrlEncodedContentType = "application/x-www-form-urlencoded"; 
     OperationDescription operation; 
     IDispatchMessageFormatter originalFormatter; 
     QueryStringConverter queryStringConverter; 
     public MyFormUrlEncodedAwareFormatter(OperationDescription operation, IDispatchMessageFormatter originalFormatter, QueryStringConverter queryStringConverter) 
     { 
      this.operation = operation; 
      this.originalFormatter = originalFormatter; 
      this.queryStringConverter = queryStringConverter; 
     } 

     public void DeserializeRequest(Message message, object[] parameters) 
     { 
      if (IsFormUrlEncodedMessage(message)) 
      { 
       XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents(); 
       bodyReader.ReadStartElement("Binary"); 
       byte[] bodyBytes = bodyReader.ReadContentAsBase64(); 
       string body = Encoding.UTF8.GetString(bodyBytes); 
       NameValueCollection pairs = HttpUtility.ParseQueryString(body); 
       Dictionary<string, string> values = new Dictionary<string, string>(); 
       foreach (var key in pairs.AllKeys) 
       { 
        values.Add(key, pairs[key]); 
       } 

       foreach (var part in this.operation.Messages[0].Body.Parts) 
       { 
        if (values.ContainsKey(part.Name)) 
        { 
         string value = values[part.Name]; 
         parameters[part.Index] = this.queryStringConverter.ConvertStringToValue(value, part.Type); 
        } 
        else 
        { 
         parameters[part.Index] = GetDefaultValue(part.Type); 
        } 
       } 
      } 
      else 
      { 
       this.originalFormatter.DeserializeRequest(message, parameters); 
      } 
     } 

     public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result) 
     { 
      throw new NotSupportedException("This is a request-only formatter"); 
     } 

     private static bool IsFormUrlEncodedMessage(Message message) 
     { 
      object prop; 
      if (message.Properties.TryGetValue(WebBodyFormatMessageProperty.Name, out prop)) 
      { 
       if (((WebBodyFormatMessageProperty)prop).Format == WebContentFormat.Raw) 
       { 
        if (message.Properties.TryGetValue(HttpRequestMessageProperty.Name, out prop)) 
        { 
         if (((HttpRequestMessageProperty)prop).Headers[HttpRequestHeader.ContentType].StartsWith(FormUrlEncodedContentType)) 
         { 
          return true; 
         } 
        } 
       } 
      } 

      return false; 
     } 

     private static object GetDefaultValue(Type type) 
     { 
      if (type.IsValueType) 
      { 
       return Activator.CreateInstance(type); 
      } 
      else 
      { 
       return null; 
      } 
     } 
    } 
} 
[ServiceContract] 
public class Service 
{ 
    [WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)] 
    public string Concat(string text1, string text2) 
    { 
     return text1 + text2; 
    } 

    [WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)] 
    public int Add(int x, int y) 
    { 
     return x + y; 
    } 
} 
class Program 
{ 
    public static void SendRequest(string uri, string method, string contentType, string body) 
    { 
     HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri); 
     req.Method = method; 
     if (!String.IsNullOrEmpty(contentType)) 
     { 
      req.ContentType = contentType; 
     } 

     if (body != null) 
     { 
      byte[] bodyBytes = Encoding.UTF8.GetBytes(body); 
      req.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length); 
      req.GetRequestStream().Close(); 
     } 

     HttpWebResponse resp; 
     try 
     { 
      resp = (HttpWebResponse)req.GetResponse(); 
     } 
     catch (WebException e) 
     { 
      resp = (HttpWebResponse)e.Response; 
     } 
     Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription); 
     foreach (string headerName in resp.Headers.AllKeys) 
     { 
      Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]); 
     } 
     Console.WriteLine(); 
     Console.WriteLine(new StreamReader(resp.GetResponseStream()).ReadToEnd()); 
     Console.WriteLine(); 
     Console.WriteLine(" *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* "); 
     Console.WriteLine(); 
    } 

    static void Main(string[] args) 
    { 
     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"); 

     SendRequest(baseAddress + "/Add", "POST", "application/json", "{\"x\":22,\"y\":33}"); 
     SendRequest(baseAddress + "/Add", "POST", "application/x-www-form-urlencoded", "x=22&y=33"); 
     SendRequest(baseAddress + "/Add", "POST", "application/json", "{\"x\":22,\"z\":33}"); 
     SendRequest(baseAddress + "/Add", "POST", "application/x-www-form-urlencoded", "x=22&z=33"); 

     SendRequest(baseAddress + "/Concat", "POST", "application/json", "{\"text1\":\"hello\",\"text2\":\" world\"}"); 
     SendRequest(baseAddress + "/Concat", "POST", "application/x-www-form-urlencoded", "text1=hello&text2=%20world"); 
     SendRequest(baseAddress + "/Concat", "POST", "application/json", "{\"text1\":\"hello\",\"text9\":\" world\"}"); 
     SendRequest(baseAddress + "/Concat", "POST", "application/x-www-form-urlencoded", "text1=hello&text9=%20world"); 
    } 
} 
+0

即使我沒有嘗試你的代碼,我認爲你是對的,WCF默認不支持非XML/JSON的東西。我會嘗試以json的形式發送請求。謝謝 – bob

-1

唯一看起來不合適的地方是playerJson2,但那只是因爲我以前從未使用過UriTemplate。你可以讓它在沒有UriTemplate的情況下工作,只需發佈​​到/WcfService1/Service1.svc/GetPlayers?您有沒有在項目中工作的其他WCF服務?

+0

對不起,這是我的錯字,我有其他GET方法工作正常。 – bob

-1

在這種情況下,您需要設置正確的 Content-Type,即 application/json

對不起您的問題。更新您的UriTemplate如下:

[WebInvoke(Method = "POST", 
     ResponseFormat = WebMessageFormat.Json, 
     UriTemplate = "playersJson2?name1={name1}&name2={name2}")]  
+0

但請求內容類型不是JSON; JSON將是'{「name1」:「Bob」,「name2」:「Joanne」}'而不是'name1 = Bob&name2 = Joanne1' – configurator

+0

application/json將是來自WCF服務的響應的內容類型,而不是請求的內容類型 – Alexander

+0

那麼這是另一個問題。查詢參數不能反序列化爲JSON對象(不是沒有使用一些黑客)。 – Mrchief

0

看起來你需要分析你的文章數據手冊......

你可以看看here例如

+0

感謝您的鏈接。這似乎很有幫助。也許與url編碼實體的問題,仍然在尋找什麼是錯的。 – bob