WCF RESTful service returns 400 when sending raw XML

I hit my head against the wall for two days with this, hope someone can give me a hand. I have a RESTful web service that I wrote using WCF; for this there is nothing just two methods that take a single string parameter, and also return a string. Both parameters and return value are direct XML.

[ServiceContract] public interface IService { [OperationContract] [WebGet(UriTemplate = "/method1/{data}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml)] string Method1(string data); [OperationContract] [WebGet(UriTemplate = "/method2/{data}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml)] string Method2(string data); } 

For the argument, we can say that the implementation of both of these methods looks like this:

 public string Method1(string data) { return string.Format("You entered: {0}", data); } 

If I go to http://myuri.com/service.svc/method1/foo, the following is written in the browser:

  <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">You entered: foo</string> 

This works fine, but if I change the URL to: http://myuri.com/service.svc/method1/ <foo> I get 400 (invalid request). So I turned on some indicators to see what was happening using the following code:

 <system.diagnostics> <sources> <source name="System.ServiceModel" switchValue="All"> <listeners> <add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData= "c:\Traces.svclog" /> </listeners> </source> </sources> 

As you can see, I use the value of the "All" switch to capture every event that occurs during the execution of this service. I came back several times using the URL format, which works to check if the tracing devices were working, and they were. Then I went to the URL containing the XML tag foo and got a 400 error as expected, but when I returned to the log file, no additional information was added to the end. This leads me to believe that error 400 is displayed before calling the WCF service.

Finally, I switched methods from GET methods to POST methods, wrote some code using WebRequest / WebResponse with the same result. Now I read a few posts on how to use the client-side XmlSerializer to send data to the service, but this defeats the purpose of this service. Although I use .NET to record the service, it is likely that PHP or classic ASP scripts will connect to this service, and they obviously do not have access to the XmlSerializer.

So my million dollar question is: is it possible to send a β€œraw” XML request to the RESTful web service developed by WCF, and if so, how?

PS XML entering and leaving a service is not based on any material object, but simply on the structure that I created for use with this service. The XML arrival is processed through XPath, the values ​​are placed in a large XML string and passed to the external API. The results of this API are processed and then returned by the RESTful service.

Any help would be greatly appreciated!

+7
c # rest wcf
source share
4 answers

Bret, thanks for the bit of code. Unfortunately, I found in this thread: WCF Rest parameters containing complex types , and tried to do this before publishing.

Anyway, I solved this problem. Now I would like to say that I had the full moment of Eureka, and everything just got together, but the fact is that I just started throwing acronyms on Google, and one of the SERP led me to this link: http: // blogs.msdn.com/pedram/archive/2008/04/21/how-to-consume-rest-services-with-wcf.aspx

The link itself does not directly address this issue, but it made me think about how I put together my URI templates. I read this MSDN article http://msdn.microsoft.com/en-us/library/dd203052.aspx on how to build a RESTful service. In this example, the author provides several different L templates, some of which use the typical esque querystring parameter template, and some not. For some reason, I am choosing a template that was devoid of the typical querystring parameter, as can be seen in my original post. So I changed my code a bit and came up with the following:

 [OperationContract] [WebGet(UriTemplate = "/method1/?xml={data}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml)] string Method2(string data); 

Note that the URI pattern is the only thing that has changed; changing "/ method1 / {data}" to "/ method1 /? xml = {data}. Then I went to http://myuri.com/service.svc/method1/?xml= and alt, everything worked perfectly!

It was also a problem with POST. For some reason, passing XML to the content body, even as a key / value pair, caused a 400 error. Using the same URI pattern shown above, I opened Fiddler, executed POST, and the result was 200 OK.

Thanks for helping everyone.

+3
source share

one of the main reasons the source code didn't work was that any xml string data had to be encoded at the url if it was passed in the url path or in the query string.

in my opinion, however, if you want the client to send you the data as xml in your service method, then it should not be executed in the URL. The URL has an undefined maximum length, depending on the browser, the version of iis, as well as any web proxies that are between the client on the server.

this means sending data to the request body, which means a verb other than GET. So let me use POST.

declare the parameter "data", as before, in the method signature, but output the parameter from UriTemplate and make it WebInvoke (by default it is POST, as you know).

 [WebInvoke(UriTemplate = "/method1", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml)] string Method2(string data); 

Then your POST requests should be formatted as follows:

 <data><![CDATA[data xml goes in here]]></data> 

Why a CDATA partition? Think about the type of target parameter - the string. You want to pass the XML in this line. Therefore, you need to make sure that the WCF serializer does not consider data as complex data that must be read directly. The same would be true if your request format was JSON and you wanted to send a JSON string to the service.

+3
source share

I do not believe that you will be able to pass raw XML code to a URL, but you can do it in code. I have written clients for RESTful web services that run on the Compact Framework that have no problem deserializing raw XML objects and sending them to the service through HttpWebRequest and HttpWebResponse.

If you are doing a GET, you simply create the URL in the code. If you are doing POST, you can attach XML as an array of bytes (the code is below .Net, but you can do something similar in PHP).

 private HttpWebRequest DoInvokeRequest<T>(string uri, string method, T requestBody) { string destinationUrl = _baseUrl + uri; var invokeRequest = WebRequest.Create(destinationUrl) as HttpWebRequest; if (invokeRequest == null) return null; invokeRequest.Method = method; invokeRequest.ContentType = "text/xml"; byte[] requestBodyBytes = ToByteArray(requestBody); invokeRequest.ContentLength = requestBodyBytes.Length; AddRequestHeaders(invokeRequest); using (Stream postStream = invokeRequest.GetRequestStream()) postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length); invokeRequest.Timeout = 60000; return invokeRequest; } private static byte[] ToByteArray<T>(T requestBody) { byte[] bytes; using (var s = new MemoryStream()) { var serializer = new XmlSerializer(typeof (T)); serializer.Serialize(s, requestBody); bytes = s.ToArray(); } return bytes; } 
+1
source share

From my understanding of WCF services providing RESTful APIs, a large payload is not allowed. In fact, by default, WCF services are designed to send small messages back and forth.

On the machine I tested, I was unable to get the XML payload (XML file) returned from the WCF service displayed through the REST-ful endpoint, which was more than 2.7 MB .

From digging and searching the WCF LOTS documentation, I came to the conclusion that WCF is designed for small messages in buffered mode. When switching to streaming mode, large messages can be sent back and forth.

However, if you expose WCF services through IIS using RESTful, then you cannot stream the response as this is not supported. Or at least I could never figure it out.

I'm sorry that I didn’t have a great answer to the sample code for you, but from what I could distinguish from my own experiments, it was that I could not return the large useful XML data from the WCF service opened through the IIS endpoint .

My conclusion is that WCF is really a network solution that is retro-fitted (poorly) in IIS to try to provide web services. I would recommend using ASP.NET MVC to create RESTful web services without using WCF at all.

+1
source share

All Articles