REST风格的WCF Web服务POST问题 [英] RESTful WCF web service POST problem

查看:111
本文介绍了REST风格的WCF Web服务POST问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不能越过参数WCF Web服务。我的Web方法:




  [OperationContract的] 
[WebInvoke(方法=POST ,
ResponseFormat = WebMessageFormat.Json,
UriTemplate =playersJson2)]
名单,LT;人> GetPlayers(字符串名称1,串名2);




当我提出HTTP POST请求,我买了200 OK响应正确的JSON形式,但Web服务似乎轮不到paramters(1,名称2)。 Wireshark的显示如下:结果



你看见什么了?



更新:不知道它的问题,但我的服务使用的WebHttpBinding和后请求来自Android的未来


解决方案

WCF不支持表格/编码数据外的箱子。提到一些替代品的其他答案(接收输入的一个流,变更请求JSON)。另一种选择,它不强迫你改变请求或操作要使用的理解窗体-urlencoded请求自定义格式。 。下面的代码显示其中一个做了



 公共类MyWebHttpBehavior:WebHttpBehavior 
{
保护覆盖IDispatchMessageFormatter GetRequestDispatchFormatter(OperationDescription operationDescription,ServiceEndpoint端点)
{
布尔isRequestWrapped = this.IsRequestWrapped(operationDescription.Behaviors.Find< WebInvokeAttribute>());
IDispatchMessageFormatter originalFormatter = base.GetRequestDispatchFormatter(operationDescription,终点);
如果(isRequestWrapped)
{
返回新MyFormUrlEncodedAwareFormatter(
operationDescription,
originalFormatter,
this.GetQueryStringConverter(operationDescription));
}
,否则
{
返回originalFormatter;
}
}

私人布尔IsRequestWrapped(WebInvokeAttribute WIA)
{
WebMessageBodyStyle bodyStyle;
如果(wia.IsBodyStyleSetExplicitly)
{
bodyStyle = wia.BodyStyle;
}
,否则
{
bodyStyle = this.DefaultBodyStyle;
}

返回bodyStyle == || WebMessageBodyStyle.Wrapped bodyStyle == WebMessageBodyStyle.WrappedRequest;
}

类MyFormUrlEncodedAwareFormatter:IDispatchMessageFormatter
{
常量字符串FormUrlEncodedContentType =应用/的X WWW的形式,进行了urlencoded
OperationDescription操作;
IDispatchMessageFormatter originalFormatter;
QueryStringConverter queryStringConverter;
公共MyFormUrlEncodedAwareFormatter(OperationDescription操作,IDispatchMessageFormatter originalFormatter,QueryStringConverter queryStringConverter)
{
this.operation =操作;
this.originalFormatter = originalFormatter;
this.queryStringConverter = queryStringConverter;
}

公共无效DeserializeRequest(消息消息,对象[]参数)
{
如果(IsFormUrlEncodedMessage(消息))
{
XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents();
bodyReader.ReadStartElement(二进制);
字节[] = bodyBytes bodyReader.ReadContentAsBase64();
绳体= Encoding.UTF8.GetString(bodyBytes);
的NameValueCollection对= HttpUtility.ParseQueryString(体);
&字典LT;字符串,字符串>值=新词典<字符串,字符串>();
的foreach(在pairs.AllKeys VAR键)
{
values.Add(键,对[关键]);
}

的foreach(在this.operation.Messages VAR部分[0] .Body.Parts)如果
{
(values.ContainsKey(part.Name) )
{
字符串值=值[part.Name]
参数[part.Index] = this.queryStringConverter.ConvertStringToValue(值,part.Type);
}
,否则
{
参数[part.Index] = GetDefaultValue(part.Type);
}
}
}
,否则
{
this.originalFormatter.DeserializeRequest(消息,参数);
}
}

公共信息SerializeReply(MessageVersion messageVersion,对象[]参数,对象的结果)
{
抛出新NotSupportedException异常(这是一个只请求格式);
}

私人静态布尔IsFormUrlEncodedMessage(消息消息)
{
对象道具;
如果(message.Properties.TryGetValue(WebBodyFormatMessageProperty.Name,出道具))
{
如果(((WebBodyFormatMessageProperty)丙).Format == WebContentFormat.Raw)
{
如果(message.Properties.TryGetValue(HttpRequestMessageProperty.Name,出道具))
{
如果(((HttpRequestMessageProperty)道具).Headers [HttpRequestHeader.ContentType] .StartsWith(FormUrlEncodedContentType))
{
返回真;
}
}
}
}

返回FALSE;
}

私有静态对象GetDefaultValue(type类型)
{
如果(type.IsValueType)
{
返回Activator.CreateInstance(类型);
}
,否则
{
返回NULL;
}
}
}
}
[的ServiceContract]
公共类服务
{
[WebInvoke(BodyStyle = WebMessageBodyStyle。 WrappedRequest)]
公共字符串连接(字符串文本1,字符串文本2)
{
返回文本1 + text2的;
}

[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)]
公众诠释添加(INT X,int y)对
{
返回X + Y ;
}
}
类节目
{
公共静态无效sendRequest将(字符串URI,字符串的方法,字符串的contentType,弦体)
{
HttpWebRequest的REQ =(HttpWebRequest的)HttpWebRequest.Create(URI);
req.Method =方法;
如果
{
req.ContentType的contentType =(String.IsNullOrEmpty(contentType中)!);
}

如果(身体!= NULL)
{
字节[] = bodyBytes Encoding.UTF8.GetBytes(体);
req.GetRequestStream()写(bodyBytes,0,bodyBytes.Length);
req.GetRequestStream()关闭()。
}

HttpWebResponse RESP;

{
RESP =(HttpWebResponse)req.GetResponse();
}
赶上(引发WebException五)
{
RESP =(HttpWebResponse)e.Response;
}
Console.WriteLine(HTTP / {0} {1} {2},resp.ProtocolVersion,(INT)resp.StatusCode,resp.StatusDescription);
的foreach(在resp.Headers.AllKeys串headerName)
{
Console.WriteLine({0}:{1},headerName,resp.Headers [headerName]);
}
Console.WriteLine();
Console.WriteLine(新的StreamReader(resp.GetResponseStream())为ReadToEnd());
Console.WriteLine();
Console.WriteLine(* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *);
Console.WriteLine();
}

静态无效的主要(字串[] args)
{
串baseAddress =HTTP://+ Environment.MachineName +:8000 /服务
ServiceHost的主机=新的ServiceHost(typeof运算(服务),新的URI(baseAddress));
host.AddServiceEndpoint(typeof运算(服务),新的WebHttpBinding(),).Behaviors.Add(新MyWebHttpBehavior());
host.Open();
Console.WriteLine(主机开);

sendRequest将(baseAddress +/添加,POST,应用/ JSON,{\x\:22,\y\:33} );
sendRequest将(baseAddress +/添加,POST,应用程序/ x-WWW的形式,进行了urlencoded,X = 22安培; Y = 33);
sendRequest将(baseAddress +/添加,POST,应用/ JSON,{\x\:22,\z\:33});
sendRequest将(baseAddress +/添加,POST,应用程序/ x-WWW的形式,进行了urlencoded,X = 22安培; Z = 33);

sendRequest将(baseAddress +/的毗连,POST,应用/ JSON,{\text1\:\hello\,\text2\\ \\:\world\});
sendRequest将(baseAddress +/的毗连,POST,应用程序/ x-WWW的形式,进行了urlencoded,文本1 =你好&安培;文本2 =%20world);
sendRequest将(baseAddress +/的毗连,POST,应用/ JSON,{\text1\:\hello\,\text9\:\\ \\world\});
sendRequest将(baseAddress +/的毗连,POST,应用程序/ x-WWW的形式,进行了urlencoded,文本1 =你好&安培; text9 =%20world);
}
}


I can't pass over parameters to wcf web service. My web method:

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

When I make http post request, I got 200 OK response with correct json form but web service seems to fail to get paramters (name1, name2). Wireshark shows following:

Do you see anything wrong?

Update: Not sure it matters but my service is using "webHttpBinding" and post request is coming from Android.

解决方案

WCF doesn't support forms/encoded data out-of-the box. The other answers mentioned some alternatives (receive the input as a Stream, change the request to JSON). Another alternative, which doesn't force you to change the request or the operation is to use a custom formatter which understands form-urlencoded requests. The code below shows one which does that.

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");
    }
}

这篇关于REST风格的WCF Web服务POST问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆