c# - RESTful WCF Web 服务 POST 问题

标签 c# wcf http-post

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

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

当我发出 HTTP POST 请求时,我得到了 200 OK 响应和正确的 json 格式,但 Web 服务似乎无法获取参数(名称 1、名称 2)。 Wireshark 显示如下:
enter image description here

你看到什么不对了吗?

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

最佳答案

WCF 不支持开箱即用的表单/编码数据。其他答案提到了一些替代方案(将输入作为流接收,将请求更改为 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");
    }
}

关于c# - RESTful WCF Web 服务 POST 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6605042/

相关文章:

wcf - 如何从 Internet 访问内部的 asp.net web 应用程序?

wcf - 如何使用azure和wp7将图片上传到blob

java - 如何使用 httpUrlConnection 获取 url 的查询字符串,android

rest - 使用 WifiESP 库对带有 ESP8266 的 arduino 进行 POST 请求

javascript - 从使用 Trigger.io 构建的移动应用程序发送发布请求

c# - Datagridview 组合框列不显示选择组合框值

c# - 如何使用 'with' 关键字添加?

c# - Entity Framework 中的 Sql Char(13) 和 isnull 的替代品是什么?

c# - 如何更改数字反序列化的默认类型?

asp.net - 使用像 asmx 服务一样的 aspx 页面