So i wrote my first WCF project, seems like its working using my browser and jquery, but then i wrote a client and things messed up a bit...
actually seems like everything i do with that client result in a 400 bad request response...
so i've read some posts and found out a good way to sort things up is using fiddler, and started picking around...
since fiddler can't identify my client, i've used my client to send the data directly to it...
https://docs.google.com/file/d/0ByOtHJSZT_GtNHZqTVZMdVVqZEU/edit?usp=sharing
you can see a screenshot here.
as i can see oly things that differs are the leack of some headers (that don't seems like really usefull to me) and one use content-type as application/jsonp the other text/html (wich i think is the main problem).
The bad thing is i've setted the content-type header before sending the request, but with no result, please notice that in the right panel you can still see application/json.
I'm getting confused.
private void SendSelectedFile()
{
string url = "http://" + WindowsFormsApplication1.Properties.Settings.Default.HostAddress + "/Service1.svc/rest/PostFileToServer";
string jsonMsg = "{\"fileContentAsBase64String\":\"" + this.textBox1.Text + "\",\"where\":\"D:\\Temp.dwg\"}";
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(jsonMsg);
HttpWebRequest wr = WebRequest.Create(new Uri(url)) as HttpWebRequest;
wr.Method = "POST";
wr.ContentType = "application/json; charset=utf-8";
wr.ContentLength = buffer.Length;
//wr.TransferEncoding = "UTF-8";
System.IO.Stream rs = wr.GetRequestStream();
rs.Write(buffer , 0, buffer.Length);
rs.Close();
WebResponse response = wr.GetResponse();
}
and this is the interface of the service
[WebInvoke(
Method = "POST",
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "/PostFileToServer"
)]
Boolean PostFileToServer(string fileContentAsBase64String, string where);
I tested your code, and I narrowed the 400 down to the value that's being passed to your where member:
string jsonMsg = "{\"fileContentAsBase64String\":\"" + this.textBox1.Text + "\",\"where\":\"D:\\Temp.dwg\"}";
I'm guessing you're trying to pass the value D:\Tempdwg, but the backslash \T seems to be getting interpreted by the server as an escape sequence. Try base64 encoding that value, or double escaping it \\\\
Related
In my WCF (azure cloud) service, I want to support JSON. I am creating some test methods to see if everything works. I can get the GET calls to work, but when I'm doing a POST with a simple parameter I will always get:
The remote server returned an error: (400) Bad Request.
If I don't send a parameter, it will execute the method, but with a null value as parameter of course. I tried different formats of JSON and WebMessageBodyStyle, but none seem to work.
If I change the parameter type to Stream I receive the data, but I have to manually deserialize it. This shouldn't be necessary right?
Interface:
[OperationContract]
[WebInvoke(UriTemplate = "Test",
Method = "POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
string Test(string data);
Impl:
public string Test(string data)
{
return "result is " + data;
}
Test client:
WebClient client = new WebClient();
client.Headers["Content-type"] = "application/json";
client.Encoding = System.Text.Encoding.UTF8;
string jsonInput = "{'data':'testvalue'}";
string postResponse = client.UploadString(postUrl, jsonInput);
Console.WriteLine("post response: " + postResponse);
The golden combination was to use double quotes in the JSON code combined with WebMessageBodyStyle.WrappedRequest.
Working JSON:
string jsonInput = "{\"data\":\"testvalue\"}";
When setting WebMessageBodyStyle to Bare, the following JSON works:
string jsonInput = "\"testvalue\"";
I have a WCF RESTful service that is supposed to return a name and surname of a customer as a XML response, the service is defined as indicated below
[OperationContract]
[WebInvoke(Method = "POST",
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/GetNameAndSurname")]
string GetNameAndSurname();
The problem I'm experiencing is that the XML response that is returned was not in normal XML as expected, for example
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
<Customer;
<Name>Andre</Name>
<SurnameName>Lombaard</SurnameName>
>
</string>
I'm not sure if it is the service returning the response this way or if it is the way I'm reading the data, just for informational purposes I included the code I use to read the response below,
var request = HttpWebRequest.Create(url);
request.Method = "POST";
request.Timeout = 2 * 60 * 1000;
byte[] byteArray = Encoding.UTF8.GetBytes(xml);
request.ContentType = "text/xml";
request.ContentLength = byteArray.Length;
var dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
var response = request.GetResponse();
dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream, Encoding.UTF8);
dataStream.Flush();
var results = reader.ReadToEnd();
reader.Close();
dataStream.Close();
response.Close();
How do I get normal XML without having to perform various replacements on the characters received in the response.
At the moment I replace the characters with the code below. This is not ideal
results = results.Replace("</string>", String.Empty);
results = results.Replace("<", "<");
results = results.Replace(">
", ">");
results = results.Replace(">", ">");
results = Regex.Replace(results, "<string .*?\\>", String.Empty);
The service is doing exactly what it says it's doing - it's returning an XML-serialized string. I'm guessing the service code does some serialization of the Customer object into a string before returning that. If you want the return type to be the Customer, have the service method return a Customer object instead of a string, and you should be good. It will be smart enough to serialize your Customer into the appropriate XML string.
For testing your data out, you can use something like Fiddler to watch the raw HTTP request and response, so you can be sure exactly what's being requested and responded - but my guess is that it is coming back exactly as you're showing.
Definitely don't do that last thing with the string replaces. If you ever do need to do this, then look into XML decoding, possibly with one of the solutions found here.
I have a REST based WCF web-service;
The contract is:
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Xml)]
string EchoWithPost(string message);
The message is:
public string EchoWithPost(string s)
{
return "ECHO with POST : You said " + s;
}
I used the web channel factory to get a response via POST and it works. I used wireshark to tap the message and I can see some important things:
1) That xml is sent
2) The Content Type
From this I have constructed the following request logic:
//5) manually post to the REST service
//Create a request using a URL that can receive a post.
WebRequest request = WebRequest.Create(urlOfService + "/rest/EchoWithPOST");
// Set the Method property of the request to POST.
request.Method = "POST";
// Create POST data and convert it to a byte array.
string postData = "<EchoWithPost xmlns="http://tempuri.org"><message>Hello</message><EchoWithPost>";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Set the ContentType property of the WebRequest.
request.ContentType = "application/xml";
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
// Get the response.
WebResponse response = request.GetResponse();
// Display the status.
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
Console.WriteLine(responseFromServer);
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
However when I hit the line that says:
dataStream =
response.GetResponseStream();
I get the following error:
"The remote server returned an error : (400) Bad Request"
Could someone help me with what I need to do as I need to be able to tell people how to manually create a POST request to interact with this REST based service.
Any help much appreciated dont really see what else I can try.
I've made a few small changes, so I'll just post the entire thing. Hopefully it works for you. Also, I didn't add any deserializing, figuring you could tackle that as long as you make it past the HTTP 400 error.
A great tool to help you debug these situations is SoapUI. Just setup a "Web TestCase", and you can create your own POST requests and monitor the data that's going back and forth.
-Vito
Interface:
[OperationContract]
[WebInvoke(UriTemplate = "EchoWithPost", Method="POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
string EchoWithPost(string message);
Service:
public string EchoWithPost(string s)
{
return "ECHO with POST : You said " + s;
}
Client:
string urlOfService = "http://somewhere.com/RestService.svc/EchoWithPost";
string postData = "<EchoWithPost xmlns=\"http://tempuri.org/\"><message>Vito</message></EchoWithPost>";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
WebRequest request = WebRequest.Create(urlOfService);
request.Method = "POST";
request.ContentType = "application/xml;";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
WebResponse webResponse = request.GetResponse();
// Output raw string result
string rawStringResult = new StreamReader(webResponse.GetResponseStream()).ReadToEnd();
HttpContext.Current.Response.Write("\r\n" + rawStringResult);
web.config:
If the content type says that you're sending XML, then you shouldn't escape your XML to send it to the service - at least not the wrapping of the message; if you had some characters which needed escaping in the content (text), then you'd need to escape them. Change postData to the line below, and it should work.
string postData = "<EchoWithPost xmlns=\"http://tempuri.org\"><message>Hello & goodbye</message></EchoWithPost>";
Download this tool http://www.fiddler2.com/fiddler2/
try to call the rest method and see the raw data(request response) in fiddler, you will get the exact info about the error
Well Pete2k, I would say that without running your service it could take some time to reconstruct this. Are you using the WCF 4.0 REST Project? If so it has a help page that should show you what the request data looks like.
How do i get the data inside an HTTP POST request , that is received in my WCF Service?
i send the data from another service using HTTP POST:
string ReportText = "Hello world";
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] data = encoding.GetBytes(ReportText);
// Prepare web request...
String serverURL = ConfigurationManager.AppSettings["REPORT"];
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(serverURL);
myRequest.Method = "POST";
myRequest.ContentType = "application/x-www-form-urlencoded";
myRequest.ContentLength = data.Length;
Stream newStream = myRequest.GetRequestStream();
// Send the data.
newStream.Write(data, 0, data.Length);
newStream.Close();
but when i receive the POST request in the WCF i can't find a way to extract it using WebOperationContext.Current.IncomingRequest,
how do i extract the data from the HTTP POST request ?
My guess is that you are using a WCF Rest service and you can pull the GET parameters but you are unable to read RAW post data?
If this is the case then add a Stream parameter to the end of the parameter list in the Contract declaration. If there is a single stream at the end of the function, the framework treats it as a raw data stream.
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "DoSomething?siteId={siteId}&configTarget={configTarget}",
RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
bool DoSomething(string itemid, Stream body);
public bool DoSomething(int siteId, string configTarget, Stream postData)
{
string data = new StreamReader(postData).ReadToEnd();
return data.Length > 0;
}
See this link for more details:
http://blogs.msdn.com/b/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-receiving-arbitrary-data.aspx
Hello world isn't exactly application/x-www-form-urlencoded. You need to encode the post message body accordingly someproperty=Hello%20world as well as use WCF HTTP bindings.
This isn't a WCF question, as you're not using WCF. What you're really doing is submitting a form using HTTP Post, and you need to make a web page to receive and handle that. You can do that with the Request.Form collection.
Here's a simple example: http://bytes.com/topic/asp-net/answers/655226-how-use-request-form
I'm trying to send a POST request to a simple WCF service I wrote, but I keep getting a 400 Bad Request. I'm trying to send JSON data to the service. Can anyone spot what I'm doing wrong? :-)
This is my service interface:
public interface Itestservice
{
[OperationContract]
[WebInvoke(
Method = "POST",
UriTemplate = "/create",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
String Create(TestData testData);
}
The implementation:
public class testservice: Itestservice
{
public String Create(TestData testData)
{
return "Hello, your test data is " + testData.SomeData;
}
}
The DataContract:
[DataContract]
public class TestData
{
[DataMember]
public String SomeData { get; set; }
}
And finally my client code:
private static void TestCreatePost()
{
Console.WriteLine("testservice.svc/create POST:");
Console.WriteLine("-----------------------");
Uri address = new Uri("http://localhost:" + PORT + "/testweb/testservice.svc/create");
// Create the web request
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
// Set type to POST
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
//request.ContentType = "text/x-json";
// Create the data we want to send
string data = "{\"SomeData\":\"someTestData\"}";
// Create a byte array of the data we want to send
byte[] byteData = UTF8Encoding.UTF8.GetBytes(data);
// Set the content length in the request headers
request.ContentLength = byteData.Length;
// Write data
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
}
// Get response
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
// Console application output
Console.WriteLine(reader.ReadToEnd());
}
Console.WriteLine();
Console.WriteLine();
}
Can anyone think of what I might be doing wrong? As you can see in the C# client I've tried both application/x-www-form-urlencoded and text/x-json for ContentType, thinking that might have something to do with it, but it doesn't seem to. I've tried a GET version of this same service and it works fine, and returns a JSON version of TestData with no problem. But for POST, well, I'm pretty stuck at the moment on this :-(
Have you tried "application/json" instead of "text/x-json". According to this Stack Overflow question application/json is the only valid json media type.
The only problem here is the ContentType.
try ( recommended )
request.ContentType = "application/json; charset=utf-8";
or ( this will work too )
request.ContentType = "text/json; charset=utf-8";
Both of above solve the problem. However, the first one is recommended, for details of JSON-RPC 1.1 Specification check out http://json-rpc.org
Try:
[OperationContract]
[WebInvoke(
Method = "POST",
UriTemplate = "/create",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
/* non-wrapped */ BodyStyle = WebMessageBodyStyle.Bare )]
String Create(TestData testData);