Reputation: 145
I am working with REST web services on a third party open source server software, Bonitasoft's workflow engine. This is running on Apache. This software unfortunately only allows POST methods for any of the web service calls.
To test the basics of a call I have been able to use the Poster add-in for Firefox without issue. The following is the request information that is used in the utility:
After running the add-in with this information I get a response that has the information that I am looking for. There are no errors associated with the call, neither on the client nor the server. This is what is written to the server log when making this call through Poster:
10.0.5.1 - username [26/Apr/2012:16:06:24 -0600] "POST /bonita-server-rest/API/queryDefinitionAPI/getLightProcesses HTTP/1.1" 200 981091
All systems go!
Now, I am trying to make a C# console app that will do the same thing as this Poster utility. The following is the current test code that I am working with:
// Create the URI Address
var address = new Uri(url);
// Create the web request
var request = WebRequest.Create(address) as HttpWebRequest;
// Set type to POST
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.Credentials = new NetworkCredential("username", "password");
// Create the data we want to send
var data = HttpUtility.UrlEncode("options=user:100,password:100");
// Set the content length in the request headers
request.ContentLength = data;
// Write data
using (Stream postStream = request.GetRequestStream())
{
using (StreamWriter writeStream = new StreamWriter(postStream))
{
writeStream.Write(data);
}
}
// 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());
}
When I run the application it gets to the GetResponse() method without issue but once this method is invoked I get the following error (truncating the stacktrace):
System.Net.WebException: The remote server returned an error: (500) Internal Server Error.
The following is the log information that is written out by Apache:
10.0.5.1 - - [26/Apr/2012:16:21:08 -0600] "POST /bonita-server-rest/API/queryDefinitionAPI/getLightProcesses HTTP/1.1" 401 1331172
10.0.5.1 - username [26/Apr/2012:16:21:08 -0600] "options%3duser%3a100%2cpassword%3a100POST /bonita-server-rest/API/queryDefinitionAPI/getLightProcesses HTTP/1.1" 500 1150384
Of course the first thought is that the service is not functioning properly but that was determined to not be the case because a standalone client can invoke the service without errors. I have been running through a load of articles and questions but am unable to resolve this issue. Is there something that I am doing wrong in regard to receiving the response? Other ideas?
For reference, I have done this exact same service call with Grails (sigh) and have not received any errors.
** Update 1 ** I attempted to eliminate the 401 by adding the:
request.PreAuthenticate = true;
But this did not solve my issue.
** Update 2 ** I have been able to eliminate the 401 by setting the header manually using the following code:
byte[] authBytes = Encoding.UTF8.GetBytes("username:password".ToCharArray());
request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(authBytes);
To be sure I manually added the header to the Poster request and I do not receive a 500 error but the data that I am expecting. However I am still receiving the 500 error through the .NET implementation.
Upvotes: 2
Views: 5429
Reputation: 145
I have resolved my issue.
To fall in line with the majority of the documentation out there I moved back to a byte array for the body data that I needed to write out.
// Create the data we want to send
var data = HttpUtility.UrlEncode("options=user:100,password:100");
// 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(data);
}
This did not solve my problem but got me back on common ground. I then looked at the header and body that was being sent via the browser add-in and reversed any UTF8 encoding to find that the content was not URL encoded before the UTF8 encoding. I then changed my code to not perform the URL encoding and it worked without issue:
// Create the data we want to send
var data = "options=user:100,password:100";
// 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(data);
}
It seems so simple that I am not sure how I missed it. Thank you for your help on this. Hopefully this will help some people out there.
Upvotes: 2
Reputation: 6597
Assuming the request works properly in the web browser, the problem is likely the order in which the auth info is passed to the server.
Set request.PreAuthenticate
to true. That should fix the problem.
Upvotes: 0