REST风格的WCF Web服务POST问题 [英] RESTful WCF web service POST problem
问题描述
我不能越过参数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屋!