2011-07-07 131 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