Postby propagandhi » Wed Feb 04, 2009 12:44 am
I'm definitely at a point where I am kicking myself in the head for my stupidity, but I'm sure at least some of you know what it's like when you look at the most complex reason for why something isn't working, when the answer is perfectly simple.
I don't believe there should be any requirement to send a GET first or anything like that, there are no oddities other than a lack of understanding on my behalf....
When I was sending SOAP requests to http://scalix.ourdomain.com/caa with C# .NET's HttpWebRequest - I was getting the HTTP 1.1/302 Moved Temporarily message, after which I would try to fetch the response from the call, and I would have the text "Unknown Request".
Quite literally the solution was to add an extra / at the end of the url: http://scalix.ourdomain.com/caa/
I believe maybe in Barry's case, they ran the initial GET and retrieved the Location or redirect headers that gave them the correct url/syntax, but of course I cannot say that for sure.
Now for those interested in making some basic soap calls to and from scalix with C# or other languages also, here is a very basic example without error handling etc etc to show roughly how to do it.
using System;
using System.Xml;
using System.Net;
using System.IO;
using System.Text;
using System.Windows.Forms;
public class ScalixSoap
{
private String UbermanagerHostname;
private String UbermanagerAPIUrl;
private String UbermanagerUsername;
private String UbermanagerPassword;
private String UbermanagerUserID;
public ScalixSoap()
{
UbermanagerHostname = "scalix.domain.com.";
UbermanagerAPIUrl = "http://scalix.domain.com/caa/";
UbermanagerUsername = "scalixadmin";
UbermanagerPassword = "password";
UbermanagerUserID = "2565";
}
//Get a string of valid xml that builds the soap envelope header
public String GetSoapHeaderXml()
{
String XMLHeader = " "
+"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+ "<SOAP-ENV:Body>"
+ "<scalix-caa:CAARequestMessage xmlns:scalix-caa=\"http://www.scalix.com/caa\"> "
+ "<ServiceType>scalix.res</ServiceType>";
return XMLHeader;
}
//Returns the string of valid XML that makes up the soap envelope footer
public String GetSoapFooterXml()
{
String XMLFooter = "</scalix-caa:CAARequestMessage>"
+ "</SOAP-ENV:Body> "
+ "</SOAP-ENV:Envelope>";
return XMLFooter;
}
//Get the credentials to use when querying the API
public String GetSoapCredentialsXML()
{
String CredentialsXML = "<Credentials id=\""+this.UbermanagerUserID+"\">"
+ " <Identity name=\""+this.UbermanagerUsername+"\" passwd =\""+this.UbermanagerPassword+"\"/> "
+ "</Credentials>";
return CredentialsXML;
}
//Open a new connection to the API
public HttpWebRequest OpenSoapConnection(String Url)
{
//IMPORTANT: Turn of the Expect-100 Continue behaviour!!!
System.Net.ServicePointManager.Expect100Continue = false;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
request.AllowAutoRedirect = true; //Not strictly required - it should be default
request.ContentType = "text/xml;charset=utf-8";
//It's handy to be able to look in apache or caa logs etc and search for the unique user agent our code sends.
request.UserAgent = "CSHARP-TRACE-USERAGENT/1.0";
request.Headers.Add("SOAPAction: \"1\"");
request.Method = "POST";
return request;
}
//Making a valid XML document out of the request string isn't vital, but can make sure there's no garbage in the xml we send, as it does all sorts of XML Validation
//In my case, I make the request message only the body of the scalix request I want to make, that is all the credentials and the header and footer are loaded and the RequestMessage we pass here is just the function name and parameters.
public XmlDocument BuildRequestDocument(String RequestMessage)
{
String XMLText = this.GetSoapHeaderXml() + this.GetSoapCredentialsXML() + RequestMessage + this.GetSoapFooterXml();
XmlDocument RequestDoc = new XmlDocument();
RequestDoc.LoadXml(RequestMessage);
return RequestDoc;
}
public HttpWebResponse SendSoapRequest(XmlDocument requestDocument, HttpWebRequest RequestConnection)
{
//If you want to see what you are sending
// requestDocument.Save(@"C:\RequestDocument.xml");
RequestConnection.Method = "POST";
Stream RequestStream = RequestConnection.GetRequestStream();
requestDocument.Save(RequestStream); //send the document to the POST stream
RequestStream.Close();
RequestConnection.GetResponse();
HttpWebResponse ResponseMessage;
ResponseMessage = (HttpWebResponse)RequestConnection.GetResponse();
return ResponseMessage;
}
public XmlDocument GetResponseDocument(HttpWebResponse SoapResponse)
{
//Read the response from the request, and return it as a document.
Stream ResponseStream = SoapResponse.GetResponseStream();
//Let's inspect the result
StreamReader reader = new StreamReader(ResponseStream);
String ResponseText = "";
while (!reader.EndOfStream)
{
ResponseText = ResponseText + reader.ReadLine();
}
//convert the response to an xml document
//ResponseText=System.Text.Encoding.UTF8.GetString(buffer);
MessageBox.Show(ResponseText);
SoapResponse.Close();
XmlDocument ResponseDocument = new XmlDocument();
ResponseDocument.LoadXml(ResponseText);
return ResponseDocument;
}
}
You would call the above class in the following way:
ScalixSoap SoapClient = new ScalixSoap();
String UbermanagerQueryServer = "scalix.domain.com"; //or write a method to get the ubermanager API URL out of the class above etc etc
String ServerList = "<ScalixServers><Host>scalix.domain.com</Host></ScalixServers>";
String FunctionName = "<FunctionName>GetServersList</FunctionName>";
String FunctionOptions = ""; //eg maxrows="200"
String FunctionParameters = "<filters><typefilter value=\"normal\"/></filters>";
String SoapServerList = SoapClient.GetServerList("scalix.domain.com");
String RequestMessage = ServerList + FunctionName+ FunctionParameters; //That's the body of the request
XmlDocument RequestDoc = SoapClient.BuildRequestDocument(RequestMessage); //Gives us a validated Soap XML Doc
//open soap connection
HttpWebRequest SoapConnection = SoapClient.OpenSoapConnection(UbermanagerQueryServer);
//Send the request
HttpWebResponse Response = SoapClient.SendSoapRequest(RequestDoc,SoapConnection);
//Get the response
XmlDocument ResponseDoc = SoapClient.GetResponseDocument(Response);
//Now you would save or process the document however you like
XmlDocument.Save(@"C:\ResponseDocument");
I'd be more than happy to elaborate if anyone needs it, I've got a much bigger code base written now than that, but it just occurred to me how very infrequently people come back to forums with answers after they solve their problems.
I only had 5 spare minutes here to knock this up, and I'm not at my development machine and don't have visual studio with me so excuse any mistakes, I think the basic idea is shown here, but I haven't run this code or anything, so please point out any errors I made!
Cheers.
Last edited by
propagandhi on Sun Nov 22, 2009 7:47 pm, edited 1 time in total.