RESTful WCF Web服务POST问题

时间:2011-07-07 02:00:28

标签: c# wcf http-post

我无法将参数传递给wcf web服务。我的网络方法:

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

当我发出http post请求时,我用正确的json格式获得了200 OK响应但是web服务似乎无法获得参数(name1,name2)。 Wireshark显示以下内容:
enter image description here

你知道有什么不对吗?

更新:不确定是否重要,但我的服务正在使用“webHttpBinding”,而发布请求来自Android。

4 个答案:

答案 0 :(得分:4)

WCF不支持开箱即用的表单/编码数据。其他答案提到了一些替代方案(将输入作为Stream接收,将请求更改为JSON)。另一种不强制您更改请求或操作的替代方法是使用自定义格式化程序来理解form-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");
    }
}

答案 1 :(得分:0)

看起来你需要解析你的帖子数据手册......

您可以查看here例如

答案 2 :(得分:-1)

唯一看起来不合适的是playerJson2,但这只是因为我之前从未使用过UriTemplate。你可以在没有UriTemplate的情况下让它工作,只需发布​​到/WcfService1/Service1.svc/GetPlayers吗?您是否在项目中使用过其他WCF服务?

答案 3 :(得分:-1)

在这种情况下,您需要设置正确的Content-Type application/json

很抱歉误读了您的问题。按如下方式更新您的UriTemplate:

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